From af16a80c6f5d09659024f6e246f1b3c3e253b5ea Mon Sep 17 00:00:00 2001 From: Sergei Blinov Date: Thu, 14 May 2026 13:16:59 +0200 Subject: [PATCH 1/5] Add build-actions ExecuteParams fixture --- tvm_executor/src/lib.rs | 3 + tvm_executor/src/ordinary_transaction.rs | 10 +- tvm_executor/src/test_utils.rs | 231 +++++++++++++++++++++++ tvm_executor/src/transaction_executor.rs | 49 ++--- 4 files changed, 265 insertions(+), 28 deletions(-) create mode 100644 tvm_executor/src/test_utils.rs diff --git a/tvm_executor/src/lib.rs b/tvm_executor/src/lib.rs index 7e96d3143..44a6edaf2 100644 --- a/tvm_executor/src/lib.rs +++ b/tvm_executor/src/lib.rs @@ -27,6 +27,9 @@ pub use vmsetup::*; pub mod blockchain_config; pub use blockchain_config::*; +#[cfg(test)] +pub(crate) mod test_utils; + pub fn build_commit() -> Option<&'static str> { std::option_env!("BUILD_GIT_COMMIT") } diff --git a/tvm_executor/src/ordinary_transaction.rs b/tvm_executor/src/ordinary_transaction.rs index 2b7075d70..ab7574151 100644 --- a/tvm_executor/src/ordinary_transaction.rs +++ b/tvm_executor/src/ordinary_transaction.rs @@ -625,9 +625,9 @@ mod tests { use tvm_vm::stack::integer::IntegerData; use super::OrdinaryTransactionExecutor; - use crate::ExecuteParams; use crate::TransactionExecutor; use crate::error::ExecutorError as LocalExecutorError; + use crate::test_utils::build_actions_execute_params; fn address(byte: u8) -> MsgAddressInt { MsgAddressInt::with_standart(None, 0, UInt256::with_array([byte; 32]).into()).unwrap() @@ -690,7 +690,7 @@ mod tests { let executor = OrdinaryTransactionExecutor::new(Default::default()); let mut account = Account::with_address(address(1)); let err = executor - .execute_with_params(None, &mut account, ExecuteParams::default(), &mut 0) + .execute_with_params(None, &mut account, build_actions_execute_params(), &mut 0) .unwrap_err(); assert!(err.to_string().contains("Ordinary transaction must have input message")); @@ -702,7 +702,7 @@ mod tests { let mut account = Account::with_address(address(1)); let msg = Message::with_ext_out_header(ExtOutMessageHeader::default()); let err = executor - .execute_with_params(Some(&msg), &mut account, ExecuteParams::default(), &mut 0) + .execute_with_params(Some(&msg), &mut account, build_actions_execute_params(), &mut 0) .unwrap_err(); assert_eq!( @@ -724,7 +724,7 @@ mod tests { )); let tx = executor - .execute_with_params(Some(&msg), &mut account, ExecuteParams::default(), &mut 0) + .execute_with_params(Some(&msg), &mut account, build_actions_execute_params(), &mut 0) .unwrap(); assert_eq!(tx.account_id(), &dst.address()); @@ -745,7 +745,7 @@ mod tests { )); let tx = executor - .execute_with_params(Some(&msg), &mut account, ExecuteParams::default(), &mut 0) + .execute_with_params(Some(&msg), &mut account, build_actions_execute_params(), &mut 0) .unwrap(); assert_eq!(tx.account_id(), &dst.address()); diff --git a/tvm_executor/src/test_utils.rs b/tvm_executor/src/test_utils.rs new file mode 100644 index 000000000..46f457ac0 --- /dev/null +++ b/tvm_executor/src/test_utils.rs @@ -0,0 +1,231 @@ +#[cfg(feature = "wasmtime")] +use std::collections::HashMap; +#[cfg(feature = "wasmtime")] +use std::collections::HashSet; +use std::sync::Arc; +use std::sync::Mutex; +use std::sync::atomic::AtomicU64; +use std::time::Duration; +use std::time::Instant; + +use tvm_types::HashmapE; +use tvm_types::UInt256; +use tvm_vm::executor::MVConfig; + +use crate::ExecuteParams; + +// Mirrors ExecuteParams construction in acki-nacki/node's block builder +// `build_actions.rs`. +pub(crate) enum BuildActionsTraceMode { + Regular, + TvmTracing { trace_callback: Arc }, +} + +#[cfg(feature = "wasmtime")] +pub(crate) struct BuildActionsWasmCache { + pub wasm_binary_root_path: String, + pub wasm_hash_whitelist: HashSet<[u8; 32]>, + pub wasm_engine: wasmtime::Engine, + pub wasm_component_cache: HashMap<[u8; 32], wasmtime::component::Component>, +} + +#[cfg(feature = "wasmtime")] +impl Default for BuildActionsWasmCache { + fn default() -> Self { + Self { + wasm_binary_root_path: "./config/wasm".to_owned(), + wasm_hash_whitelist: HashSet::new(), + wasm_engine: wasmtime::Engine::default(), + wasm_component_cache: HashMap::new(), + } + } +} + +pub(crate) struct BuildActionsExecuteParamsFixture { + pub block_unixtime: u32, + pub block_lt: u64, + pub seq_no: u32, + pub last_tr_lt: Arc, + pub seed_block: UInt256, + pub trace_mode: BuildActionsTraceMode, + #[cfg(feature = "signature_with_id")] + pub signature_id: i32, + pub vm_execution_is_block_related: Arc>, + pub block_collation_was_finished: Arc>, + pub dapp_id: Option, + pub available_credit: i128, + pub termination_deadline: Option, + pub execution_timeout: Option, + #[cfg(feature = "wasmtime")] + pub wasm_cache: BuildActionsWasmCache, + pub mvconfig: MVConfig, + pub engine_version: semver::Version, +} + +impl Default for BuildActionsExecuteParamsFixture { + fn default() -> Self { + Self { + block_unixtime: 0, + block_lt: 0, + seq_no: 0, + last_tr_lt: Arc::new(AtomicU64::new(0)), + seed_block: UInt256::default(), + trace_mode: BuildActionsTraceMode::Regular, + #[cfg(feature = "signature_with_id")] + signature_id: 0, + vm_execution_is_block_related: Arc::new(Mutex::new(false)), + block_collation_was_finished: Arc::new(Mutex::new(false)), + dapp_id: None, + available_credit: 0, + termination_deadline: None, + execution_timeout: None, + #[cfg(feature = "wasmtime")] + wasm_cache: BuildActionsWasmCache::default(), + mvconfig: MVConfig::default(), + engine_version: semver::Version::new(1, 0, 3), + } + } +} + +impl BuildActionsExecuteParamsFixture { + pub(crate) fn regular() -> Self { + Self::default() + } + + pub(crate) fn tvm_tracing(trace_callback: Arc) -> Self { + let mut fixture = Self::default(); + fixture.trace_mode = BuildActionsTraceMode::TvmTracing { trace_callback }; + fixture + } + + pub(crate) fn build(self) -> ExecuteParams { + let (debug, trace_callback) = match self.trace_mode { + BuildActionsTraceMode::Regular => (false, None), + BuildActionsTraceMode::TvmTracing { trace_callback } => (true, Some(trace_callback)), + }; + + ExecuteParams { + // Intentionally default: acki-nacki build_actions.rs leaves state libs to + // ExecuteParams::default(). + state_libs: HashmapE::with_bit_len(32), + block_unixtime: self.block_unixtime, + block_lt: self.block_lt, + seq_no: self.seq_no, + last_tr_lt: self.last_tr_lt, + seed_block: self.seed_block, + debug, + trace_callback, + // Intentionally default: acki-nacki build_actions.rs does not pass behavior modifiers. + behavior_modifiers: None, + // Intentionally default: acki-nacki build_actions.rs does not pass block version here. + block_version: 0, + #[cfg(feature = "signature_with_id")] + signature_id: self.signature_id, + vm_execution_is_block_related: self.vm_execution_is_block_related, + block_collation_was_finished: self.block_collation_was_finished, + dapp_id: self.dapp_id, + available_credit: self.available_credit, + termination_deadline: self.termination_deadline, + execution_timeout: self.execution_timeout, + #[cfg(feature = "wasmtime")] + wasm_binary_root_path: self.wasm_cache.wasm_binary_root_path, + #[cfg(feature = "wasmtime")] + wasm_hash_whitelist: self.wasm_cache.wasm_hash_whitelist, + #[cfg(feature = "wasmtime")] + wasm_engine: Some(self.wasm_cache.wasm_engine), + #[cfg(feature = "wasmtime")] + wasm_component_cache: self.wasm_cache.wasm_component_cache, + mvconfig: self.mvconfig, + engine_version: self.engine_version, + } + } +} + +pub(crate) fn build_actions_execute_params() -> ExecuteParams { + BuildActionsExecuteParamsFixture::regular().build() +} + +#[cfg(test)] +mod tests { + use std::sync::atomic::Ordering; + + use super::*; + + #[test] + fn build_actions_execute_params_contract_covers_regular_branch() { + let last_tr_lt = Arc::new(AtomicU64::new(91)); + let vm_execution_is_block_related = Arc::new(Mutex::new(false)); + let block_collation_was_finished = Arc::new(Mutex::new(false)); + let dapp_id = UInt256::with_array([0x44; 32]); + let seed_block = UInt256::with_array([0x77; 32]); + let termination_deadline = Some(Instant::now() + Duration::from_secs(30)); + let execution_timeout = Some(Duration::from_secs(10)); + let mut mvconfig = MVConfig::default(); + mvconfig.set_config(vec![3, 5, 8]); + + let mut fixture = BuildActionsExecuteParamsFixture::regular(); + fixture.block_unixtime = 123; + fixture.block_lt = 456; + fixture.seq_no = 7; + fixture.last_tr_lt = last_tr_lt.clone(); + fixture.seed_block = seed_block.clone(); + #[cfg(feature = "signature_with_id")] + { + fixture.signature_id = -239; + } + fixture.vm_execution_is_block_related = vm_execution_is_block_related.clone(); + fixture.block_collation_was_finished = block_collation_was_finished.clone(); + fixture.dapp_id = Some(dapp_id.clone()); + fixture.available_credit = 13; + fixture.termination_deadline = termination_deadline; + fixture.execution_timeout = execution_timeout; + fixture.mvconfig = mvconfig.clone(); + fixture.engine_version = semver::Version::new(1, 0, 3); + #[cfg(feature = "wasmtime")] + { + fixture.wasm_cache.wasm_binary_root_path = "./tests/wasm".to_owned(); + fixture.wasm_cache.wasm_hash_whitelist.insert([0xab; 32]); + } + + let params = fixture.build(); + + assert_eq!(params.state_libs, HashmapE::with_bit_len(32)); + assert_eq!(params.block_unixtime, 123); + assert_eq!(params.block_lt, 456); + assert_eq!(params.seq_no, 7); + assert!(Arc::ptr_eq(¶ms.last_tr_lt, &last_tr_lt)); + assert_eq!(params.last_tr_lt.load(Ordering::Relaxed), 91); + assert_eq!(params.seed_block, seed_block); + assert!(!params.debug); + assert!(params.trace_callback.is_none()); + assert!(params.behavior_modifiers.is_none()); + assert_eq!(params.block_version, 0); + #[cfg(feature = "signature_with_id")] + assert_eq!(params.signature_id, -239); + assert!(Arc::ptr_eq(¶ms.vm_execution_is_block_related, &vm_execution_is_block_related)); + assert!(Arc::ptr_eq(¶ms.block_collation_was_finished, &block_collation_was_finished)); + assert_eq!(params.dapp_id, Some(dapp_id)); + assert_eq!(params.available_credit, 13); + assert_eq!(params.termination_deadline, termination_deadline); + assert_eq!(params.execution_timeout, execution_timeout); + #[cfg(feature = "wasmtime")] + { + assert_eq!(params.wasm_binary_root_path, "./tests/wasm"); + assert!(params.wasm_hash_whitelist.contains(&[0xab; 32])); + assert!(params.wasm_engine.is_some()); + assert!(params.wasm_component_cache.is_empty()); + } + assert_eq!(params.mvconfig, mvconfig); + assert_eq!(params.engine_version, semver::Version::new(1, 0, 3)); + } + + #[test] + fn build_actions_execute_params_contract_covers_tvm_tracing_branch() { + let callback: Arc = Arc::new(|_, _| {}); + + let params = BuildActionsExecuteParamsFixture::tvm_tracing(callback).build(); + + assert!(params.debug); + assert!(params.trace_callback.is_some()); + } +} diff --git a/tvm_executor/src/transaction_executor.rs b/tvm_executor/src/transaction_executor.rs index a41129ce7..6f3322a95 100644 --- a/tvm_executor/src/transaction_executor.rs +++ b/tvm_executor/src/transaction_executor.rs @@ -2154,6 +2154,7 @@ mod tests { use crate::BlockchainConfig; use crate::OrdinaryTransactionExecutor; use crate::blockchain_config::TONDefaultConfig; + use crate::test_utils::BuildActionsExecuteParamsFixture; struct DummyExecutor { config: BlockchainConfig, @@ -2307,32 +2308,33 @@ mod tests { let vm_execution_is_block_related = Arc::new(Mutex::new(false)); let block_collation_was_finished = Arc::new(Mutex::new(false)); let last_tr_lt = Arc::new(AtomicU64::new(100)); + let trace_steps = Arc::new(AtomicU64::new(0)); let mut mvconfig = MVConfig::default(); mvconfig.set_config(vec![3, 5, 8]); - let params = ExecuteParams { - block_unixtime: 123, - block_lt: 456, - seq_no: 7, - last_tr_lt: last_tr_lt.clone(), - seed_block: UInt256::with_array([0x77; 32]), - debug: true, - dapp_id: Some(dapp_id.clone()), - available_credit: 13, - termination_deadline: Some(Instant::now() + Duration::from_secs(30)), - execution_timeout: Some(Duration::from_secs(30)), - vm_execution_is_block_related: vm_execution_is_block_related.clone(), - block_collation_was_finished: block_collation_was_finished.clone(), - mvconfig, - engine_version: semver::Version::new(1, 0, 3), - ..ExecuteParams::default() - }; + let trace_steps_callback = trace_steps.clone(); + let trace_callback: Arc = Arc::new(move |_, _| { + trace_steps_callback.fetch_add(1, Ordering::Relaxed); + }); + let mut fixture = BuildActionsExecuteParamsFixture::tvm_tracing(trace_callback); + fixture.block_unixtime = 123; + fixture.block_lt = 456; + fixture.seq_no = 7; + fixture.last_tr_lt = last_tr_lt.clone(); + fixture.seed_block = UInt256::with_array([0x77; 32]); + fixture.dapp_id = Some(dapp_id.clone()); + fixture.available_credit = 13; + fixture.termination_deadline = Some(Instant::now() + Duration::from_secs(30)); + fixture.execution_timeout = Some(Duration::from_secs(30)); + fixture.vm_execution_is_block_related = vm_execution_is_block_related.clone(); + fixture.block_collation_was_finished = block_collation_was_finished.clone(); + fixture.mvconfig = mvconfig; + fixture.engine_version = semver::Version::new(1, 0, 3); #[cfg(feature = "wasmtime")] - let params = { - let mut params = params; - params.wasm_binary_root_path = "./tests/wasm".to_owned(); - params.wasm_engine = Some(wasmtime::Engine::default()); - params - }; + { + fixture.wasm_cache.wasm_binary_root_path = "./tests/wasm".to_owned(); + fixture.wasm_cache.wasm_engine = wasmtime::Engine::default(); + } + let params = fixture.build(); let code = tvm_assembler::compile_code_to_cell( "NOW\nPUSHINT 123\nEQUAL\nTHROWIFNOT 100\n\ @@ -2358,6 +2360,7 @@ mod tests { assert_eq!(tx.now(), 123); assert_eq!(tx.logical_time(), 100); assert_eq!(last_tr_lt.load(Ordering::Relaxed), 101); + assert!(trace_steps.load(Ordering::Relaxed) > 0); assert!(*vm_execution_is_block_related.lock().unwrap()); match tx.read_description().unwrap() { TransactionDescr::Ordinary(description) => { From 6e0a0680b9cd5684cfe11968594cdb630501fab6 Mon Sep 17 00:00:00 2001 From: Sergei Blinov Date: Tue, 19 May 2026 14:06:55 +0200 Subject: [PATCH 2/5] expand executor parameter coverage --- Cargo.lock | 1 + tvm_executor/Cargo.toml | 1 + tvm_executor/src/transaction_executor.rs | 431 ++++++++++++++++++++++- 3 files changed, 432 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 73d446812..ec48c0542 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6452,6 +6452,7 @@ dependencies = [ "log", "semver", "thiserror 2.0.18", + "tvm_abi", "tvm_assembler", "tvm_block", "tvm_types", diff --git a/tvm_executor/Cargo.toml b/tvm_executor/Cargo.toml index 34de48b48..da1fecb1e 100644 --- a/tvm_executor/Cargo.toml +++ b/tvm_executor/Cargo.toml @@ -22,6 +22,7 @@ tvm_vm.workspace = true wasmtime = { workspace = true, optional = true } [dev-dependencies] +tvm_abi.workspace = true tvm_assembler.workspace = true [features] diff --git a/tvm_executor/src/transaction_executor.rs b/tvm_executor/src/transaction_executor.rs index 6f3322a95..add236ced 100644 --- a/tvm_executor/src/transaction_executor.rs +++ b/tvm_executor/src/transaction_executor.rs @@ -2143,12 +2143,14 @@ mod tests { use tvm_block::TrActionPhase; use tvm_block::Transaction; use tvm_block::TransactionDescr; + use tvm_block::TransactionDescrOrdinary; use tvm_types::BuilderData; use tvm_types::Cell; use tvm_types::Result; use tvm_types::SliceData; use tvm_types::UInt256; use tvm_vm::stack::Stack; + use tvm_vm::stack::StackItem; use super::*; use crate::BlockchainConfig; @@ -2239,13 +2241,17 @@ mod tests { } fn executor_config() -> BlockchainConfig { + executor_config_with_capabilities(0x572e) + } + + fn executor_config_with_capabilities(capabilities: u64) -> BlockchainConfig { let mut config = ConfigParams { config_addr: UInt256::with_array([0x55; 32]), ..ConfigParams::default() }; config .set_config(ConfigParamEnum::ConfigParam8(ConfigParam8 { - global_version: GlobalVersion { version: 42, capabilities: 0x572e }, + global_version: GlobalVersion { version: 42, capabilities }, })) .unwrap(); config.set_config(ConfigParamEnum::ConfigParam18(storage_prices())).unwrap(); @@ -2285,6 +2291,189 @@ mod tests { .unwrap() } + fn internal_message(src: u8, dst: u8) -> Message { + Message::with_int_header(InternalMessageHeader::with_addresses( + address(src), + address(dst), + CurrencyCollection::with_grams(1_000_000_000), + )) + } + + fn execute_node_contract( + code: &str, + params: ExecuteParams, + ) -> std::result::Result<(Transaction, i128), anyhow::Error> { + execute_node_contract_with_config(code, params, executor_config()) + } + + fn execute_node_contract_with_config( + code: &str, + params: ExecuteParams, + config: BlockchainConfig, + ) -> std::result::Result<(Transaction, i128), anyhow::Error> { + let executor = OrdinaryTransactionExecutor::new(config); + let code = tvm_assembler::compile_code_to_cell(code).unwrap(); + let account = active_account_with_code(7, code); + let mut account_root = account.serialize().unwrap(); + executor.execute_with_libs_and_params( + Some(&internal_message(1, 7)), + &mut account_root, + params, + ) + } + + fn ordinary_description(tx: &Transaction) -> TransactionDescrOrdinary { + match tx.read_description().unwrap() { + TransactionDescr::Ordinary(description) => description, + _ => panic!("unexpected transaction description"), + } + } + + fn vm_phase(tx: &Transaction) -> TrComputePhaseVm { + match ordinary_description(tx).compute_ph { + TrComputePhase::Vm(phase) => phase, + _ => panic!("unexpected compute phase"), + } + } + + fn run_mint_shellq_action( + available_credit: i128, + initial_minted_shell: i128, + requested: u64, + ) -> (ActionPhaseResult, i128, u128) { + let executor = DummyExecutor::new(); + let mut account = active_account(8); + let mut tx = Transaction::with_address_and_status(address(8).address(), account.status()); + let original_balance = account.balance().cloned().unwrap(); + let mut acc_balance = original_balance.clone(); + let mut msg_balance = CurrencyCollection::default(); + let mut actions = OutActions::default(); + actions.push_back(OutAction::new_mint_shellq(requested)); + let mut minted_shell = initial_minted_shell; + + let result = executor + .action_phase_with_copyleft( + &mut tx, + &mut account, + &original_balance, + &mut acc_balance, + &mut msg_balance, + &Grams::zero(), + actions.serialize().unwrap(), + None, + &address(8), + false, + available_credit, + &mut minted_shell, + Grams::zero(), + Some(UInt256::with_array([0x99; 32])), + ) + .unwrap(); + + (result, minted_shell, acc_balance.grams.as_u128() - original_balance.grams.as_u128()) + } + + fn bytes_to_hex(bytes: &[u8]) -> String { + bytes.iter().map(|byte| format!("{byte:02x}")).collect() + } + + #[cfg(feature = "wasmtime")] + fn bytes_from_hex(hex: &str) -> Vec { + (0..hex.len()) + .step_by(2) + .map(|index| u8::from_str_radix(&hex[index..index + 2], 16).unwrap()) + .collect() + } + + #[cfg(feature = "wasmtime")] + fn run_wasm_hash_stack(wasm_hash: &[u8]) -> Stack { + use tvm_abi::TokenValue; + use tvm_abi::contract::ABI_VERSION_2_4; + + let hash_cell = + TokenValue::write_bytes(wasm_hash, &ABI_VERSION_2_4).unwrap().into_cell().unwrap(); + let args_cell = + TokenValue::write_bytes(&[1u8, 2u8], &ABI_VERSION_2_4).unwrap().into_cell().unwrap(); + let function_cell = tvm_vm::utils::pack_data_to_cell(b"add", &mut 0).unwrap(); + let instance_cell = + tvm_vm::utils::pack_data_to_cell(b"docs:adder/add-interface@0.1.0", &mut 0).unwrap(); + let dict_cell = + TokenValue::write_bytes(&[], &ABI_VERSION_2_4).unwrap().into_cell().unwrap(); + + let mut stack = Stack::new(); + stack.push(StackItem::cell(hash_cell)); + stack.push(StackItem::cell(args_cell)); + stack.push(StackItem::cell(function_cell)); + stack.push(StackItem::cell(instance_cell)); + stack.push(StackItem::cell(dict_cell)); + stack + } + + #[allow(deprecated)] + fn compute_node_contract( + code: &str, + argument_stack: Stack, + params: ExecuteParams, + ) -> TrComputePhaseVm { + let executor = OrdinaryTransactionExecutor::new(executor_config()); + let code = tvm_assembler::compile_code_to_cell(code).unwrap(); + let mut account = active_account_with_code(7, code); + let mut msg = internal_message(1, 7); + let mut acc_balance = account.balance().cloned().unwrap(); + let mut msg_balance = CurrencyCollection::with_grams(1_000_000_000); + let smc_info = + executor.build_contract_info(&acc_balance, &address(7), 0, 0, 0, UInt256::default()); + let mut stack = executor.build_stack(Some(&msg), &account); + for index in (0..argument_stack.depth()).rev() { + stack.push(argument_stack.get(index).clone()); + } + + let (phase, _, _) = executor + .compute_phase( + Some(&mut msg), + &mut account, + &mut acc_balance, + &mut msg_balance, + smc_info, + stack, + 0, + false, + false, + ¶ms, + ) + .unwrap(); + match phase { + TrComputePhase::Vm(phase) => phase, + _ => panic!("unexpected compute phase"), + } + } + + fn uint64_array_cell(values: &[u64]) -> Cell { + use tvm_abi::TokenValue; + use tvm_abi::contract::ABI_VERSION_2_2; + use tvm_abi::param_type::ParamType; + + let items = values + .iter() + .map(|value| TokenValue::Uint(tvm_abi::Uint::new(*value as u128, 64))) + .collect(); + TokenValue::Array(ParamType::Uint(64), items) + .pack_into_chain(&ABI_VERSION_2_2) + .unwrap() + .into_cell() + .unwrap() + } + + fn calc_mv_reward_stack() -> Stack { + let mut stack = Stack::new(); + stack.push(StackItem::int(0)); + stack.push(StackItem::int(0)); + stack.push(StackItem::cell(uint64_array_cell(&[1, 1]))); + stack.push(StackItem::int(2)); + stack.push(StackItem::int(1_000_000_000)); + stack + } + #[test] fn action_phase_result_from_phase_starts_empty() { let phase = TrActionPhase { @@ -2379,6 +2568,246 @@ mod tests { .with_borrow(|x| assert!(x.is_none())); } + #[test] + fn node_params_available_credit_reaches_get_available_balance() { + for (available_credit, expected_balance) in [(0, 0), (42, 42), (INFINITY_CREDIT, 0)] { + let mut fixture = BuildActionsExecuteParamsFixture::regular(); + fixture.available_credit = available_credit; + + let (tx, minted_shell) = execute_node_contract( + &format!( + "GETAVAILABLEBALANCE\n\ + PUSHINT {}\n\ + EQUAL\n\ + THROWIFNOT 201\n", + expected_balance + ), + fixture.build(), + ) + .unwrap(); + + let phase = vm_phase(&tx); + assert!(phase.success, "{phase:?}"); + assert_eq!(phase.exit_code, 0); + assert_eq!(minted_shell, 0); + } + } + + #[test] + fn node_params_dapp_id_reaches_my_dapp_id() { + let dapp_id = UInt256::with_array([0x31; 32]); + let mut fixture = BuildActionsExecuteParamsFixture::regular(); + fixture.dapp_id = Some(dapp_id); + + let (tx, _) = execute_node_contract( + "MYDAPPID\n\ + PUSHINT 0x3131313131313131313131313131313131313131313131313131313131313131\n\ + EQUAL\n\ + THROWIFNOT 202\n", + fixture.build(), + ) + .unwrap(); + + let phase = vm_phase(&tx); + assert!(phase.success, "{phase:?}"); + assert_eq!(phase.exit_code, 0); + } + + #[test] + fn node_params_missing_dapp_id_is_observable_in_my_dapp_id() { + let fixture = BuildActionsExecuteParamsFixture::regular(); + + let (tx, _) = execute_node_contract("MYDAPPID\n", fixture.build()).unwrap(); + + let phase = vm_phase(&tx); + assert!(!phase.success, "{phase:?}"); + assert_eq!(phase.exit_code, ExceptionCode::DAppIdNotSet as i32); + } + + #[test] + fn node_params_reached_termination_deadline_aborts_execution() { + let mut fixture = BuildActionsExecuteParamsFixture::regular(); + fixture.termination_deadline = Some(Instant::now() - Duration::from_secs(1)); + + let err = execute_node_contract("PUSHINT 1\n", fixture.build()).unwrap_err(); + + assert!(matches!( + err.downcast_ref::(), + Some(ExecutorError::TerminationDeadlineReached) + )); + } + + #[test] + fn node_params_zero_execution_timeout_reaches_vm_compute_phase() { + let mut fixture = BuildActionsExecuteParamsFixture::regular(); + fixture.execution_timeout = Some(Duration::ZERO); + + let (tx, _) = execute_node_contract("PUSHINT 1\n", fixture.build()).unwrap(); + + let phase = vm_phase(&tx); + assert!(!phase.success, "{phase:?}"); + assert_eq!(phase.exit_code, ExceptionCode::ExecutionTimeout as i32); + } + + #[test] + fn node_params_minted_shellq_limits_cover_zero_limited_and_infinite_credit() { + let (result, minted_shell, credited) = run_mint_shellq_action(0, 0, 20); + assert!(result.phase.success, "{:?}", result.phase); + assert_eq!(result.phase.spec_actions, 1); + assert_eq!(minted_shell, 0); + assert_eq!(credited, 0); + + let (result, minted_shell, credited) = run_mint_shellq_action(13, 5, 20); + assert!(result.phase.success, "{:?}", result.phase); + assert_eq!(result.phase.spec_actions, 1); + assert_eq!(minted_shell, 13); + assert_eq!(credited, 8); + + let (result, minted_shell, credited) = run_mint_shellq_action(INFINITY_CREDIT, 0, 20); + assert!(result.phase.success, "{:?}", result.phase); + assert_eq!(result.phase.spec_actions, 1); + assert_eq!(minted_shell, 20); + assert_eq!(credited, 20); + } + + #[test] + fn node_params_engine_version_reaches_calc_min_stake() { + for (engine_version, expected_min_stake) in [ + (semver::Version::new(1, 0, 1), 14_393_409_967_783u128), + (semver::Version::new(1, 0, 3), 10_000_000_000_000_000u128), + ] { + let mut fixture = BuildActionsExecuteParamsFixture::regular(); + fixture.engine_version = engine_version; + + let (tx, _) = execute_node_contract( + &format!( + "PUSHINT 0\n\ + PUSHINT 0\n\ + PUSHINT 0\n\ + PUSHINT 1\n\ + CALCMINSTAKE\n\ + PUSHINT {}\n\ + EQUAL\n\ + THROWIFNOT 204\n", + expected_min_stake + ), + fixture.build(), + ) + .unwrap(); + + let phase = vm_phase(&tx); + assert!(phase.success, "{phase:?}"); + assert_eq!(phase.exit_code, 0); + } + } + + #[test] + fn node_params_mvconfig_reaches_calc_mv_reward() { + let fixture = BuildActionsExecuteParamsFixture::regular(); + let phase = compute_node_contract( + "CALCMVREWARD\n\ + PUSHINT 0\n\ + EQUAL\n\ + THROWIFNOT 205\n", + calc_mv_reward_stack(), + fixture.build(), + ); + assert!(phase.success, "{phase:?}"); + + let mut fixture = BuildActionsExecuteParamsFixture::regular(); + fixture.mvconfig.set_config(vec![1, 3]); + let phase = compute_node_contract( + "CALCMVREWARD\n\ + PUSHINT 0\n\ + GREATER\n\ + THROWIFNOT 206\n", + calc_mv_reward_stack(), + fixture.build(), + ); + assert!(phase.success, "{phase:?}"); + } + + #[cfg(feature = "signature_with_id")] + #[test] + fn node_params_signature_id_reaches_chksignu() { + let signature_id = 17i32; + let data_hash = [0x42; 32]; + let key = tvm_types::Ed25519KeyOption::from_private_key(&[0x11; 32]).unwrap(); + let mut signed_data = signature_id.to_be_bytes().to_vec(); + signed_data.extend_from_slice(&data_hash); + let signature = key.sign(&signed_data).unwrap(); + let code = format!( + "PUSHINT 0x{}\n\ + PUSHSLICE x{}\n\ + PUSHINT 0x{}\n\ + CHKSIGNU\n\ + THROWIFNOT 203\n", + bytes_to_hex(&data_hash), + bytes_to_hex(&signature), + bytes_to_hex(key.pub_key().unwrap()) + ); + + let mut fixture = BuildActionsExecuteParamsFixture::regular(); + fixture.signature_id = signature_id; + let config = executor_config_with_capabilities( + 0x572e | GlobalCapabilities::CapSignatureWithId as u64, + ); + let (tx, _) = + execute_node_contract_with_config(&code, fixture.build(), config.clone()).unwrap(); + let phase = vm_phase(&tx); + assert!(phase.success, "{phase:?}"); + assert_eq!(phase.exit_code, 0); + + let mut fixture = BuildActionsExecuteParamsFixture::regular(); + fixture.signature_id = signature_id + 1; + let (tx, _) = execute_node_contract_with_config(&code, fixture.build(), config).unwrap(); + let phase = vm_phase(&tx); + assert!(!phase.success, "{phase:?}"); + assert_eq!(phase.exit_code, 203); + } + + #[cfg(feature = "wasmtime")] + #[test] + fn node_params_wasm_hash_whitelist_reaches_run_wasm() { + let hash_str = "7b7f96a857a4ada292d7c6b1f47940dde33112a2c2bc15b577dff9790edaeef2"; + let wasm_hash = bytes_from_hex(hash_str); + let mut fixture = BuildActionsExecuteParamsFixture::regular(); + fixture.wasm_cache.wasm_binary_root_path = "../tvm_vm/config/wasm".to_owned(); + fixture.wasm_cache.wasm_engine = + tvm_vm::executor::Engine::extern_wasm_engine_init().unwrap(); + + let phase = + compute_node_contract("RUNWASM\n", run_wasm_hash_stack(&wasm_hash), fixture.build()); + assert!(!phase.success, "{phase:?}"); + assert_eq!(phase.exit_code, ExceptionCode::WasmWhitelistForbiddenHash as i32); + } + + #[cfg(feature = "wasmtime")] + #[test] + fn node_params_wasm_whitelist_and_cache_allow_run_wasm() { + let hash_str = "7b7f96a857a4ada292d7c6b1f47940dde33112a2c2bc15b577dff9790edaeef2"; + let wasm_hash: [u8; 32] = bytes_from_hex(hash_str).try_into().unwrap(); + let wasm_engine = tvm_vm::executor::Engine::extern_wasm_engine_init().unwrap(); + let wasm_hash_whitelist: std::collections::HashSet<[u8; 32]> = + [wasm_hash].into_iter().collect(); + let wasm_component_cache = + tvm_vm::executor::Engine::extern_precompile_all_wasm_from_hash_list( + "../tvm_vm/config/wasm".to_owned(), + wasm_engine.clone(), + wasm_hash_whitelist.clone(), + ); + let mut fixture = BuildActionsExecuteParamsFixture::regular(); + fixture.wasm_cache.wasm_binary_root_path = "../tvm_vm/config/wasm".to_owned(); + fixture.wasm_cache.wasm_engine = wasm_engine; + fixture.wasm_cache.wasm_hash_whitelist = wasm_hash_whitelist; + fixture.wasm_cache.wasm_component_cache = wasm_component_cache; + + let phase = + compute_node_contract("RUNWASM\n", run_wasm_hash_stack(&wasm_hash), fixture.build()); + assert!(phase.success, "{phase:?}"); + assert_eq!(phase.exit_code, 0); + } + #[test] fn action_phase_caps_shell_minting_and_applies_dapp_config_action() { let executor = DummyExecutor::new(); From 42e7cc78885edaef43b34e0bc8eb66fded5892f0 Mon Sep 17 00:00:00 2001 From: Sergei Blinov Date: Wed, 20 May 2026 01:19:35 +0200 Subject: [PATCH 3/5] Make build_actions fixture match node wasm cache --- tvm_executor/src/test_utils.rs | 118 ++++++++++++++++++++--- tvm_executor/src/transaction_executor.rs | 5 - 2 files changed, 103 insertions(+), 20 deletions(-) diff --git a/tvm_executor/src/test_utils.rs b/tvm_executor/src/test_utils.rs index 46f457ac0..1c7f35f13 100644 --- a/tvm_executor/src/test_utils.rs +++ b/tvm_executor/src/test_utils.rs @@ -10,18 +10,39 @@ use std::time::Instant; use tvm_types::HashmapE; use tvm_types::UInt256; +#[cfg(feature = "wasmtime")] +use tvm_vm::executor::Engine; use tvm_vm::executor::MVConfig; use crate::ExecuteParams; // Mirrors ExecuteParams construction in acki-nacki/node's block builder -// `build_actions.rs`. +// `build_actions.rs` and its WasmNodeCache from `producer/wasm.rs`. +#[cfg(feature = "wasmtime")] +const NODE_WASM_BINARY_ROOT_PATH: &str = "./config/wasm"; +#[cfg(feature = "wasmtime")] +const NODE_WASM_HASH_STRS: [&str; 12] = [ + "c5b3fe1a4fa391e9660a13d55ca2200f9343d5b1d18473ebbee19d8219e3ddc1", + "7b7f96a857a4ada292d7c6b1f47940dde33112a2c2bc15b577dff9790edaeef2", + "e88c99c9a1cbbde5bf47839db7685953c3bf266945f3270abb731ed84d58d163", + "e7adc782c05b67bcda5babaca1deabf80f30ca0e6cf668c89825286c3ce0e560", + "afbe8c5a02df7d6fa5decd4d48ff0f74ecbd4dae38bb5144328354db6bd95967", + "25dc3d80d7e4d8f27dfadc9c2faf9cf2d8dea0a9e08a692da2db7e34d74d66e1", + "d4a067079c3ff4e0b0b6f579ef2d1b9a1d8fc21a0076162503ff46a6e8fca2e5", + "f6b0cc30d023d266819b16dafa5a6a6ad25b97246bbbca80abac2df974939b87", + "7670910579bb17bf986de6e318c6f5a8bf7e148b3fb8e0cbf03479fb9eb8c948", + "b8891b913656ae35d9ffff371f0f03e4f1f869d0e17556a8c273750313884b0a", + "2d577ca2e693700282d6d778dce8cfcedbada644497e411ec6aed889f5a3d5f4", + "343268736f6dbb5a075a477fb1146b3c25c114d341b41c142e6609a7d1a90a2c", +]; + pub(crate) enum BuildActionsTraceMode { Regular, TvmTracing { trace_callback: Arc }, } #[cfg(feature = "wasmtime")] +#[derive(Clone)] pub(crate) struct BuildActionsWasmCache { pub wasm_binary_root_path: String, pub wasm_hash_whitelist: HashSet<[u8; 32]>, @@ -32,12 +53,42 @@ pub(crate) struct BuildActionsWasmCache { #[cfg(feature = "wasmtime")] impl Default for BuildActionsWasmCache { fn default() -> Self { - Self { - wasm_binary_root_path: "./config/wasm".to_owned(), - wasm_hash_whitelist: HashSet::new(), - wasm_engine: wasmtime::Engine::default(), - wasm_component_cache: HashMap::new(), - } + Self::with_binary_root_path(NODE_WASM_BINARY_ROOT_PATH) + } +} + +#[cfg(feature = "wasmtime")] +impl BuildActionsWasmCache { + pub(crate) fn with_binary_root_path(wasm_binary_root_path: impl Into) -> Self { + let wasm_binary_root_path = wasm_binary_root_path.into(); + let wasm_hash_whitelist = Self::node_wasm_hash_whitelist(); + let wasm_engine = Self::node_wasm_engine(); + let wasm_component_cache = Engine::extern_precompile_all_wasm_from_hash_list( + wasm_binary_root_path.clone(), + wasm_engine.clone(), + wasm_hash_whitelist.clone(), + ); + + Self { wasm_binary_root_path, wasm_hash_whitelist, wasm_engine, wasm_component_cache } + } + + fn node_wasm_hash_whitelist() -> HashSet<[u8; 32]> { + NODE_WASM_HASH_STRS.into_iter().map(Self::parse_wasm_hash).collect() + } + + fn parse_wasm_hash(hash_str: &str) -> [u8; 32] { + let hash = (0..hash_str.len()) + .step_by(2) + .map(|i| u8::from_str_radix(&hash_str[i..i + 2], 16).unwrap()) + .collect::>(); + + hash.try_into().unwrap_or_else(|_| panic!("node wasm hash must be 32 bytes: {hash_str}")) + } + + fn node_wasm_engine() -> wasmtime::Engine { + Engine::extern_wasm_engine_init().unwrap_or_else(|err| { + panic!("Could not initialise node-like Wasm engine: {err:?}"); + }) } } @@ -181,11 +232,6 @@ mod tests { fixture.execution_timeout = execution_timeout; fixture.mvconfig = mvconfig.clone(); fixture.engine_version = semver::Version::new(1, 0, 3); - #[cfg(feature = "wasmtime")] - { - fixture.wasm_cache.wasm_binary_root_path = "./tests/wasm".to_owned(); - fixture.wasm_cache.wasm_hash_whitelist.insert([0xab; 32]); - } let params = fixture.build(); @@ -210,15 +256,57 @@ mod tests { assert_eq!(params.execution_timeout, execution_timeout); #[cfg(feature = "wasmtime")] { - assert_eq!(params.wasm_binary_root_path, "./tests/wasm"); - assert!(params.wasm_hash_whitelist.contains(&[0xab; 32])); + assert_eq!(params.wasm_binary_root_path, NODE_WASM_BINARY_ROOT_PATH); + assert_eq!( + params.wasm_hash_whitelist, + BuildActionsWasmCache::node_wasm_hash_whitelist() + ); + assert_eq!(params.wasm_hash_whitelist.len(), NODE_WASM_HASH_STRS.len()); assert!(params.wasm_engine.is_some()); - assert!(params.wasm_component_cache.is_empty()); + assert!( + params + .wasm_component_cache + .keys() + .all(|hash| params.wasm_hash_whitelist.contains(hash)) + ); } assert_eq!(params.mvconfig, mvconfig); assert_eq!(params.engine_version, semver::Version::new(1, 0, 3)); } + #[cfg(feature = "wasmtime")] + #[test] + fn build_actions_wasm_cache_precompiles_available_node_wasm_components() { + use std::fmt::Write; + use std::path::Path; + + fn hash_to_hex(hash: &[u8; 32]) -> String { + let mut s = String::with_capacity(64); + for byte in hash { + write!(&mut s, "{byte:02x}").unwrap(); + } + s + } + + let wasm_binary_root_path = format!("{}/../tvm_vm/config/wasm", env!("CARGO_MANIFEST_DIR")); + let cache = BuildActionsWasmCache::with_binary_root_path(wasm_binary_root_path.clone()); + let expected_precompiled = cache + .wasm_hash_whitelist + .iter() + .filter(|hash| { + let path = Path::new(&wasm_binary_root_path).join(hash_to_hex(hash)); + path.is_file() + }) + .count(); + + assert_eq!(cache.wasm_hash_whitelist, BuildActionsWasmCache::node_wasm_hash_whitelist()); + assert!(expected_precompiled > 0); + assert_eq!(cache.wasm_component_cache.len(), expected_precompiled); + assert!( + cache.wasm_component_cache.keys().all(|hash| cache.wasm_hash_whitelist.contains(hash)) + ); + } + #[test] fn build_actions_execute_params_contract_covers_tvm_tracing_branch() { let callback: Arc = Arc::new(|_, _| {}); diff --git a/tvm_executor/src/transaction_executor.rs b/tvm_executor/src/transaction_executor.rs index 6f3322a95..1653e0cbf 100644 --- a/tvm_executor/src/transaction_executor.rs +++ b/tvm_executor/src/transaction_executor.rs @@ -2329,11 +2329,6 @@ mod tests { fixture.block_collation_was_finished = block_collation_was_finished.clone(); fixture.mvconfig = mvconfig; fixture.engine_version = semver::Version::new(1, 0, 3); - #[cfg(feature = "wasmtime")] - { - fixture.wasm_cache.wasm_binary_root_path = "./tests/wasm".to_owned(); - fixture.wasm_cache.wasm_engine = wasmtime::Engine::default(); - } let params = fixture.build(); let code = tvm_assembler::compile_code_to_cell( From 816c862d52f8b3d5d2a28f0889bca1ce06f59d26 Mon Sep 17 00:00:00 2001 From: Sergei Blinov Date: Tue, 2 Jun 2026 13:28:10 +0200 Subject: [PATCH 4/5] refine executor coverage for engine version and wasm cache --- tvm_executor/src/transaction_executor.rs | 88 ++++++++++++++++-------- 1 file changed, 59 insertions(+), 29 deletions(-) diff --git a/tvm_executor/src/transaction_executor.rs b/tvm_executor/src/transaction_executor.rs index 7e0d1f7e6..b25e24144 100644 --- a/tvm_executor/src/transaction_executor.rs +++ b/tvm_executor/src/transaction_executor.rs @@ -2448,6 +2448,37 @@ mod tests { } } + fn currency_other_u64(balance: &CurrencyCollection, key: u32) -> u64 { + let Some(value) = balance.get_other(key).unwrap() else { + return 0; + }; + value.value().iter_u64_digits().next().unwrap_or(0) + } + + fn cross_dapp_exchange_balance(engine_version: semver::Version) -> CurrencyCollection { + let executor = OrdinaryTransactionExecutor::new(executor_config()); + let code = tvm_assembler::compile_code_to_cell("PUSHINT 1\n").unwrap(); + let account = active_account_with_code(7, code); + let mut account_root = account.serialize().unwrap(); + let mut msg_value = CurrencyCollection::with_grams(1_000_000_000); + msg_value.set_other(2, 123).unwrap(); + let mut header = InternalMessageHeader::with_addresses(address(1), address(7), msg_value); + header.set_src_dapp_id(Some(UInt256::with_array([0x33; 32]))); + header.set_exchange(true); + let msg = Message::with_int_header(header); + + let mut fixture = BuildActionsExecuteParamsFixture::regular(); + fixture.dapp_id = Some(UInt256::with_array([0x22; 32])); + fixture.engine_version = engine_version; + let (tx, _) = executor + .execute_with_libs_and_params(Some(&msg), &mut account_root, fixture.build()) + .unwrap(); + let phase = vm_phase(&tx); + assert!(phase.success, "{phase:?}"); + + Account::construct_from_cell(account_root).unwrap().balance_checked() + } + fn uint64_array_cell(values: &[u64]) -> Cell { use tvm_abi::TokenValue; use tvm_abi::contract::ABI_VERSION_2_2; @@ -2666,34 +2697,13 @@ mod tests { } #[test] - fn node_params_engine_version_reaches_calc_min_stake() { - for (engine_version, expected_min_stake) in [ - (semver::Version::new(1, 0, 1), 14_393_409_967_783u128), - (semver::Version::new(1, 0, 3), 10_000_000_000_000_000u128), - ] { - let mut fixture = BuildActionsExecuteParamsFixture::regular(); - fixture.engine_version = engine_version; + fn node_params_engine_version_reaches_cross_dapp_exchange() { + let pre_1_0_3_balance = cross_dapp_exchange_balance(semver::Version::new(1, 0, 2)); + let post_1_0_3_balance = cross_dapp_exchange_balance(semver::Version::new(1, 0, 3)); - let (tx, _) = execute_node_contract( - &format!( - "PUSHINT 0\n\ - PUSHINT 0\n\ - PUSHINT 0\n\ - PUSHINT 1\n\ - CALCMINSTAKE\n\ - PUSHINT {}\n\ - EQUAL\n\ - THROWIFNOT 204\n", - expected_min_stake - ), - fixture.build(), - ) - .unwrap(); - - let phase = vm_phase(&tx); - assert!(phase.success, "{phase:?}"); - assert_eq!(phase.exit_code, 0); - } + assert_eq!(currency_other_u64(&pre_1_0_3_balance, 2), 123); + assert_eq!(currency_other_u64(&post_1_0_3_balance, 2), 0); + assert_eq!(post_1_0_3_balance.grams.as_u128() - pre_1_0_3_balance.grams.as_u128(), 123); } #[test] @@ -2768,6 +2778,7 @@ mod tests { let wasm_hash = bytes_from_hex(hash_str); let mut fixture = BuildActionsExecuteParamsFixture::regular(); fixture.wasm_cache.wasm_binary_root_path = "../tvm_vm/config/wasm".to_owned(); + fixture.wasm_cache.wasm_hash_whitelist.clear(); fixture.wasm_cache.wasm_engine = tvm_vm::executor::Engine::extern_wasm_engine_init().unwrap(); @@ -2793,14 +2804,33 @@ mod tests { ); let mut fixture = BuildActionsExecuteParamsFixture::regular(); fixture.wasm_cache.wasm_binary_root_path = "../tvm_vm/config/wasm".to_owned(); - fixture.wasm_cache.wasm_engine = wasm_engine; - fixture.wasm_cache.wasm_hash_whitelist = wasm_hash_whitelist; + fixture.wasm_cache.wasm_engine = wasm_engine.clone(); + fixture.wasm_cache.wasm_hash_whitelist = wasm_hash_whitelist.clone(); fixture.wasm_cache.wasm_component_cache = wasm_component_cache; let phase = compute_node_contract("RUNWASM\n", run_wasm_hash_stack(&wasm_hash), fixture.build()); assert!(phase.success, "{phase:?}"); assert_eq!(phase.exit_code, 0); + + let wrong_binary = std::fs::read( + "../tvm_vm/config/wasm/65b6403f531ba6504e590905712af3208ddcba3d0c4ea4c003d1ef9685ec4947", + ) + .unwrap(); + let wrong_component = + wasmtime::component::Component::new(&wasm_engine, wrong_binary.as_slice()).unwrap(); + let mut poisoned_cache = std::collections::HashMap::new(); + poisoned_cache.insert(wasm_hash, wrong_component); + let mut fixture = BuildActionsExecuteParamsFixture::regular(); + fixture.wasm_cache.wasm_binary_root_path = "../tvm_vm/config/wasm".to_owned(); + fixture.wasm_cache.wasm_engine = wasm_engine; + fixture.wasm_cache.wasm_hash_whitelist = wasm_hash_whitelist; + fixture.wasm_cache.wasm_component_cache = poisoned_cache; + + let phase = + compute_node_contract("RUNWASM\n", run_wasm_hash_stack(&wasm_hash), fixture.build()); + assert!(!phase.success, "{phase:?}"); + assert_ne!(phase.exit_code, 0); } #[test] From 2894b9974e425c9d6a89407c72e0d89a49c615d9 Mon Sep 17 00:00:00 2001 From: Sergei Blinov Date: Fri, 12 Jun 2026 13:47:22 +0200 Subject: [PATCH 5/5] fix: resolve clippy warnings in tests and source code - Fix redundant references in println!/format! macros (tvm_types/bls.rs, tvm_block_json/serialize.rs, tvm_tl_codegen/lib.rs) - Fix field-reassign-with-default in test_config_params.rs - Fix unnecessary cast, len_zero, bool_comparison in test_signature.rs - All priority unit tests pass (tvm_abi, tvm_block, tvm_types, tvm_block_json, tvm_sdk, tvm_vm, tvm_executor, tvm_client) - cargo fmt --check passes --- tvm_block/tests/test_config_params.rs | 34 +++++++++++---------------- tvm_block/tests/test_signature.rs | 8 +++---- tvm_block_json/src/serialize.rs | 2 +- tvm_tl_codegen/src/lib.rs | 2 +- tvm_types/src/bls.rs | 14 +++++------ 5 files changed, 27 insertions(+), 33 deletions(-) diff --git a/tvm_block/tests/test_config_params.rs b/tvm_block/tests/test_config_params.rs index 037a77019..4d7c62b7e 100644 --- a/tvm_block/tests/test_config_params.rs +++ b/tvm_block/tests/test_config_params.rs @@ -157,14 +157,14 @@ fn test_config_msg_forward_prices() { fn get_cat_chain_config() -> CatchainConfig { let mut rng = rand::thread_rng(); - let mut cc = CatchainConfig::default(); - cc.shuffle_mc_validators = rng.gen(); - cc.isolate_mc_validators = rng.gen(); - cc.mc_catchain_lifetime = rng.gen(); - cc.shard_catchain_lifetime = rng.gen(); - cc.shard_validators_lifetime = rng.gen(); - cc.shard_validators_num = rng.gen(); - cc + CatchainConfig { + shuffle_mc_validators: rng.gen(), + isolate_mc_validators: rng.gen(), + mc_catchain_lifetime: rng.gen(), + shard_catchain_lifetime: rng.gen(), + shard_validators_lifetime: rng.gen(), + shard_validators_num: rng.gen(), + } } #[test] @@ -215,16 +215,13 @@ fn get_validator_set() -> ValidatorSet { #[test] fn test_config_param_32_34_36() { - let mut cp32 = ConfigParam32::default(); - cp32.prev_validators = get_validator_set(); + let cp32 = ConfigParam32 { prev_validators: get_validator_set() }; write_read_and_assert(cp32); - let mut cp34 = ConfigParam34::default(); - cp34.cur_validators = get_validator_set(); + let cp34 = ConfigParam34 { cur_validators: get_validator_set() }; write_read_and_assert(cp34); - let mut cp36 = ConfigParam36::default(); - cp36.next_validators = get_validator_set(); + let cp36 = ConfigParam36 { next_validators: get_validator_set() }; write_read_and_assert(cp36); } @@ -493,8 +490,7 @@ fn test_config_params() { ); assert!(!cp.prev_validator_set_present().unwrap()); - let mut cp32 = ConfigParam32::default(); - cp32.prev_validators = get_validator_set(); + let cp32 = ConfigParam32 { prev_validators: get_validator_set() }; let c32 = ConfigParamEnum::ConfigParam32(cp32); cp.set_config(c32.clone()).unwrap(); let c = cp.config(32).unwrap().unwrap(); @@ -503,8 +499,7 @@ fn test_config_params() { assert!(cp.prev_validator_set_present().unwrap()); write_read_and_assert(cp.clone()); - let mut cp34 = ConfigParam34::default(); - cp34.cur_validators = get_validator_set(); + let cp34 = ConfigParam34 { cur_validators: get_validator_set() }; let c34 = ConfigParamEnum::ConfigParam34(cp34); cp.set_config(c34.clone()).unwrap(); let c = cp.config(34).unwrap().unwrap(); @@ -520,8 +515,7 @@ fn test_config_params() { ); assert!(!cp.next_validator_set_present().unwrap()); - let mut cp36 = ConfigParam36::default(); - cp36.next_validators = get_validator_set(); + let cp36 = ConfigParam36 { next_validators: get_validator_set() }; let c36 = ConfigParamEnum::ConfigParam36(cp36); cp.set_config(c36.clone()).unwrap(); let c = cp.config(36).unwrap().unwrap(); diff --git a/tvm_block/tests/test_signature.rs b/tvm_block/tests/test_signature.rs index b6d6afb66..4af1f495e 100644 --- a/tvm_block/tests/test_signature.rs +++ b/tvm_block/tests/test_signature.rs @@ -253,7 +253,7 @@ fn test_crypto_signature_read_from_invalid_tag() { // Create data with wrong tag (not 0x5) let mut builder = BuilderData::new(); - builder.append_bits(0x7 as usize, 4).unwrap(); // wrong tag + builder.append_bits(0x7_usize, 4).unwrap(); // wrong tag builder.append_raw(&[1; 64], 64 * 8).unwrap(); let cell = builder.into_cell().unwrap(); let mut slice = SliceData::load_cell(cell).unwrap(); @@ -892,7 +892,7 @@ fn test_crypto_signature_to_bytes() { fn test_crypto_signature_signature_method() { let cs = CryptoSignature::from_r_s(&[1; 32], &[2; 32]).unwrap(); let sig_ref = cs.signature(); - assert!(sig_ref.to_bytes().len() > 0); + assert!(!sig_ref.to_bytes().is_empty()); } #[test] @@ -939,7 +939,7 @@ fn test_block_signatures_pure_signatures_method() { bsp.add_sigpair(csp); let sigs = bsp.signatures(); - assert!(sigs.is_empty() == false || bsp.count() > 0); + assert!(!sigs.is_empty() || bsp.count() > 0); } #[test] @@ -1166,7 +1166,7 @@ fn test_sig_pub_key_verify_signature_error_branch() { let invalid_key = SigPubKey::from_bytes(&[0; 32]).unwrap(); let cs = CryptoSignature::from_r_s(&[1; 32], &[2; 32]).unwrap(); let result = invalid_key.verify_signature(b"test", &cs); - assert!(result == true || result == false); + assert!(result || !result); } #[test] diff --git a/tvm_block_json/src/serialize.rs b/tvm_block_json/src/serialize.rs index 0a9b6c407..809af114a 100644 --- a/tvm_block_json/src/serialize.rs +++ b/tvm_block_json/src/serialize.rs @@ -1548,7 +1548,7 @@ pub fn serialize_config_param(config: &ConfigParams, config_number: u32) -> Resu if let Some(cp) = serialize_known_config_param(config_number, param, SerializationMode::Standart)? { - master_map.insert(format!("p{}", &config_number), cp); + master_map.insert(format!("p{}", config_number), cp); } } let json = serde_json::to_string_pretty(&master_map)?; diff --git a/tvm_tl_codegen/src/lib.rs b/tvm_tl_codegen/src/lib.rs index 0305460f9..b85fe6ae4 100644 --- a/tvm_tl_codegen/src/lib.rs +++ b/tvm_tl_codegen/src/lib.rs @@ -2072,7 +2072,7 @@ impl Constructors { fn as_enum_doc(&self) -> String { use std::fmt::Write; let mut ret = - format!("TL-derived from `{}`\n\n```text\n", &self.first_constructor().original_output); + format!("TL-derived from `{}`\n\n```text\n", self.first_constructor().original_output); for (e, cm) in self.0.iter().enumerate() { if e != 0 { ret.write_str("\n\n").unwrap(); diff --git a/tvm_types/src/bls.rs b/tvm_types/src/bls.rs index 279b2bcef..dc30174b5 100644 --- a/tvm_types/src/bls.rs +++ b/tvm_types/src/bls.rs @@ -200,7 +200,7 @@ pub fn aggregate_bls_signatures(sig_bytes_with_nodes_info_vec: &[&[u8]]) -> Resu for it in &bls_sigs_refs { nodes_info_refs.push(&it.nodes_info); let sig = convert_signature_bytes_to_signature(&it.sig_bytes)?; - println!("{:?}", &sig.to_bytes()); + println!("{:?}", sig.to_bytes()); // return this part to exclude zero sig // let res = sig.validate(true); // if res.is_err() { @@ -294,11 +294,11 @@ impl BlsKeyPair { println!("BLS key pair:"); println!("--------------------------------------------------"); println!("Secret key bytes:"); - println!("{:?}", &self.sk_bytes); - println!("Secret key len: {}", &self.sk_bytes.len()); + println!("{:?}", self.sk_bytes); + println!("Secret key len: {}", self.sk_bytes.len()); println!("Public key bytes:"); - println!("{:?}", &self.pk_bytes); - println!("Public key len: {}", &self.pk_bytes.len()); + println!("{:?}", self.pk_bytes); + println!("Public key len: {}", self.pk_bytes.len()); println!("--------------------------------------------------"); } @@ -404,7 +404,7 @@ impl NodesInfo { pub fn print(&self) { println!("--------------------------------------------------"); - println!("Total number of nodes: {}", &self.total_num_of_nodes); + println!("Total number of nodes: {}", self.total_num_of_nodes); println!("Indexes -- occurrences: "); for (index, number_of_occurrence) in &self.map { println!("{}: \"{}\"", index, number_of_occurrence); @@ -609,7 +609,7 @@ impl BlsSignature { println!("Aggregated BLS signature:"); println!("--------------------------------------------------"); println!("Signature bytes:"); - println!("{:?}", &self.sig_bytes); + println!("{:?}", self.sig_bytes); self.nodes_info.print(); println!("--------------------------------------------------"); }