From 9074440105959367e8b08a7e2f84343b9f7a2e09 Mon Sep 17 00:00:00 2001 From: zero Date: Mon, 1 Apr 2024 17:46:27 +0200 Subject: [PATCH] runtime: remove call_idx from the payload, and add it as a Runtime param --- src/contract/dao/src/entrypoint/mod.rs | 8 +++++--- src/contract/money/src/entrypoint.rs | 9 ++++++--- src/contract/test-harness/src/lib.rs | 8 +++++--- src/runtime/import/util.rs | 11 +++++++++++ src/runtime/vm_runtime.rs | 10 ++++++++++ src/sdk/src/util.rs | 11 +++++++++++ src/validator/utils.rs | 3 ++- src/validator/verification.rs | 12 ++++++------ 8 files changed, 56 insertions(+), 16 deletions(-) diff --git a/src/contract/dao/src/entrypoint/mod.rs b/src/contract/dao/src/entrypoint/mod.rs index 1ea22d4db..cfc176ac4 100644 --- a/src/contract/dao/src/entrypoint/mod.rs +++ b/src/contract/dao/src/entrypoint/mod.rs @@ -23,7 +23,7 @@ use darkfi_sdk::{ dark_tree::DarkLeaf, db::{db_get, db_init, db_lookup, db_set, zkas_db_set}, error::ContractResult, - util::set_return_data, + util::{get_call_index, set_return_data}, ContractCall, }; use darkfi_serial::{deserialize, serialize, Decodable, Encodable, WriteExt}; @@ -141,7 +141,8 @@ fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult { /// for verifying signatures and ZK proofs. The payload given here are all the /// contract calls in the transaction. fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult { - let (call_idx, calls): (u32, Vec>) = deserialize(ix)?; + let call_idx = get_call_index(); + let calls: Vec> = deserialize(ix)?; let self_ = &calls[call_idx as usize].data; let func = DaoFunction::try_from(self_.data[0])?; @@ -159,7 +160,8 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult { /// This function verifies a state transition and produces a state update /// if everything is successful. fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult { - let (call_idx, calls): (u32, Vec>) = deserialize(ix)?; + let call_idx = get_call_index(); + let calls: Vec> = deserialize(ix)?; let self_ = &calls[call_idx as usize].data; let func = DaoFunction::try_from(self_.data[0])?; diff --git a/src/contract/money/src/entrypoint.rs b/src/contract/money/src/entrypoint.rs index 8d88bf850..f08ad1d28 100644 --- a/src/contract/money/src/entrypoint.rs +++ b/src/contract/money/src/entrypoint.rs @@ -21,8 +21,9 @@ use darkfi_sdk::{ dark_tree::DarkLeaf, db::{db_init, db_lookup, db_set, zkas_db_set}, error::ContractResult, + msg, pasta::pallas, - util::set_return_data, + util::{get_call_index, set_return_data}, ContractCall, }; use darkfi_serial::{deserialize, serialize, Encodable, WriteExt}; @@ -206,7 +207,8 @@ fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult { /// for verifying signatures and zk proofs. The payload given here are all the /// contract calls in the transaction. fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult { - let (call_idx, calls): (u32, Vec>) = deserialize(ix)?; + let call_idx = get_call_index(); + let calls: Vec> = deserialize(ix)?; let self_ = &calls[call_idx as usize].data; let func = MoneyFunction::try_from(self_.data[0])?; @@ -236,7 +238,8 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult { /// if everything is successful. This step should happen **after** the host /// has successfully verified the metadata from `get_metadata()`. fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult { - let (call_idx, calls): (u32, Vec>) = deserialize(ix)?; + let call_idx = get_call_index(); + let calls: Vec> = deserialize(ix)?; let self_ = &calls[call_idx as usize].data; let func = MoneyFunction::try_from(self_.data[0])?; diff --git a/src/contract/test-harness/src/lib.rs b/src/contract/test-harness/src/lib.rs index 6a2394dfa..80e5085fb 100644 --- a/src/contract/test-harness/src/lib.rs +++ b/src/contract/test-harness/src/lib.rs @@ -41,7 +41,7 @@ use darkfi_sdk::{ }, pasta::pallas, }; -use darkfi_serial::{Encodable, WriteExt}; +use darkfi_serial::Encodable; use log::debug; use num_bigint::BigUint; @@ -305,11 +305,13 @@ fn benchmark_wasm_calls( call.data.contract_id, block_height, tx.hash().clone(), + idx as u32, ) .expect("runtime"); + + // Write call data let mut payload = vec![]; - payload.write_u32(idx as u32).unwrap(); // Call index - tx.calls.encode(&mut payload).unwrap(); // Actual call data + tx.calls.encode(&mut payload).unwrap(); let mut times = [0; 3]; let now = std::time::Instant::now(); diff --git a/src/runtime/import/util.rs b/src/runtime/import/util.rs index a027bf8eb..4fa71a7f3 100644 --- a/src/runtime/import/util.rs +++ b/src/runtime/import/util.rs @@ -254,6 +254,17 @@ pub(crate) fn get_tx_hash(mut ctx: FunctionEnvMut) -> i64 { (objects.len() - 1) as i64 } +/// Will return current runtime configured verifying block height number +pub(crate) fn get_call_index(mut ctx: FunctionEnvMut) -> u32 { + let (env, mut store) = ctx.data_and_store_mut(); + + // Subtract used gas. Here we count the size of the object. + // u32 is 4 bytes. + env.subtract_gas(&mut store, 4); + + env.call_idx +} + /// Will return current blockchain timestamp, /// defined as the last block's timestamp. pub(crate) fn get_blockchain_time(mut ctx: FunctionEnvMut) -> i64 { diff --git a/src/runtime/vm_runtime.rs b/src/runtime/vm_runtime.rs index 52f53c466..4ded1a9b7 100644 --- a/src/runtime/vm_runtime.rs +++ b/src/runtime/vm_runtime.rs @@ -99,6 +99,8 @@ pub struct Env { pub verifying_block_height: u64, /// The hash for this transaction the runtime is being run against. pub tx_hash: TransactionHash, + /// The index for this call in the transaction + pub call_idx: u32, /// Parent `Instance` pub instance: Option>, } @@ -155,6 +157,7 @@ impl Runtime { contract_id: ContractId, verifying_block_height: u64, tx_hash: TransactionHash, + call_idx: u32, ) -> Result { info!(target: "runtime::vm_runtime", "[WASM] Instantiating a new runtime"); // This function will be called for each `Operator` encountered during @@ -197,6 +200,7 @@ impl Runtime { objects: RefCell::new(vec![]), verifying_block_height, tx_hash, + call_idx, instance: None, }, ); @@ -299,6 +303,12 @@ impl Runtime { import::util::get_tx_hash, ), + "get_call_index_" => Function::new_typed_with_env( + &mut store, + &ctx, + import::util::get_call_index, + ), + "get_blockchain_time_" => Function::new_typed_with_env( &mut store, &ctx, diff --git a/src/sdk/src/util.rs b/src/sdk/src/util.rs index 3614ac860..4d4a0baa9 100644 --- a/src/sdk/src/util.rs +++ b/src/sdk/src/util.rs @@ -113,6 +113,16 @@ pub fn get_tx_hash() -> GenericResult { Ok(TransactionHash(tx_hash_data)) } +/// Only deploy(), metadata() and exec() can call this. Will return runtime configured +/// verifying block height. +/// +/// ``` +/// call_idx = get_call_index(); +/// ``` +pub fn get_call_index() -> u32 { + unsafe { get_call_index_() } +} + /// Everyone can call this. Will return current blockchain timestamp. /// /// ``` @@ -156,6 +166,7 @@ extern "C" { fn get_verifying_block_height_() -> u64; fn get_tx_hash_() -> i64; + fn get_call_index_() -> u32; fn get_blockchain_time_() -> i64; fn get_last_block_height_() -> i64; fn get_tx_(ptr: *const u8) -> i64; diff --git a/src/validator/utils.rs b/src/validator/utils.rs index 7d9542ff8..d56dfdfe8 100644 --- a/src/validator/utils.rs +++ b/src/validator/utils.rs @@ -81,7 +81,7 @@ pub async fn deploy_native_contracts(overlay: &BlockchainOverlayPtr) -> Result<( Err(_) => 0, }; - for nc in native_contracts { + for (call_idx, nc) in native_contracts.into_iter().enumerate() { info!(target: "validator::utils::deploy_native_contracts", "Deploying {} with ContractID {}", nc.0, nc.1); let mut runtime = Runtime::new( @@ -90,6 +90,7 @@ pub async fn deploy_native_contracts(overlay: &BlockchainOverlayPtr) -> Result<( nc.1, verifying_block_height, TransactionHash::none(), + call_idx as u32, )?; runtime.deploy(&nc.3)?; diff --git a/src/validator/verification.rs b/src/validator/verification.rs index 40b548bec..ae9a36899 100644 --- a/src/validator/verification.rs +++ b/src/validator/verification.rs @@ -28,9 +28,7 @@ use darkfi_sdk::{ deploy::DeployParamsV1, pasta::pallas, }; -use darkfi_serial::{ - deserialize_async, serialize_async, AsyncDecodable, AsyncEncodable, AsyncWriteExt, WriteExt, -}; +use darkfi_serial::{deserialize_async, serialize_async, AsyncDecodable, AsyncEncodable}; use log::{debug, error, warn}; use num_bigint::BigUint; use smol::io::Cursor; @@ -276,7 +274,6 @@ pub async fn verify_producer_transaction( // Write the actual payload data let mut payload = vec![]; - payload.write_u32_async(0).await?; // Call index tx.calls.encode_async(&mut payload).await?; // Actual call data debug!(target: "validator::verification::verify_producer_transaction", "Instantiating WASM runtime"); @@ -288,6 +285,8 @@ pub async fn verify_producer_transaction( call.data.contract_id, verifying_block_height, tx_hash.clone(), + // Call index in producer tx is 0 + 0, )?; debug!(target: "validator::verification::verify_producer_transaction", "Executing \"metadata\" call"); @@ -443,8 +442,7 @@ pub async fn verify_transaction( // Write the actual payload data let mut payload = vec![]; - payload.write_u32(idx as u32)?; // Call index - tx.calls.encode_async(&mut payload).await?; // Actual call data + 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)?; @@ -455,6 +453,7 @@ pub async fn verify_transaction( call.data.contract_id, verifying_block_height, tx_hash.clone(), + idx as u32, )?; debug!(target: "validator::verification::verify_transaction", "Executing \"metadata\" call"); @@ -529,6 +528,7 @@ pub async fn verify_transaction( deploy_cid, verifying_block_height, tx_hash.clone(), + idx as u32, )?; deploy_runtime.deploy(&deploy_params.ix)?;