From bd9be2e26c158d0ef8d1dcaefbd11d9b366bfc27 Mon Sep 17 00:00:00 2001 From: Mihai Calin Luca Date: Fri, 13 Sep 2024 18:52:19 +0200 Subject: [PATCH 1/4] impl for interactor --- .../scenario/src/facade/result_handlers.rs | 2 ++ .../facade/result_handlers/returns_tx_hash.rs | 24 +++++++++++++++++++ .../scenario/model/transaction/tx_response.rs | 2 ++ framework/snippets/src/network_response.rs | 6 +++++ 4 files changed, 34 insertions(+) create mode 100644 framework/scenario/src/facade/result_handlers/returns_tx_hash.rs diff --git a/framework/scenario/src/facade/result_handlers.rs b/framework/scenario/src/facade/result_handlers.rs index 33b5b1a495..88e90d0cd5 100644 --- a/framework/scenario/src/facade/result_handlers.rs +++ b/framework/scenario/src/facade/result_handlers.rs @@ -7,6 +7,7 @@ mod returns_message; mod returns_new_bech32_address; mod returns_new_token_identifier; mod returns_status; +mod returns_tx_hash; mod with_tx_raw_response; pub use expect_error::ExpectError; @@ -18,4 +19,5 @@ pub use returns_message::ReturnsMessage; pub use returns_new_bech32_address::ReturnsNewBech32Address; pub use returns_new_token_identifier::ReturnsNewTokenIdentifier; pub use returns_status::ReturnsStatus; +pub use returns_tx_hash::ReturnsTxHash; pub use with_tx_raw_response::WithRawTxResponse; diff --git a/framework/scenario/src/facade/result_handlers/returns_tx_hash.rs b/framework/scenario/src/facade/result_handlers/returns_tx_hash.rs new file mode 100644 index 0000000000..7494b41edc --- /dev/null +++ b/framework/scenario/src/facade/result_handlers/returns_tx_hash.rs @@ -0,0 +1,24 @@ +use multiversx_sc::types::RHListItemExec; + +use crate::{ + multiversx_sc::types::{RHListItem, TxEnv}, + scenario_model::TxResponse, +}; + +pub struct ReturnsTxHash; + +impl RHListItem for ReturnsTxHash +where + Env: TxEnv, +{ + type Returns = String; +} + +impl RHListItemExec for ReturnsTxHash +where + Env: TxEnv, +{ + fn item_process_result(self, raw_result: &TxResponse) -> Self::Returns { + raw_result.tx_hash.clone() + } +} diff --git a/framework/scenario/src/scenario/model/transaction/tx_response.rs b/framework/scenario/src/scenario/model/transaction/tx_response.rs index 8a7a5c4bf9..b230fd1878 100644 --- a/framework/scenario/src/scenario/model/transaction/tx_response.rs +++ b/framework/scenario/src/scenario/model/transaction/tx_response.rs @@ -20,6 +20,8 @@ pub struct TxResponse { pub gas: u64, /// The refund of the transaction. pub refund: u64, + /// The transaction hash + pub tx_hash: String, } impl TxResponse { diff --git a/framework/snippets/src/network_response.rs b/framework/snippets/src/network_response.rs index 0140dd839e..4684fdce3c 100644 --- a/framework/snippets/src/network_response.rs +++ b/framework/snippets/src/network_response.rs @@ -17,6 +17,7 @@ pub fn parse_tx_response(tx: TransactionOnNetwork) -> TxResponse { if !tx_error.is_success() { return TxResponse { tx_error, + tx_hash: process_tx_hash(&tx).to_string(), ..Default::default() }; } @@ -45,10 +46,15 @@ fn process_success(tx: &TransactionOnNetwork) -> TxResponse { new_deployed_address: process_new_deployed_address(tx), new_issued_token_identifier: process_new_issued_token_identifier(tx), logs: process_logs(tx), + tx_hash: process_tx_hash(tx).to_string(), ..Default::default() } } +fn process_tx_hash(tx: &TransactionOnNetwork) -> &str { + tx.hash.as_deref().unwrap_or("") +} + fn process_out(tx: &TransactionOnNetwork) -> Vec> { let out_scr = tx.smart_contract_results.iter().find(is_out_scr); From b72c23db19ba2c6985827b838ea5ad7fddaf8dce Mon Sep 17 00:00:00 2001 From: Mihai Calin Luca Date: Thu, 19 Sep 2024 09:58:15 +0200 Subject: [PATCH 2/4] tx hash in scenario --- .../facade/world_tx/scenario_tx_whitebox.rs | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/framework/scenario/src/facade/world_tx/scenario_tx_whitebox.rs b/framework/scenario/src/facade/world_tx/scenario_tx_whitebox.rs index 62842a6e25..e20538ce0e 100644 --- a/framework/scenario/src/facade/world_tx/scenario_tx_whitebox.rs +++ b/framework/scenario/src/facade/world_tx/scenario_tx_whitebox.rs @@ -1,3 +1,5 @@ +use core::str; + use crate::debug_executor::contract_instance_wrapped_execution; use crate::scenario::tx_to_step::TxToQueryStep; use crate::{ @@ -68,6 +70,15 @@ where }); let mut response = TxResponse::from_tx_result(tx_result); + if let Some(tx_hash) = &step_wrapper.env.data.tx_hash { + let tx_hash_bytes = tx_hash.as_bytes(); + response.tx_hash = str::from_utf8(tx_hash_bytes) + .expect("tx hash not utf8 valid") + .to_string(); + } else { + response.tx_hash = String::from(""); + } + response.new_deployed_address = Some(new_address); step_wrapper.step.save_response(response); step_wrapper.process_result() @@ -140,7 +151,16 @@ where }); }); - let response = TxResponse::from_tx_result(tx_result); + let mut response = TxResponse::from_tx_result(tx_result); + if let Some(tx_hash) = &step_wrapper.env.data.tx_hash { + let tx_hash_bytes = tx_hash.as_bytes(); + response.tx_hash = str::from_utf8(tx_hash_bytes) + .expect("tx hash not utf8 valid") + .to_string(); + } else { + response.tx_hash = String::from(""); + } + step_wrapper.step.save_response(response); step_wrapper.process_result() } From 69d09a5467bf4cf31bb242bdcf53a8ea3d8f90c0 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Fri, 20 Sep 2024 15:38:09 +0300 Subject: [PATCH 3/4] unified syntax - tx hash in blackbox/whitebox tests --- .../scenario-tester/tests/st_blackbox_test.rs | 42 +++++++++++++++++++ .../scenario-tester/tests/st_whitebox_test.rs | 33 +++++++++++++++ framework/base/src/types/interaction/tx.rs | 6 +-- .../facade/result_handlers/returns_tx_hash.rs | 5 ++- .../facade/world_tx/scenario_tx_whitebox.rs | 24 ++--------- .../src/scenario/model/step/sc_call_step.rs | 3 +- .../src/scenario/model/step/sc_deploy_step.rs | 7 ++-- .../scenario/model/transaction/tx_response.rs | 6 +-- framework/snippets/src/network_response.rs | 14 ++++--- 9 files changed, 102 insertions(+), 38 deletions(-) diff --git a/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs b/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs index cdcf610b25..d3f78692e8 100644 --- a/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs +++ b/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs @@ -244,3 +244,45 @@ fn set_state_test() { .balance(600) .esdt_balance(TOKEN_ID, 60); } + +#[test] +fn st_blackbox_tx_hash() { + let mut world = world(); + + world + .account(OWNER_ADDRESS) + .nonce(1) + .balance(100) + .account(OTHER_ADDRESS) + .nonce(2) + .balance(300) + .esdt_balance(TOKEN_ID, 500) + .commit(); + + let (new_address, tx_hash) = world + .tx() + .from(OWNER_ADDRESS) + .typed(scenario_tester_proxy::ScenarioTesterProxy) + .init(5u32) + .code(CODE_PATH) + .new_address(ST_ADDRESS) + .tx_hash([11u8; 32]) + .returns(ReturnsNewAddress) + .returns(ReturnsTxHash) + .run(); + + assert_eq!(new_address, ST_ADDRESS.to_address()); + assert_eq!(tx_hash.as_array(), &[11u8; 32]); + + let tx_hash = world + .tx() + .from(OWNER_ADDRESS) + .to(ST_ADDRESS) + .typed(scenario_tester_proxy::ScenarioTesterProxy) + .add(1u32) + .tx_hash([22u8; 32]) + .returns(ReturnsTxHash) + .run(); + + assert_eq!(tx_hash.as_array(), &[22u8; 32]); +} diff --git a/contracts/feature-tests/scenario-tester/tests/st_whitebox_test.rs b/contracts/feature-tests/scenario-tester/tests/st_whitebox_test.rs index 61dd6cdc2d..99e56d29f1 100644 --- a/contracts/feature-tests/scenario-tester/tests/st_whitebox_test.rs +++ b/contracts/feature-tests/scenario-tester/tests/st_whitebox_test.rs @@ -52,3 +52,36 @@ fn st_whitebox() { .check_account(SCENARIO_TESTER) .check_storage("str:sum", "8"); } + +#[test] +fn st_whitebox_tx_hash() { + let mut world = world(); + + world.account(OWNER).nonce(1); + + let (new_address, tx_hash) = world + .tx() + .from(OWNER) + .raw_deploy() + .code(ST_PATH_EXPR) + .new_address(SCENARIO_TESTER) + .tx_hash([11u8; 32]) + .returns(ReturnsNewBech32Address) + .returns(ReturnsTxHash) + .whitebox(scenario_tester::contract_obj, |sc| { + sc.init(BigUint::from(5u64)); + }); + + assert_eq!(new_address.to_address(), SCENARIO_TESTER.to_address()); + assert_eq!(tx_hash.as_array(), &[11u8; 32]); + + let tx_hash = world + .tx() + .from(OWNER) + .to(SCENARIO_TESTER) + .tx_hash([22u8; 32]) + .returns(ReturnsTxHash) + .whitebox(scenario_tester::contract_obj, |sc| sc.add(3u32.into())); + + assert_eq!(tx_hash.as_array(), &[22u8; 32]); +} diff --git a/framework/base/src/types/interaction/tx.rs b/framework/base/src/types/interaction/tx.rs index 905b9af8fc..b216ce0f28 100644 --- a/framework/base/src/types/interaction/tx.rs +++ b/framework/base/src/types/interaction/tx.rs @@ -908,11 +908,11 @@ where impl Tx where Env: TxEnvWithTxHash, - From: TxFromSpecified, + From: TxFrom, To: TxTo, - Payment: TxPaymentEgldOnly, + Payment: TxPayment, Gas: TxGas, - Data: TxDataFunctionCall, + Data: TxData, RH: TxResultHandler, { /// Sets the mock transaction hash to be used in a test. diff --git a/framework/scenario/src/facade/result_handlers/returns_tx_hash.rs b/framework/scenario/src/facade/result_handlers/returns_tx_hash.rs index 7494b41edc..fb30ea1ff3 100644 --- a/framework/scenario/src/facade/result_handlers/returns_tx_hash.rs +++ b/framework/scenario/src/facade/result_handlers/returns_tx_hash.rs @@ -1,3 +1,4 @@ +use multiversx_chain_vm::types::H256; use multiversx_sc::types::RHListItemExec; use crate::{ @@ -11,7 +12,7 @@ impl RHListItem for ReturnsTxHash where Env: TxEnv, { - type Returns = String; + type Returns = H256; } impl RHListItemExec for ReturnsTxHash @@ -19,6 +20,6 @@ where Env: TxEnv, { fn item_process_result(self, raw_result: &TxResponse) -> Self::Returns { - raw_result.tx_hash.clone() + raw_result.tx_hash.clone().expect("missing tx hash") } } diff --git a/framework/scenario/src/facade/world_tx/scenario_tx_whitebox.rs b/framework/scenario/src/facade/world_tx/scenario_tx_whitebox.rs index e20538ce0e..f8d03dc6da 100644 --- a/framework/scenario/src/facade/world_tx/scenario_tx_whitebox.rs +++ b/framework/scenario/src/facade/world_tx/scenario_tx_whitebox.rs @@ -1,5 +1,3 @@ -use core::str; - use crate::debug_executor::contract_instance_wrapped_execution; use crate::scenario::tx_to_step::TxToQueryStep; use crate::{ @@ -57,6 +55,7 @@ where let contract_obj = contract_obj_builder(); let mut step_wrapper = self.tx_to_step(); + step_wrapper.step.explicit_tx_hash = core::mem::take(&mut step_wrapper.env.data.tx_hash); let (new_address, tx_result) = step_wrapper .env .world @@ -70,15 +69,6 @@ where }); let mut response = TxResponse::from_tx_result(tx_result); - if let Some(tx_hash) = &step_wrapper.env.data.tx_hash { - let tx_hash_bytes = tx_hash.as_bytes(); - response.tx_hash = str::from_utf8(tx_hash_bytes) - .expect("tx hash not utf8 valid") - .to_string(); - } else { - response.tx_hash = String::from(""); - } - response.new_deployed_address = Some(new_address); step_wrapper.step.save_response(response); step_wrapper.process_result() @@ -133,6 +123,7 @@ where let contract_obj = contract_obj_builder(); let mut step_wrapper = self.tx_to_step(); + step_wrapper.step.explicit_tx_hash = core::mem::take(&mut step_wrapper.env.data.tx_hash); // no endpoint is called per se, but if it is empty, the VM thinks it is a simple transfer of value if step_wrapper.step.tx.function.is_empty() { @@ -151,16 +142,7 @@ where }); }); - let mut response = TxResponse::from_tx_result(tx_result); - if let Some(tx_hash) = &step_wrapper.env.data.tx_hash { - let tx_hash_bytes = tx_hash.as_bytes(); - response.tx_hash = str::from_utf8(tx_hash_bytes) - .expect("tx hash not utf8 valid") - .to_string(); - } else { - response.tx_hash = String::from(""); - } - + let response = TxResponse::from_tx_result(tx_result); step_wrapper.step.save_response(response); step_wrapper.process_result() } diff --git a/framework/scenario/src/scenario/model/step/sc_call_step.rs b/framework/scenario/src/scenario/model/step/sc_call_step.rs index 4a68bfa000..2a25fb2c2f 100644 --- a/framework/scenario/src/scenario/model/step/sc_call_step.rs +++ b/framework/scenario/src/scenario/model/step/sc_call_step.rs @@ -205,12 +205,13 @@ impl ScCallStep { .expect("SC call response not yet available") } - pub fn save_response(&mut self, tx_response: TxResponse) { + pub fn save_response(&mut self, mut tx_response: TxResponse) { if let Some(expect) = &mut self.expect { if expect.build_from_response { expect.update_from_response(&tx_response) } } + tx_response.tx_hash = self.explicit_tx_hash.as_ref().map(|vm_hash| vm_hash.as_array().into()); self.response = Some(tx_response); } } diff --git a/framework/scenario/src/scenario/model/step/sc_deploy_step.rs b/framework/scenario/src/scenario/model/step/sc_deploy_step.rs index 7e520e1a17..3b22522f69 100644 --- a/framework/scenario/src/scenario/model/step/sc_deploy_step.rs +++ b/framework/scenario/src/scenario/model/step/sc_deploy_step.rs @@ -135,13 +135,14 @@ impl ScDeployStep { .expect("SC deploy response not yet available") } - pub fn save_response(&mut self, response: TxResponse) { + pub fn save_response(&mut self, mut tx_response: TxResponse) { if let Some(expect) = &mut self.expect { if expect.build_from_response { - expect.update_from_response(&response) + expect.update_from_response(&tx_response) } } - self.response = Some(response); + tx_response.tx_hash = self.explicit_tx_hash.as_ref().map(|vm_hash| vm_hash.as_array().into()); + self.response = Some(tx_response); } } diff --git a/framework/scenario/src/scenario/model/transaction/tx_response.rs b/framework/scenario/src/scenario/model/transaction/tx_response.rs index b230fd1878..547b381338 100644 --- a/framework/scenario/src/scenario/model/transaction/tx_response.rs +++ b/framework/scenario/src/scenario/model/transaction/tx_response.rs @@ -1,4 +1,4 @@ -use multiversx_chain_vm::tx_mock::TxResult; +use multiversx_chain_vm::{tx_mock::TxResult, types::H256}; use multiversx_sc::types::Address; use super::{Log, TxExpect, TxResponseStatus}; @@ -20,8 +20,8 @@ pub struct TxResponse { pub gas: u64, /// The refund of the transaction. pub refund: u64, - /// The transaction hash - pub tx_hash: String, + /// The transaction hash, if available. + pub tx_hash: Option, } impl TxResponse { diff --git a/framework/snippets/src/network_response.rs b/framework/snippets/src/network_response.rs index 4684fdce3c..b5839e2e10 100644 --- a/framework/snippets/src/network_response.rs +++ b/framework/snippets/src/network_response.rs @@ -1,6 +1,6 @@ use multiversx_sc_scenario::{ imports::{Address, ESDTSystemSCAddress}, - multiversx_chain_vm::crypto_functions::keccak256, + multiversx_chain_vm::{crypto_functions::keccak256, types::H256}, scenario_model::{Log, TxResponse, TxResponseStatus}, }; use multiversx_sdk::{ @@ -17,7 +17,7 @@ pub fn parse_tx_response(tx: TransactionOnNetwork) -> TxResponse { if !tx_error.is_success() { return TxResponse { tx_error, - tx_hash: process_tx_hash(&tx).to_string(), + tx_hash: process_tx_hash(&tx), ..Default::default() }; } @@ -46,13 +46,17 @@ fn process_success(tx: &TransactionOnNetwork) -> TxResponse { new_deployed_address: process_new_deployed_address(tx), new_issued_token_identifier: process_new_issued_token_identifier(tx), logs: process_logs(tx), - tx_hash: process_tx_hash(tx).to_string(), + tx_hash: process_tx_hash(tx), ..Default::default() } } -fn process_tx_hash(tx: &TransactionOnNetwork) -> &str { - tx.hash.as_deref().unwrap_or("") +fn process_tx_hash(tx: &TransactionOnNetwork) -> Option { + tx.hash.as_ref().map(|encoded_hash| { + let decoded = hex::decode(encoded_hash).expect("error decoding tx hash from hex"); + assert_eq!(decoded.len(), 32); + H256::from_slice(&decoded) + }) } fn process_out(tx: &TransactionOnNetwork) -> Vec> { From b8853bc338e7e65b9f92eaa22dd9bcb348bb2e41 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Fri, 20 Sep 2024 15:55:56 +0300 Subject: [PATCH 4/4] unified syntax - tx hash refactor --- framework/base/src/types/interaction/tx_env.rs | 3 +++ .../src/facade/world_tx/scenario_exec_call.rs | 9 +++++---- .../src/facade/world_tx/scenario_exec_deploy.rs | 1 - .../src/facade/world_tx/scenario_tx_env.rs | 13 ++++++++++++- .../src/facade/world_tx/scenario_tx_whitebox.rs | 2 -- .../src/scenario/model/step/sc_call_step.rs | 5 ++++- .../src/scenario/model/step/sc_deploy_step.rs | 5 ++++- .../src/scenario/tx_to_step/tx_to_step_call.rs | 9 +++++---- .../src/scenario/tx_to_step/tx_to_step_deploy.rs | 8 +++++--- .../src/interactor_tx/interactor_exec_env.rs | 14 +++++++++++++- 10 files changed, 51 insertions(+), 18 deletions(-) diff --git a/framework/base/src/types/interaction/tx_env.rs b/framework/base/src/types/interaction/tx_env.rs index 37e18d7dec..188e304311 100644 --- a/framework/base/src/types/interaction/tx_env.rs +++ b/framework/base/src/types/interaction/tx_env.rs @@ -27,4 +27,7 @@ pub trait TxEnvMockDeployAddress: TxEnv { pub trait TxEnvWithTxHash: TxEnv { fn set_tx_hash(&mut self, tx_hash: H256); + + /// Retrieves current tx hash, while resetting it in self. + fn take_tx_hash(&mut self) -> Option; } diff --git a/framework/scenario/src/facade/world_tx/scenario_exec_call.rs b/framework/scenario/src/facade/world_tx/scenario_exec_call.rs index 8905c7d14d..ca09b9d318 100644 --- a/framework/scenario/src/facade/world_tx/scenario_exec_call.rs +++ b/framework/scenario/src/facade/world_tx/scenario_exec_call.rs @@ -85,7 +85,6 @@ where fn run(self) -> Self::Returns { let mut step_wrapper = self.tx_to_step(); - step_wrapper.step.explicit_tx_hash = core::mem::take(&mut step_wrapper.env.data.tx_hash); step_wrapper.env.world.sc_call(&mut step_wrapper.step); step_wrapper.process_result() } @@ -111,7 +110,6 @@ where fn run(self) -> Self::Returns { let mut step_wrapper = self.tx_to_step(); - step_wrapper.step.explicit_tx_hash = core::mem::take(&mut step_wrapper.env.data.tx_hash); step_wrapper.env.world.sc_call(&mut step_wrapper.step); step_wrapper.process_result() } @@ -119,8 +117,11 @@ where impl<'w> TxEnvWithTxHash for ScenarioEnvExec<'w> { fn set_tx_hash(&mut self, tx_hash: H256) { - assert!(self.data.tx_hash.is_none(), "tx hash set twice"); - self.data.tx_hash = Some(tx_hash); + self.data.set_tx_hash(tx_hash); + } + + fn take_tx_hash(&mut self) -> Option { + self.data.take_tx_hash() } } diff --git a/framework/scenario/src/facade/world_tx/scenario_exec_deploy.rs b/framework/scenario/src/facade/world_tx/scenario_exec_deploy.rs index 40fbbaa878..866d4f562f 100644 --- a/framework/scenario/src/facade/world_tx/scenario_exec_deploy.rs +++ b/framework/scenario/src/facade/world_tx/scenario_exec_deploy.rs @@ -35,7 +35,6 @@ where fn run(self) -> Self::Returns { let mut step_wrapper = self.tx_to_step(); - step_wrapper.step.explicit_tx_hash = core::mem::take(&mut step_wrapper.env.data.tx_hash); step_wrapper.env.world.sc_deploy(&mut step_wrapper.step); step_wrapper.process_result() } diff --git a/framework/scenario/src/facade/world_tx/scenario_tx_env.rs b/framework/scenario/src/facade/world_tx/scenario_tx_env.rs index 339ed9b38b..c3a2a1c204 100644 --- a/framework/scenario/src/facade/world_tx/scenario_tx_env.rs +++ b/framework/scenario/src/facade/world_tx/scenario_tx_env.rs @@ -1,5 +1,5 @@ use multiversx_chain_scenario_format::interpret_trait::InterpreterContext; -use multiversx_sc::types::{ManagedAddress, ManagedBuffer, TxEnv, H256}; +use multiversx_sc::types::{ManagedAddress, ManagedBuffer, TxEnv, TxEnvWithTxHash, H256}; use crate::{api::StaticApi, scenario_model::TxExpect, ScenarioWorld}; @@ -33,6 +33,17 @@ impl TxEnv for ScenarioTxEnvData { } } +impl TxEnvWithTxHash for ScenarioTxEnvData { + fn set_tx_hash(&mut self, tx_hash: H256) { + assert!(self.tx_hash.is_none(), "tx hash set twice"); + self.tx_hash = Some(tx_hash); + } + + fn take_tx_hash(&mut self) -> Option { + core::mem::take(&mut self.tx_hash) + } +} + impl ScenarioTxEnvData { pub fn interpreter_context(&self) -> InterpreterContext { self.interpreter_context.clone() diff --git a/framework/scenario/src/facade/world_tx/scenario_tx_whitebox.rs b/framework/scenario/src/facade/world_tx/scenario_tx_whitebox.rs index f8d03dc6da..62842a6e25 100644 --- a/framework/scenario/src/facade/world_tx/scenario_tx_whitebox.rs +++ b/framework/scenario/src/facade/world_tx/scenario_tx_whitebox.rs @@ -55,7 +55,6 @@ where let contract_obj = contract_obj_builder(); let mut step_wrapper = self.tx_to_step(); - step_wrapper.step.explicit_tx_hash = core::mem::take(&mut step_wrapper.env.data.tx_hash); let (new_address, tx_result) = step_wrapper .env .world @@ -123,7 +122,6 @@ where let contract_obj = contract_obj_builder(); let mut step_wrapper = self.tx_to_step(); - step_wrapper.step.explicit_tx_hash = core::mem::take(&mut step_wrapper.env.data.tx_hash); // no endpoint is called per se, but if it is empty, the VM thinks it is a simple transfer of value if step_wrapper.step.tx.function.is_empty() { diff --git a/framework/scenario/src/scenario/model/step/sc_call_step.rs b/framework/scenario/src/scenario/model/step/sc_call_step.rs index 2a25fb2c2f..8d8d71b0e8 100644 --- a/framework/scenario/src/scenario/model/step/sc_call_step.rs +++ b/framework/scenario/src/scenario/model/step/sc_call_step.rs @@ -211,7 +211,10 @@ impl ScCallStep { expect.update_from_response(&tx_response) } } - tx_response.tx_hash = self.explicit_tx_hash.as_ref().map(|vm_hash| vm_hash.as_array().into()); + tx_response.tx_hash = self + .explicit_tx_hash + .as_ref() + .map(|vm_hash| vm_hash.as_array().into()); self.response = Some(tx_response); } } diff --git a/framework/scenario/src/scenario/model/step/sc_deploy_step.rs b/framework/scenario/src/scenario/model/step/sc_deploy_step.rs index 3b22522f69..6090cfd492 100644 --- a/framework/scenario/src/scenario/model/step/sc_deploy_step.rs +++ b/framework/scenario/src/scenario/model/step/sc_deploy_step.rs @@ -141,7 +141,10 @@ impl ScDeployStep { expect.update_from_response(&tx_response) } } - tx_response.tx_hash = self.explicit_tx_hash.as_ref().map(|vm_hash| vm_hash.as_array().into()); + tx_response.tx_hash = self + .explicit_tx_hash + .as_ref() + .map(|vm_hash| vm_hash.as_array().into()); self.response = Some(tx_response); } } diff --git a/framework/scenario/src/scenario/tx_to_step/tx_to_step_call.rs b/framework/scenario/src/scenario/tx_to_step/tx_to_step_call.rs index 475326eac7..1d1eb2c9a2 100644 --- a/framework/scenario/src/scenario/tx_to_step/tx_to_step_call.rs +++ b/framework/scenario/src/scenario/tx_to_step/tx_to_step_call.rs @@ -1,6 +1,6 @@ use multiversx_sc::types::{ - Code, FunctionCall, NotPayable, RHListExec, Tx, TxEnv, TxFromSpecified, TxGas, TxPayment, - TxToSpecified, UpgradeCall, + Code, FunctionCall, NotPayable, RHListExec, Tx, TxEnv, TxEnvWithTxHash, TxFromSpecified, TxGas, + TxPayment, TxToSpecified, UpgradeCall, }; use crate::{ @@ -14,7 +14,7 @@ use super::{address_annotated, gas_annotated, StepWrapper, TxToStep}; impl TxToStep for Tx, RH> where - Env: TxEnv, + Env: TxEnvWithTxHash, From: TxFromSpecified, To: TxToSpecified, Payment: TxPayment, @@ -23,7 +23,7 @@ where { type Step = ScCallStep; - fn tx_to_step(self) -> StepWrapper { + fn tx_to_step(mut self) -> StepWrapper { let mut step = tx_to_sc_call_step( &self.env, self.from, @@ -32,6 +32,7 @@ where self.gas, self.data, ); + step.explicit_tx_hash = self.env.take_tx_hash(); step.expect = Some(self.result_handler.list_tx_expect()); StepWrapper { diff --git a/framework/scenario/src/scenario/tx_to_step/tx_to_step_deploy.rs b/framework/scenario/src/scenario/tx_to_step/tx_to_step_deploy.rs index 4e49be51b4..1c7532e27a 100644 --- a/framework/scenario/src/scenario/tx_to_step/tx_to_step_deploy.rs +++ b/framework/scenario/src/scenario/tx_to_step/tx_to_step_deploy.rs @@ -1,5 +1,6 @@ use multiversx_sc::types::{ - Code, DeployCall, RHListExec, Tx, TxCodeValue, TxEnv, TxFromSpecified, TxGas, TxPayment, + Code, DeployCall, RHListExec, Tx, TxCodeValue, TxEnv, TxEnvWithTxHash, TxFromSpecified, TxGas, + TxPayment, }; use crate::scenario_model::{ScDeployStep, TxExpect, TxResponse}; @@ -9,7 +10,7 @@ use super::{address_annotated, code_annotated, gas_annotated, StepWrapper, TxToS impl TxToStep for Tx>, RH> where - Env: TxEnv, + Env: TxEnvWithTxHash, From: TxFromSpecified, Payment: TxPayment, Gas: TxGas, @@ -18,9 +19,10 @@ where { type Step = ScDeployStep; - fn tx_to_step(self) -> StepWrapper { + fn tx_to_step(mut self) -> StepWrapper { let mut step = tx_to_sc_deploy_step(&self.env, self.from, self.payment, self.gas, self.data); + step.explicit_tx_hash = self.env.take_tx_hash(); step.expect = Some(self.result_handler.list_tx_expect()); StepWrapper { diff --git a/framework/snippets/src/interactor_tx/interactor_exec_env.rs b/framework/snippets/src/interactor_tx/interactor_exec_env.rs index 6473c50a91..436e65ac0c 100644 --- a/framework/snippets/src/interactor_tx/interactor_exec_env.rs +++ b/framework/snippets/src/interactor_tx/interactor_exec_env.rs @@ -1,6 +1,8 @@ use multiversx_sc_scenario::{ api::StaticApi, - multiversx_sc::types::{ManagedAddress, ManagedBuffer, Tx, TxBaseWithEnv, TxEnv}, + multiversx_sc::types::{ + ManagedAddress, ManagedBuffer, Tx, TxBaseWithEnv, TxEnv, TxEnvWithTxHash, H256, + }, scenario_model::TxExpect, ScenarioTxEnv, ScenarioTxEnvData, }; @@ -44,3 +46,13 @@ impl<'w> ScenarioTxEnv for InteractorEnvExec<'w> { &self.data } } + +impl<'w> TxEnvWithTxHash for InteractorEnvExec<'w> { + fn set_tx_hash(&mut self, tx_hash: H256) { + self.data.set_tx_hash(tx_hash); + } + + fn take_tx_hash(&mut self) -> Option { + self.data.take_tx_hash() + } +}