Skip to content

Commit

Permalink
Merge pull request #1772 from multiversx/returns-tx-hash
Browse files Browse the repository at this point in the history
returnsTxHash result handler
  • Loading branch information
andrei-marinica authored Sep 27, 2024
2 parents 390d18d + b8853bc commit c5db177
Show file tree
Hide file tree
Showing 16 changed files with 174 additions and 23 deletions.
42 changes: 42 additions & 0 deletions contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
}
33 changes: 33 additions & 0 deletions contracts/feature-tests/scenario-tester/tests/st_whitebox_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
}
6 changes: 3 additions & 3 deletions framework/base/src/types/interaction/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -908,11 +908,11 @@ where
impl<Env, From, To, Payment, Gas, Data, RH> Tx<Env, From, To, Payment, Gas, Data, RH>
where
Env: TxEnvWithTxHash,
From: TxFromSpecified<Env>,
From: TxFrom<Env>,
To: TxTo<Env>,
Payment: TxPaymentEgldOnly<Env>,
Payment: TxPayment<Env>,
Gas: TxGas<Env>,
Data: TxDataFunctionCall<Env>,
Data: TxData<Env>,
RH: TxResultHandler<Env>,
{
/// Sets the mock transaction hash to be used in a test.
Expand Down
3 changes: 3 additions & 0 deletions framework/base/src/types/interaction/tx_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<H256>;
}
2 changes: 2 additions & 0 deletions framework/scenario/src/facade/result_handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
25 changes: 25 additions & 0 deletions framework/scenario/src/facade/result_handlers/returns_tx_hash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use multiversx_chain_vm::types::H256;
use multiversx_sc::types::RHListItemExec;

use crate::{
multiversx_sc::types::{RHListItem, TxEnv},
scenario_model::TxResponse,
};

pub struct ReturnsTxHash;

impl<Env, Original> RHListItem<Env, Original> for ReturnsTxHash
where
Env: TxEnv,
{
type Returns = H256;
}

impl<Env, Original> RHListItemExec<TxResponse, Env, Original> for ReturnsTxHash
where
Env: TxEnv,
{
fn item_process_result(self, raw_result: &TxResponse) -> Self::Returns {
raw_result.tx_hash.clone().expect("missing tx hash")
}
}
9 changes: 5 additions & 4 deletions framework/scenario/src/facade/world_tx/scenario_exec_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand All @@ -111,16 +110,18 @@ 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()
}
}

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<H256> {
self.data.take_tx_hash()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand Down
13 changes: 12 additions & 1 deletion framework/scenario/src/facade/world_tx/scenario_tx_env.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand Down Expand Up @@ -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<H256> {
core::mem::take(&mut self.tx_hash)
}
}

impl ScenarioTxEnvData {
pub fn interpreter_context(&self) -> InterpreterContext {
self.interpreter_context.clone()
Expand Down
6 changes: 5 additions & 1 deletion framework/scenario/src/scenario/model/step/sc_call_step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,12 +205,16 @@ 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);
}
}
Expand Down
10 changes: 7 additions & 3 deletions framework/scenario/src/scenario/model/step/sc_deploy_step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,17 @@ 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);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -20,6 +20,8 @@ pub struct TxResponse {
pub gas: u64,
/// The refund of the transaction.
pub refund: u64,
/// The transaction hash, if available.
pub tx_hash: Option<H256>,
}

impl TxResponse {
Expand Down
9 changes: 5 additions & 4 deletions framework/scenario/src/scenario/tx_to_step/tx_to_step_call.rs
Original file line number Diff line number Diff line change
@@ -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::{
Expand All @@ -14,7 +14,7 @@ use super::{address_annotated, gas_annotated, StepWrapper, TxToStep};
impl<Env, From, To, Payment, Gas, RH> TxToStep<Env, RH>
for Tx<Env, From, To, Payment, Gas, FunctionCall<Env::Api>, RH>
where
Env: TxEnv<RHExpect = TxExpect>,
Env: TxEnvWithTxHash<RHExpect = TxExpect>,
From: TxFromSpecified<Env>,
To: TxToSpecified<Env>,
Payment: TxPayment<Env>,
Expand All @@ -23,7 +23,7 @@ where
{
type Step = ScCallStep;

fn tx_to_step(self) -> StepWrapper<Env, Self::Step, RH> {
fn tx_to_step(mut self) -> StepWrapper<Env, Self::Step, RH> {
let mut step = tx_to_sc_call_step(
&self.env,
self.from,
Expand All @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -9,7 +10,7 @@ use super::{address_annotated, code_annotated, gas_annotated, StepWrapper, TxToS
impl<Env, From, Payment, Gas, CodeValue, RH> TxToStep<Env, RH>
for Tx<Env, From, (), Payment, Gas, DeployCall<Env, Code<CodeValue>>, RH>
where
Env: TxEnv<RHExpect = TxExpect>,
Env: TxEnvWithTxHash<RHExpect = TxExpect>,
From: TxFromSpecified<Env>,
Payment: TxPayment<Env>,
Gas: TxGas<Env>,
Expand All @@ -18,9 +19,10 @@ where
{
type Step = ScDeployStep;

fn tx_to_step(self) -> StepWrapper<Env, Self::Step, RH> {
fn tx_to_step(mut self) -> StepWrapper<Env, Self::Step, RH> {
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 {
Expand Down
14 changes: 13 additions & 1 deletion framework/snippets/src/interactor_tx/interactor_exec_env.rs
Original file line number Diff line number Diff line change
@@ -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,
};
Expand Down Expand Up @@ -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<H256> {
self.data.take_tx_hash()
}
}
12 changes: 11 additions & 1 deletion framework/snippets/src/network_response.rs
Original file line number Diff line number Diff line change
@@ -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::{
Expand All @@ -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),
..Default::default()
};
}
Expand Down Expand Up @@ -45,10 +46,19 @@ 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),
..Default::default()
}
}

fn process_tx_hash(tx: &TransactionOnNetwork) -> Option<H256> {
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<Vec<u8>> {
let out_scr = tx.smart_contract_results.iter().find(is_out_scr);

Expand Down

0 comments on commit c5db177

Please sign in to comment.