فهرست منبع

contracts: host enforcing update FuncId, as per task bVPVbQ

skoupidi 1 سال پیش
والد
کامیت
01cd3b15cb

+ 2 - 4
src/contract/dao/src/entrypoint/auth_xfer.rs

@@ -29,7 +29,7 @@ use darkfi_sdk::{
     pasta::pallas,
     ContractCall,
 };
-use darkfi_serial::{deserialize, Encodable, WriteExt};
+use darkfi_serial::{deserialize, Encodable};
 
 use crate::{
     error::DaoError,
@@ -222,7 +222,5 @@ pub(crate) fn dao_authxfer_process_instruction(
     // We do not need to check the amounts, since sum(input values) == sum(output values)
     // otherwise the money::transfer() call is invalid.
 
-    let mut update_data = vec![];
-    update_data.write_u8(DaoFunction::AuthMoneyTransfer as u8)?;
-    Ok(update_data)
+    Ok(vec![])
 }

+ 2 - 3
src/contract/dao/src/entrypoint/exec.rs

@@ -24,13 +24,13 @@ use darkfi_sdk::{
     pasta::pallas,
     wasm, ContractCall,
 };
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
+use darkfi_serial::{deserialize, serialize, Encodable};
 
 use crate::{
     blockwindow,
     error::DaoError,
     model::{DaoExecParams, DaoExecUpdate, DaoProposalMetadata, VecAuthCallCommit},
-    DaoFunction, DAO_CONTRACT_DB_PROPOSAL_BULLAS, DAO_CONTRACT_ZKAS_DAO_EARLY_EXEC_NS,
+    DAO_CONTRACT_DB_PROPOSAL_BULLAS, DAO_CONTRACT_ZKAS_DAO_EARLY_EXEC_NS,
     DAO_CONTRACT_ZKAS_DAO_EXEC_NS,
 };
 
@@ -143,7 +143,6 @@ pub(crate) fn dao_exec_process_instruction(
     // Create state update
     let update = DaoExecUpdate { proposal_bulla: params.proposal_bulla };
     let mut update_data = vec![];
-    update_data.write_u8(DaoFunction::Exec as u8)?;
     update.encode(&mut update_data)?;
     Ok(update_data)
 }

+ 3 - 4
src/contract/dao/src/entrypoint/mint.rs

@@ -24,13 +24,13 @@ use darkfi_sdk::{
     pasta::pallas,
     wasm, ContractCall,
 };
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
+use darkfi_serial::{deserialize, serialize, Encodable};
 
 use crate::{
     error::DaoError,
     model::{DaoMintParams, DaoMintUpdate},
-    DaoFunction, DAO_CONTRACT_DB_DAO_BULLAS, DAO_CONTRACT_DB_DAO_MERKLE_ROOTS,
-    DAO_CONTRACT_DB_INFO_TREE, DAO_CONTRACT_KEY_DAO_MERKLE_TREE, DAO_CONTRACT_KEY_LATEST_DAO_ROOT,
+    DAO_CONTRACT_DB_DAO_BULLAS, DAO_CONTRACT_DB_DAO_MERKLE_ROOTS, DAO_CONTRACT_DB_INFO_TREE,
+    DAO_CONTRACT_KEY_DAO_MERKLE_TREE, DAO_CONTRACT_KEY_LATEST_DAO_ROOT,
     DAO_CONTRACT_ZKAS_DAO_MINT_NS,
 };
 
@@ -83,7 +83,6 @@ pub(crate) fn dao_mint_process_instruction(
     // Create state update
     let update = DaoMintUpdate { dao_bulla: params.dao_bulla };
     let mut update_data = vec![];
-    update_data.write_u8(DaoFunction::Mint as u8)?;
     update.encode(&mut update_data)?;
 
     Ok(update_data)

+ 2 - 1
src/contract/dao/src/entrypoint/mod.rs

@@ -182,7 +182,8 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
 
 /// This function attempts to write a given state update provided the previous
 /// steps of the contract call execution were successful. The payload given to
-/// the function is the update data retrieved from `process_instruction()`.
+/// the function is the update data retrieved from `process_instruction()`,
+/// prefixed with the contract function.
 fn process_update(cid: ContractId, update_data: &[u8]) -> ContractResult {
     match DaoFunction::try_from(update_data[0])? {
         DaoFunction::Mint => {

+ 2 - 3
src/contract/dao/src/entrypoint/propose.rs

@@ -30,13 +30,13 @@ use darkfi_sdk::{
     tx::TransactionHash,
     wasm, ContractCall,
 };
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
+use darkfi_serial::{deserialize, serialize, Encodable};
 
 use crate::{
     blockwindow,
     error::DaoError,
     model::{DaoBlindAggregateVote, DaoProposalMetadata, DaoProposeParams, DaoProposeUpdate},
-    DaoFunction, DAO_CONTRACT_DB_DAO_MERKLE_ROOTS, DAO_CONTRACT_DB_PROPOSAL_BULLAS,
+    DAO_CONTRACT_DB_DAO_MERKLE_ROOTS, DAO_CONTRACT_DB_PROPOSAL_BULLAS,
     DAO_CONTRACT_ZKAS_DAO_PROPOSE_INPUT_NS, DAO_CONTRACT_ZKAS_DAO_PROPOSE_MAIN_NS,
     PROPOSAL_SNAPSHOT_CUTOFF_LIMIT,
 };
@@ -219,7 +219,6 @@ pub(crate) fn dao_propose_process_instruction(
     let update =
         DaoProposeUpdate { proposal_bulla: params.proposal_bulla, snapshot_coins, snapshot_nulls };
     let mut update_data = vec![];
-    update_data.write_u8(DaoFunction::Propose as u8)?;
     update.encode(&mut update_data)?;
     Ok(update_data)
 }

+ 2 - 3
src/contract/dao/src/entrypoint/vote.rs

@@ -24,13 +24,13 @@ use darkfi_sdk::{
     pasta::pallas,
     wasm, ContractCall,
 };
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
+use darkfi_serial::{deserialize, serialize, Encodable};
 
 use crate::{
     blockwindow,
     error::DaoError,
     model::{DaoProposalMetadata, DaoVoteParams, DaoVoteUpdate},
-    DaoFunction, DAO_CONTRACT_DB_PROPOSAL_BULLAS, DAO_CONTRACT_DB_VOTE_NULLIFIERS,
+    DAO_CONTRACT_DB_PROPOSAL_BULLAS, DAO_CONTRACT_DB_VOTE_NULLIFIERS,
     DAO_CONTRACT_ZKAS_DAO_VOTE_INPUT_NS, DAO_CONTRACT_ZKAS_DAO_VOTE_MAIN_NS,
 };
 
@@ -170,7 +170,6 @@ pub(crate) fn dao_vote_process_instruction(
         DaoVoteUpdate { proposal_bulla: params.proposal_bulla, proposal_metadata, vote_nullifiers };
 
     let mut update_data = vec![];
-    update_data.write_u8(DaoFunction::Vote as u8)?;
     update.encode(&mut update_data)?;
     Ok(update_data)
 }

+ 2 - 1
src/contract/deployooor/src/entrypoint.rs

@@ -100,7 +100,8 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
 /// This function attempts to write a given state update provided the previous
 /// steps of the contract call execution were all successful. It's the last in
 /// line, and assumes that the transaction/call was successful. The payload
-/// given to the function is the update data retrieved from `process_instruction()`.
+/// given to the function is the update data retrieved from `process_instruction()`,
+/// prefixed with the contract function.
 fn process_update(cid: ContractId, update_data: &[u8]) -> ContractResult {
     match DeployFunction::try_from(update_data[0])? {
         DeployFunction::DeployV1 => {

+ 2 - 3
src/contract/deployooor/src/entrypoint/deploy_v1.rs

@@ -25,13 +25,13 @@ use darkfi_sdk::{
     pasta::pallas,
     wasm, ContractCall,
 };
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
+use darkfi_serial::{deserialize, serialize, Encodable};
 use wasmparser::{
     ExternalKind::{Func, Memory},
     Payload::ExportSection,
 };
 
-use crate::{error::DeployError, model::DeployUpdateV1, DeployFunction, DEPLOY_CONTRACT_LOCK_TREE};
+use crate::{error::DeployError, model::DeployUpdateV1, DEPLOY_CONTRACT_LOCK_TREE};
 
 /// `get_metadata` function for `Deploy::DeployV1`
 pub(crate) fn deploy_get_metadata_v1(
@@ -143,7 +143,6 @@ pub(crate) fn deploy_process_instruction_v1(
 
     let update = DeployUpdateV1 { contract_id };
     let mut update_data = vec![];
-    update_data.write_u8(DeployFunction::DeployV1 as u8)?;
     update.encode(&mut update_data)?;
     Ok(update_data)
 }

+ 2 - 3
src/contract/deployooor/src/entrypoint/lock_v1.rs

@@ -24,12 +24,12 @@ use darkfi_sdk::{
     pasta::pallas,
     wasm, ContractCall,
 };
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
+use darkfi_serial::{deserialize, serialize, Encodable};
 
 use crate::{
     error::DeployError,
     model::{LockParamsV1, LockUpdateV1},
-    DeployFunction, DEPLOY_CONTRACT_LOCK_TREE,
+    DEPLOY_CONTRACT_LOCK_TREE,
 };
 
 /// `get_metadata` function for `Deploy::LockV1`
@@ -82,7 +82,6 @@ pub(crate) fn lock_process_instruction_v1(
 
     let update = LockUpdateV1 { contract_id };
     let mut update_data = vec![];
-    update_data.write_u8(DeployFunction::LockV1 as u8)?;
     update.encode(&mut update_data)?;
 
     Ok(update_data)

+ 2 - 1
src/contract/money/src/entrypoint.rs

@@ -298,7 +298,8 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
 /// This function attempts to write a given state update provided the previous steps
 /// of the contract call execution all were successful. It's the last in line, and
 /// assumes that the transaction/call was successful. The payload given to the function
-/// is the update data retrieved from `process_instruction()`.
+/// is the update data retrieved from `process_instruction()`, prefixed with the
+/// contract function.
 fn process_update(cid: ContractId, update_data: &[u8]) -> ContractResult {
     match MoneyFunction::try_from(update_data[0])? {
         MoneyFunction::FeeV1 => {

+ 2 - 3
src/contract/money/src/entrypoint/auth_token_freeze_v1.rs

@@ -24,12 +24,12 @@ use darkfi_sdk::{
     pasta::pallas,
     wasm, ContractCall,
 };
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
+use darkfi_serial::{deserialize, serialize, Encodable};
 
 use crate::{
     error::MoneyError,
     model::{MoneyAuthTokenFreezeParamsV1, MoneyAuthTokenFreezeUpdateV1},
-    MoneyFunction, MONEY_CONTRACT_TOKEN_FREEZE_TREE, MONEY_CONTRACT_ZKAS_AUTH_TOKEN_MINT_NS_V1,
+    MONEY_CONTRACT_TOKEN_FREEZE_TREE, MONEY_CONTRACT_ZKAS_AUTH_TOKEN_MINT_NS_V1,
 };
 
 /// `get_metadata` function for `Money::AuthTokenFreezeV1`
@@ -84,7 +84,6 @@ pub(crate) fn money_auth_token_freeze_process_instruction_v1(
     // Create a state update. We only need the new coin.
     let update = MoneyAuthTokenFreezeUpdateV1 { token_id: params.token_id };
     let mut update_data = vec![];
-    update_data.write_u8(MoneyFunction::AuthTokenFreezeV1 as u8)?;
     update.encode(&mut update_data)?;
 
     Ok(update_data)

+ 2 - 3
src/contract/money/src/entrypoint/auth_token_mint_v1.rs

@@ -24,12 +24,12 @@ use darkfi_sdk::{
     pasta::pallas,
     wasm, ContractCall,
 };
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
+use darkfi_serial::{deserialize, serialize, Encodable};
 
 use crate::{
     error::MoneyError,
     model::{MoneyAuthTokenMintParamsV1, MoneyAuthTokenMintUpdateV1},
-    MoneyFunction, MONEY_CONTRACT_TOKEN_FREEZE_TREE, MONEY_CONTRACT_ZKAS_AUTH_TOKEN_MINT_NS_V1,
+    MONEY_CONTRACT_TOKEN_FREEZE_TREE, MONEY_CONTRACT_ZKAS_AUTH_TOKEN_MINT_NS_V1,
 };
 
 /// `get_metadata` function for `Money::AuthTokenMintV1`
@@ -79,7 +79,6 @@ pub(crate) fn money_auth_token_mint_process_instruction_v1(
     // Create a state update.
     let update = MoneyAuthTokenMintUpdateV1 {};
     let mut update_data = vec![];
-    update_data.write_u8(MoneyFunction::AuthTokenMintV1 as u8)?;
     update.encode(&mut update_data)?;
 
     Ok(update_data)

+ 5 - 7
src/contract/money/src/entrypoint/fee_v1.rs

@@ -32,16 +32,15 @@ use darkfi_sdk::{
     pasta::pallas,
     wasm, ContractCall,
 };
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
+use darkfi_serial::{deserialize, serialize, Encodable};
 
 use crate::{
     error::MoneyError,
     model::{MoneyFeeParamsV1, MoneyFeeUpdateV1, DARK_TOKEN_ID},
-    MoneyFunction, MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE,
-    MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_FEES_TREE, MONEY_CONTRACT_INFO_TREE,
-    MONEY_CONTRACT_LATEST_COIN_ROOT, MONEY_CONTRACT_LATEST_NULLIFIER_ROOT,
-    MONEY_CONTRACT_NULLIFIERS_TREE, MONEY_CONTRACT_NULLIFIER_ROOTS_TREE,
-    MONEY_CONTRACT_ZKAS_FEE_NS_V1,
+    MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE, MONEY_CONTRACT_COIN_ROOTS_TREE,
+    MONEY_CONTRACT_FEES_TREE, MONEY_CONTRACT_INFO_TREE, MONEY_CONTRACT_LATEST_COIN_ROOT,
+    MONEY_CONTRACT_LATEST_NULLIFIER_ROOT, MONEY_CONTRACT_NULLIFIERS_TREE,
+    MONEY_CONTRACT_NULLIFIER_ROOTS_TREE, MONEY_CONTRACT_ZKAS_FEE_NS_V1,
 };
 
 /// `get_metadata` function for `Money::FeeV1`
@@ -191,7 +190,6 @@ pub(crate) fn money_fee_process_instruction_v1(
         fee: paid_fee,
     };
     let mut update_data = vec![];
-    update_data.write_u8(MoneyFunction::FeeV1 as u8)?;
     update.encode(&mut update_data)?;
     // and return it
     Ok(update_data)

+ 3 - 4
src/contract/money/src/entrypoint/genesis_mint_v1.rs

@@ -24,13 +24,13 @@ use darkfi_sdk::{
     pasta::pallas,
     wasm, ContractCall,
 };
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
+use darkfi_serial::{deserialize, serialize, Encodable};
 
 use crate::{
     error::MoneyError,
     model::{MoneyGenesisMintParamsV1, MoneyGenesisMintUpdateV1, DARK_TOKEN_ID},
-    MoneyFunction, MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE,
-    MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_INFO_TREE, MONEY_CONTRACT_LATEST_COIN_ROOT,
+    MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE, MONEY_CONTRACT_COIN_ROOTS_TREE,
+    MONEY_CONTRACT_INFO_TREE, MONEY_CONTRACT_LATEST_COIN_ROOT,
     MONEY_CONTRACT_LATEST_NULLIFIER_ROOT, MONEY_CONTRACT_NULLIFIERS_TREE,
     MONEY_CONTRACT_NULLIFIER_ROOTS_TREE, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
 };
@@ -143,7 +143,6 @@ pub(crate) fn money_genesis_mint_process_instruction_v1(
     // Create a state update. We only need the new coins.
     let update = MoneyGenesisMintUpdateV1 { coins: new_coins };
     let mut update_data = vec![];
-    update_data.write_u8(MoneyFunction::GenesisMintV1 as u8)?;
     update.encode(&mut update_data)?;
 
     Ok(update_data)

+ 5 - 7
src/contract/money/src/entrypoint/pow_reward_v1.rs

@@ -25,16 +25,15 @@ use darkfi_sdk::{
     pasta::pallas,
     wasm, ContractCall,
 };
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
+use darkfi_serial::{deserialize, serialize, Encodable};
 
 use crate::{
     error::MoneyError,
     model::{MoneyPoWRewardParamsV1, MoneyPoWRewardUpdateV1, DARK_TOKEN_ID},
-    MoneyFunction, MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE,
-    MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_FEES_TREE, MONEY_CONTRACT_INFO_TREE,
-    MONEY_CONTRACT_LATEST_COIN_ROOT, MONEY_CONTRACT_LATEST_NULLIFIER_ROOT,
-    MONEY_CONTRACT_NULLIFIERS_TREE, MONEY_CONTRACT_NULLIFIER_ROOTS_TREE,
-    MONEY_CONTRACT_ZKAS_MINT_NS_V1,
+    MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE, MONEY_CONTRACT_COIN_ROOTS_TREE,
+    MONEY_CONTRACT_FEES_TREE, MONEY_CONTRACT_INFO_TREE, MONEY_CONTRACT_LATEST_COIN_ROOT,
+    MONEY_CONTRACT_LATEST_NULLIFIER_ROOT, MONEY_CONTRACT_NULLIFIERS_TREE,
+    MONEY_CONTRACT_NULLIFIER_ROOTS_TREE, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
 };
 
 /// `get_metadata` function for `Money::PoWRewardV1`
@@ -157,7 +156,6 @@ pub(crate) fn money_pow_reward_process_instruction_v1(
     let update =
         MoneyPoWRewardUpdateV1 { coin: params.output.coin, height: verifying_block_height };
     let mut update_data = vec![];
-    update_data.write_u8(MoneyFunction::PoWRewardV1 as u8)?;
     update.encode(&mut update_data)?;
 
     Ok(update_data)

+ 2 - 7
src/contract/money/src/entrypoint/swap_v1.rs

@@ -31,14 +31,13 @@ use darkfi_sdk::{
     pasta::pallas,
     wasm, ContractCall,
 };
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
+use darkfi_serial::{deserialize, serialize, Encodable};
 
 use super::transfer_v1::{money_transfer_get_metadata_v1, money_transfer_process_update_v1};
 use crate::{
     error::MoneyError,
     model::{MoneyTransferParamsV1, MoneyTransferUpdateV1},
-    MoneyFunction, MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_ROOTS_TREE,
-    MONEY_CONTRACT_NULLIFIERS_TREE,
+    MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_NULLIFIERS_TREE,
 };
 
 /// `get_metadata` function for `Money::OtcSwapV1`
@@ -148,12 +147,8 @@ pub(crate) fn money_otcswap_process_instruction_v1(
     // Create a state update. We also use `MoneyTransferUpdateV1` because
     // they're essentially the same thing, just with a different transition
     // ruleset.
-    // FIXME: The function should not actually be written here. It should
-    //        be prepended by the host to enforce correctness. The host can
-    //        simply copy it from the payload.
     let update = MoneyTransferUpdateV1 { nullifiers: new_nullifiers, coins: new_coins };
     let mut update_data = vec![];
-    update_data.write_u8(MoneyFunction::OtcSwapV1 as u8)?;
     update.encode(&mut update_data)?;
 
     Ok(update_data)

+ 3 - 4
src/contract/money/src/entrypoint/token_mint_v1.rs

@@ -24,13 +24,13 @@ use darkfi_sdk::{
     pasta::pallas,
     wasm, ContractCall,
 };
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
+use darkfi_serial::{deserialize, serialize, Encodable};
 
 use crate::{
     error::MoneyError,
     model::{MoneyTokenMintParamsV1, MoneyTokenMintUpdateV1},
-    MoneyFunction, MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE,
-    MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_INFO_TREE, MONEY_CONTRACT_LATEST_COIN_ROOT,
+    MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE, MONEY_CONTRACT_COIN_ROOTS_TREE,
+    MONEY_CONTRACT_INFO_TREE, MONEY_CONTRACT_LATEST_COIN_ROOT,
     MONEY_CONTRACT_LATEST_NULLIFIER_ROOT, MONEY_CONTRACT_NULLIFIERS_TREE,
     MONEY_CONTRACT_NULLIFIER_ROOTS_TREE, MONEY_CONTRACT_ZKAS_TOKEN_MINT_NS_V1,
 };
@@ -101,7 +101,6 @@ pub(crate) fn money_token_mint_process_instruction_v1(
     // Create a state update. We only need the new coin.
     let update = MoneyTokenMintUpdateV1 { coin: params.coin };
     let mut update_data = vec![];
-    update_data.write_u8(MoneyFunction::TokenMintV1 as u8)?;
     update.encode(&mut update_data)?;
 
     Ok(update_data)

+ 3 - 4
src/contract/money/src/entrypoint/transfer_v1.rs

@@ -31,13 +31,13 @@ use darkfi_sdk::{
     pasta::pallas,
     wasm, ContractCall,
 };
-use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
+use darkfi_serial::{deserialize, serialize, Encodable};
 
 use crate::{
     error::MoneyError,
     model::{MoneyTransferParamsV1, MoneyTransferUpdateV1},
-    MoneyFunction, MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE,
-    MONEY_CONTRACT_COIN_ROOTS_TREE, MONEY_CONTRACT_INFO_TREE, MONEY_CONTRACT_LATEST_COIN_ROOT,
+    MONEY_CONTRACT_COINS_TREE, MONEY_CONTRACT_COIN_MERKLE_TREE, MONEY_CONTRACT_COIN_ROOTS_TREE,
+    MONEY_CONTRACT_INFO_TREE, MONEY_CONTRACT_LATEST_COIN_ROOT,
     MONEY_CONTRACT_LATEST_NULLIFIER_ROOT, MONEY_CONTRACT_NULLIFIERS_TREE,
     MONEY_CONTRACT_NULLIFIER_ROOTS_TREE, MONEY_CONTRACT_ZKAS_BURN_NS_V1,
     MONEY_CONTRACT_ZKAS_MINT_NS_V1,
@@ -223,7 +223,6 @@ pub(crate) fn money_transfer_process_instruction_v1(
     // At this point the state transition has passed, so we create a state update
     let update = MoneyTransferUpdateV1 { nullifiers: new_nullifiers, coins: new_coins };
     let mut update_data = vec![];
-    update_data.write_u8(MoneyFunction::TransferV1 as u8)?;
     update.encode(&mut update_data)?;
     // and return it
     Ok(update_data)

+ 26 - 19
src/validator/verification.rs

@@ -412,9 +412,11 @@ pub async fn verify_producer_transaction(
     sig_table.push(sig_pub);
 
     // After getting the metadata, we run the "exec" function with the same runtime
-    // and the same payload.
+    // and the same payload. We keep the returned state update in a buffer, prefixed
+    // by the call function ID, enforcing the state update function in the contract.
     debug!(target: "validator::verification::verify_producer_transaction", "Executing \"exec\" call");
-    let state_update = runtime.exec(&payload)?;
+    let mut state_update = vec![call.data.data[0]];
+    state_update.append(&mut runtime.exec(&payload)?);
     debug!(target: "validator::verification::verify_producer_transaction", "Successfully executed \"exec\" call");
 
     // If that was successful, we apply the state update in the ephemeral overlay.
@@ -511,9 +513,11 @@ async fn apply_producer_transaction(
     let signature_public_key = *sig_pub.last().unwrap();
 
     // After getting the metadata, we run the "exec" function with the same runtime
-    // and the same payload.
+    // and the same payload. We keep the returned state update in a buffer, prefixed
+    // by the call function ID, enforcing the state update function in the contract.
     debug!(target: "validator::verification::apply_producer_transaction", "Executing \"exec\" call");
-    let state_update = runtime.exec(&payload)?;
+    let mut state_update = vec![call.data.data[0]];
+    state_update.append(&mut runtime.exec(&payload)?);
     debug!(target: "validator::verification::apply_producer_transaction", "Successfully executed \"exec\" call");
 
     // If that was successful, we apply the state update in the ephemeral overlay.
@@ -586,26 +590,25 @@ pub async fn verify_transaction(
         }
     }
 
+    // Write the transaction calls payload data
+    let mut payload = vec![];
+    tx.calls.encode_async(&mut payload).await?;
+
     // We'll also take note of all the circuits in a Vec so we can calculate their verification cost.
     let mut circuits_to_verify = vec![];
 
     // Iterate over all calls to get the metadata
     for (idx, call) in tx.calls.iter().enumerate() {
+        debug!(target: "validator::verification::verify_transaction", "Executing contract call {}", idx);
+
         // Transaction must not contain a Pow reward call
         if call.data.is_money_pow_reward() {
             error!(target: "validator::verification::verify_transaction", "Reward transaction detected");
             return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
         }
 
-        debug!(target: "validator::verification::verify_transaction", "Executing contract call {}", idx);
-
-        // Write the actual payload data
-        let mut payload = vec![];
-        tx.calls.encode_async(&mut payload).await?;
-
         debug!(target: "validator::verification::verify_transaction", "Instantiating WASM runtime");
         let wasm = overlay.lock().unwrap().contracts.get(call.data.contract_id)?;
-
         let mut runtime = Runtime::new(
             &wasm,
             overlay.clone(),
@@ -661,9 +664,11 @@ pub async fn verify_transaction(
         sig_table.push(sig_pub);
 
         // After getting the metadata, we run the "exec" function with the same runtime
-        // and the same payload.
+        // and the same payload. We keep the returned state update in a buffer, prefixed
+        // by the call function ID, enforcing the state update function in the contract.
         debug!(target: "validator::verification::verify_transaction", "Executing \"exec\" call");
-        let state_update = runtime.exec(&payload)?;
+        let mut state_update = vec![call.data.data[0]];
+        state_update.append(&mut runtime.exec(&payload)?);
         debug!(target: "validator::verification::verify_transaction", "Successfully executed \"exec\" call");
 
         // If that was successful, we apply the state update in the ephemeral overlay.
@@ -808,14 +813,14 @@ async fn apply_transaction(
     let tx_hash = tx.hash();
     debug!(target: "validator::verification::apply_transaction", "Applying transaction {}", tx_hash);
 
+    // Write the transaction calls payload data
+    let mut payload = vec![];
+    tx.calls.encode_async(&mut payload).await?;
+
     // Iterate over all calls to get the metadata
     for (idx, call) in tx.calls.iter().enumerate() {
         debug!(target: "validator::verification::apply_transaction", "Executing contract call {}", idx);
 
-        // Write the actual payload data
-        let mut payload = vec![];
-        tx.calls.encode_async(&mut payload).await?;
-
         debug!(target: "validator::verification::apply_transaction", "Instantiating WASM runtime");
         let wasm = overlay.lock().unwrap().contracts.get(call.data.contract_id)?;
         let mut runtime = Runtime::new(
@@ -828,9 +833,11 @@ async fn apply_transaction(
             idx as u8,
         )?;
 
-        // Run the "exec" function
+        // Run the "exec" function. We keep the returned state update in a buffer, prefixed
+        // by the call function ID, enforcing the state update function in the contract.
         debug!(target: "validator::verification::apply_transaction", "Executing \"exec\" call");
-        let state_update = runtime.exec(&payload)?;
+        let mut state_update = vec![call.data.data[0]];
+        state_update.append(&mut runtime.exec(&payload)?);
         debug!(target: "validator::verification::apply_transaction", "Successfully executed \"exec\" call");
 
         // If that was successful, we apply the state update in the ephemeral overlay