mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
add spend_hook to money contracts, and checks for DAO::exec()
This commit is contained in:
@@ -148,8 +148,23 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
|
||||
assert!(call_idx < call.len() as u32);
|
||||
|
||||
let self_ = &call[call_idx as usize];
|
||||
let func = DaoFunction::try_from(self_.data[0])?;
|
||||
|
||||
match DaoFunction::try_from(self_.data[0])? {
|
||||
if call.len() != 1 {
|
||||
// Enforce a strict structure for our tx
|
||||
assert_eq!(call.len(), 2);
|
||||
assert_eq!(call_idx, 1);
|
||||
|
||||
// We can unpack user_data and check the function call is correct.
|
||||
// But in this contract, only DAO::exec() can be invoked by other ones.
|
||||
// So just check the function call is correct.
|
||||
|
||||
// NOTE: we may wish to improve this since it cripples user composability.
|
||||
|
||||
assert_eq!(func, DaoFunction::Exec);
|
||||
}
|
||||
|
||||
match func {
|
||||
DaoFunction::Mint => {
|
||||
let params: MintCallParams = deserialize(&self_.data[1..])?;
|
||||
let dao_bulla = params.dao_bulla.inner();
|
||||
|
||||
@@ -47,6 +47,7 @@ pub const DAO_CONTRACT_ZKAS_DAO_PROPOSE_BURN_NS: &str = "DaoProposeInput";
|
||||
pub const DAO_CONTRACT_ZKAS_DAO_PROPOSE_MAIN_NS: &str = "DaoProposeMain";
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum DaoFunction {
|
||||
Mint = 0x00,
|
||||
Propose = 0x01,
|
||||
|
||||
@@ -755,7 +755,7 @@ async fn integration_test() -> Result<()> {
|
||||
let dao_coin_blind = pallas::Base::random(&mut OsRng);
|
||||
let input_value = treasury_note.value;
|
||||
let input_value_blind = pallas::Scalar::random(&mut OsRng);
|
||||
let tx_signature_secret = SecretKey::random(&mut OsRng);
|
||||
let xfer_signature_secret = SecretKey::random(&mut OsRng);
|
||||
let exec_signature_secret = SecretKey::random(&mut OsRng);
|
||||
|
||||
let (treasury_leaf_position, treasury_merkle_path) = {
|
||||
@@ -783,7 +783,7 @@ async fn integration_test() -> Result<()> {
|
||||
note: treasury_note,
|
||||
user_data_blind,
|
||||
value_blind: input_value_blind,
|
||||
signature_secret: tx_signature_secret,
|
||||
signature_secret: xfer_signature_secret,
|
||||
}],
|
||||
outputs: vec![
|
||||
// Sending money
|
||||
@@ -847,7 +847,7 @@ async fn integration_test() -> Result<()> {
|
||||
proofs: vec![xfer_proofs, exec_proofs],
|
||||
signatures: vec![],
|
||||
};
|
||||
let xfer_sigs = tx.create_sigs(&mut OsRng, &vec![tx_signature_secret])?;
|
||||
let xfer_sigs = tx.create_sigs(&mut OsRng, &vec![xfer_signature_secret])?;
|
||||
let exec_sigs = tx.create_sigs(&mut OsRng, &vec![exec_signature_secret])?;
|
||||
tx.signatures = vec![xfer_sigs, exec_sigs];
|
||||
|
||||
|
||||
@@ -426,6 +426,32 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
|
||||
return Err(ContractError::Custom(22))
|
||||
}
|
||||
|
||||
msg!("XXXX: spend_hook = {:?}", input.spend_hook);
|
||||
|
||||
// Check the invoked contract if spend hook is set
|
||||
if !bool::from(input.spend_hook.is_zero()) {
|
||||
let next_call_idx = call_idx + 1;
|
||||
if next_call_idx >= call.len() as u32 {
|
||||
msg!(
|
||||
"[Transfer] Error: next_call_idx = {} but len(calls) = {} in input {}",
|
||||
next_call_idx,
|
||||
call.len(),
|
||||
i
|
||||
);
|
||||
return Err(ContractError::Custom(23))
|
||||
}
|
||||
|
||||
let next = &call[next_call_idx as usize];
|
||||
if next.contract_id.inner() != input.spend_hook {
|
||||
msg!(
|
||||
"[Transfer] Error: invoking contract call does not match spend hook\
|
||||
in input {}",
|
||||
i
|
||||
);
|
||||
return Err(ContractError::Custom(24))
|
||||
}
|
||||
}
|
||||
|
||||
new_nullifiers.push(input.nullifier);
|
||||
valcom_total += input.value_commit;
|
||||
}
|
||||
@@ -436,7 +462,7 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
|
||||
// TODO: Should we have coins in a sled tree too to check dupes?
|
||||
if new_coins.contains(&Coin::from(output.coin)) {
|
||||
msg!("[Transfer] Error: Duplicate coin found in output {}", i);
|
||||
return Err(ContractError::Custom(23))
|
||||
return Err(ContractError::Custom(25))
|
||||
}
|
||||
|
||||
// FIXME: Needs some work on types and their place within all these libraries
|
||||
@@ -447,7 +473,7 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
|
||||
// If the accumulator is not back in its initial state, there's a value mismatch.
|
||||
if valcom_total != pallas::Point::identity() {
|
||||
msg!("[Transfer] Error: Value commitments do not result in identity");
|
||||
return Err(ContractError::Custom(24))
|
||||
return Err(ContractError::Custom(26))
|
||||
}
|
||||
|
||||
// Verify that the token commitments are all for the same token
|
||||
|
||||
@@ -126,9 +126,13 @@ pub struct Input {
|
||||
pub nullifier: Nullifier,
|
||||
/// Revealed Merkle root
|
||||
pub merkle_root: MerkleNode,
|
||||
/// spend hook (TODO: document)
|
||||
/// Spend hook used to invoke other contracts.
|
||||
/// If this value is nonzero then the subsequent contract call in the tx
|
||||
/// must have this value as its ID.
|
||||
pub spend_hook: pallas::Base,
|
||||
/// user data enc (TODO: document)
|
||||
/// Encrypted user data field. An encrypted commitment to arbitrary data.
|
||||
/// When spend hook is set (it is nonzero), then this field may be used
|
||||
/// to pass data to the invoked contract.
|
||||
pub user_data_enc: pallas::Base,
|
||||
/// Public key for the signature
|
||||
pub signature_public: PublicKey,
|
||||
|
||||
Reference in New Issue
Block a user