diff --git a/framework/snippets/src/account_tool.rs b/framework/snippets/src/account_tool.rs index 9b259296ef..eeaa16bdee 100644 --- a/framework/snippets/src/account_tool.rs +++ b/framework/snippets/src/account_tool.rs @@ -4,6 +4,11 @@ use multiversx_sc_scenario::{ imports::Bech32Address, scenario_model::{Account, BytesKey, BytesValue, Scenario, SetStateStep, Step}, }; +use multiversx_sdk::gateway::GatewayAsyncService; +use multiversx_sdk::gateway::{ + GetAccountEsdtRolesRequest, GetAccountEsdtTokensRequest, GetAccountRequest, + GetAccountStorageRequest, +}; use multiversx_sdk_http::GatewayHttpProxy; use std::collections::{BTreeMap, HashMap}; @@ -33,31 +38,34 @@ fn build_scenario(set_state: SetStateStep) -> Scenario { } } -pub async fn retrieve_account_as_scenario_set_state( - api: &GatewayHttpProxy, +pub async fn retrieve_account_as_scenario_set_state( + api: &GatewayProxy, use_chain_simulator: bool, address: &Bech32Address, ) -> SetStateStep { let sdk_address = SdkAddress::from_bech32_string(address.to_bech32_str()).unwrap(); - let sdk_account = api.get_account(&sdk_address).await.unwrap(); + let sdk_account = api + .request(GetAccountRequest::new(&sdk_address)) + .await + .unwrap(); let (account_esdt, account_esdt_roles, account_storage) = if use_chain_simulator { (HashMap::new(), HashMap::new(), HashMap::new()) } else { let account_esdt = api - .get_account_esdt_tokens(&sdk_address) + .request(GetAccountEsdtTokensRequest::new(&sdk_address)) .await .unwrap_or_else(|err| { panic!("failed to retrieve ESDT tokens for address {address}: {err}") }); let account_esdt_roles = api - .get_account_esdt_roles(&sdk_address) + .request(GetAccountEsdtRolesRequest::new(&sdk_address)) .await .unwrap_or_else(|err| { panic!("failed to retrieve ESDT roles for address {address}: {err}") }); let account_storage = api - .get_account_storage_keys(&sdk_address) + .request(GetAccountStorageRequest::new(&sdk_address)) .await .unwrap_or_else(|err| { panic!("failed to retrieve storage for address {address}: {err}") diff --git a/framework/snippets/src/interactor.rs b/framework/snippets/src/interactor.rs index 461e120ca0..07d773ce67 100644 --- a/framework/snippets/src/interactor.rs +++ b/framework/snippets/src/interactor.rs @@ -4,6 +4,7 @@ use multiversx_sc_scenario::{ mandos_system::{run_list::ScenarioRunnerList, run_trace::ScenarioTraceFile}, multiversx_sc::types::Address, }; +use multiversx_sdk::gateway::{GatewayAsyncService, NetworkConfigRequest}; use multiversx_sdk_http::GatewayHttpProxy; use std::{ collections::HashMap, @@ -15,8 +16,11 @@ use crate::{account_tool::retrieve_account_as_scenario_set_state, Sender}; pub const INTERACTOR_SCENARIO_TRACE_PATH: &str = "interactor_trace.scen.json"; -pub struct Interactor { - pub proxy: GatewayHttpProxy, +pub struct InteractorBase +where + GatewayProxy: GatewayAsyncService, +{ + pub proxy: GatewayProxy, pub use_chain_simulator: bool, pub network_config: NetworkConfig, pub sender_map: HashMap, @@ -28,10 +32,16 @@ pub struct Interactor { pub current_dir: PathBuf, } -impl Interactor { +pub type HttpInteractor = InteractorBase; + +/// Backwards compatibility. +pub type Interactor = HttpInteractor; + +impl HttpInteractor { + /// Not yet changed for backwards compatibility. pub async fn new(gateway_uri: &str, use_chain_simulator: bool) -> Self { - let proxy = GatewayHttpProxy::new(gateway_uri.to_string()); - let network_config = proxy.get_network_config().await.unwrap(); + let proxy: GatewayHttpProxy = GatewayHttpProxy::new(gateway_uri.to_string()); + let network_config = proxy.request(NetworkConfigRequest).await.unwrap(); Self { proxy, use_chain_simulator, @@ -43,7 +53,12 @@ impl Interactor { current_dir: PathBuf::default(), } } +} +impl InteractorBase +where + GatewayProxy: GatewayAsyncService, +{ pub async fn register_wallet(&mut self, wallet: Wallet) -> Address { let wallet_address = wallet.address(); diff --git a/framework/snippets/src/interactor_chain_simulator.rs b/framework/snippets/src/interactor_chain_simulator.rs index 89898b8e23..f37e7befb8 100644 --- a/framework/snippets/src/interactor_chain_simulator.rs +++ b/framework/snippets/src/interactor_chain_simulator.rs @@ -6,9 +6,12 @@ use multiversx_sdk::{ }, }; -use crate::Interactor; +use crate::InteractorBase; -impl Interactor { +impl InteractorBase +where + GatewayProxy: GatewayAsyncService, +{ pub async fn send_user_funds(&self, receiver: &SdkAddress) -> Result { if !self.use_chain_simulator { return Ok(String::from("no-simulator")); diff --git a/framework/snippets/src/interactor_scenario/interactor_sc_call.rs b/framework/snippets/src/interactor_scenario/interactor_sc_call.rs index cc3808dce1..655893681b 100644 --- a/framework/snippets/src/interactor_scenario/interactor_sc_call.rs +++ b/framework/snippets/src/interactor_scenario/interactor_sc_call.rs @@ -1,13 +1,20 @@ -use crate::{network_response, Interactor}; +use crate::{network_response, InteractorBase}; use log::info; use multiversx_sc_scenario::{ api::StaticApi, scenario::ScenarioRunner, scenario_model::{ScCallStep, SetStateStep, TxCall}, }; +use multiversx_sdk::{ + gateway::{GatewayAsyncService, SendTxRequest}, + retrieve_tx_on_network, +}; use multiversx_sdk_http::core::{data::transaction::Transaction, utils::base64_encode}; -impl Interactor { +impl InteractorBase +where + GatewayProxy: GatewayAsyncService, +{ pub async fn sc_call(&mut self, mut sc_call_step: S) where S: AsMut, @@ -17,7 +24,7 @@ impl Interactor { self.generate_blocks_until_tx_processed(&tx_hash) .await .unwrap(); - let tx = self.proxy.retrieve_tx_on_network(tx_hash.clone()).await; + let tx = retrieve_tx_on_network(&self.proxy, tx_hash.clone()).await; sc_call_step.save_response(network_response::parse_tx_response(tx)); @@ -40,7 +47,11 @@ impl Interactor { let mut transaction = self.tx_call_to_blockchain_tx(&sc_call_step.tx); self.set_nonce_and_sign_tx(sender_address, &mut transaction) .await; - let tx_hash = self.proxy.send_transaction(&transaction).await.unwrap(); + let tx_hash = self + .proxy + .request(SendTxRequest(&transaction)) + .await + .unwrap(); println!("sc call tx hash: {tx_hash}"); info!("sc call tx hash: {}", tx_hash); diff --git a/framework/snippets/src/interactor_scenario/interactor_sc_deploy.rs b/framework/snippets/src/interactor_scenario/interactor_sc_deploy.rs index 1228dd00d4..8cb04ea171 100644 --- a/framework/snippets/src/interactor_scenario/interactor_sc_deploy.rs +++ b/framework/snippets/src/interactor_scenario/interactor_sc_deploy.rs @@ -1,13 +1,20 @@ -use crate::{network_response, Interactor}; +use crate::{network_response, InteractorBase}; use log::info; use multiversx_sc_scenario::{ imports::{Address, Bech32Address}, mandos_system::ScenarioRunner, scenario_model::{ScDeployStep, SetStateStep}, }; +use multiversx_sdk::{ + gateway::{GatewayAsyncService, SendTxRequest}, + retrieve_tx_on_network, +}; use multiversx_sdk_http::core::{data::transaction::Transaction, utils::base64_encode}; -impl Interactor { +impl InteractorBase +where + GatewayProxy: GatewayAsyncService, +{ pub(crate) fn sc_deploy_to_blockchain_tx(&self, sc_deploy_step: &ScDeployStep) -> Transaction { Transaction { nonce: 0, @@ -33,7 +40,7 @@ impl Interactor { .await; let tx_hash = self .proxy - .send_transaction(&transaction) + .request(SendTxRequest(&transaction)) .await .expect("error sending tx (possible API failure)"); println!("sc deploy tx hash: {tx_hash}"); @@ -51,7 +58,7 @@ impl Interactor { self.generate_blocks_until_tx_processed(&tx_hash) .await .unwrap(); - let tx = self.proxy.retrieve_tx_on_network(tx_hash.clone()).await; + let tx = retrieve_tx_on_network(&self.proxy, tx_hash.clone()).await; let addr = sc_deploy_step.tx.from.clone(); let nonce = tx.nonce; diff --git a/framework/snippets/src/interactor_scenario/interactor_sc_extra.rs b/framework/snippets/src/interactor_scenario/interactor_sc_extra.rs index 44e5efa744..b08d1f284f 100644 --- a/framework/snippets/src/interactor_scenario/interactor_sc_extra.rs +++ b/framework/snippets/src/interactor_scenario/interactor_sc_extra.rs @@ -1,6 +1,6 @@ #![allow(deprecated)] -use crate::Interactor; +use crate::InteractorBase; use multiversx_sc_scenario::{ api::StaticApi, multiversx_sc::{ @@ -13,8 +13,12 @@ use multiversx_sc_scenario::{ TypedScDeploy, TypedScQuery, }, }; +use multiversx_sdk::gateway::GatewayAsyncService; -impl Interactor { +impl InteractorBase +where + GatewayProxy: GatewayAsyncService, +{ #[deprecated( since = "0.49.0", note = "Please use the unified transaction syntax instead." diff --git a/framework/snippets/src/interactor_scenario/interactor_transfer.rs b/framework/snippets/src/interactor_scenario/interactor_transfer.rs index 2bdef581ac..36a0a342db 100644 --- a/framework/snippets/src/interactor_scenario/interactor_transfer.rs +++ b/framework/snippets/src/interactor_scenario/interactor_transfer.rs @@ -1,8 +1,15 @@ -use crate::Interactor; +use crate::InteractorBase; use log::info; use multiversx_sc_scenario::{scenario::ScenarioRunner, scenario_model::TransferStep}; +use multiversx_sdk::{ + gateway::{GatewayAsyncService, SendTxRequest}, + retrieve_tx_on_network, +}; -impl Interactor { +impl InteractorBase +where + GatewayProxy: GatewayAsyncService, +{ pub async fn transfer(&mut self, transfer_step: TransferStep) -> String { self.pre_runners.run_transfer_step(&transfer_step); @@ -10,7 +17,11 @@ impl Interactor { let mut transaction = self.tx_call_to_blockchain_tx(&transfer_step.tx.to_tx_call()); self.set_nonce_and_sign_tx(sender_address, &mut transaction) .await; - let tx_hash = self.proxy.send_transaction(&transaction).await.unwrap(); + let tx_hash = self + .proxy + .request(SendTxRequest(&transaction)) + .await + .unwrap(); self.generate_blocks_until_tx_processed(&tx_hash) .await .unwrap(); @@ -18,7 +29,7 @@ impl Interactor { println!("transfer tx hash: {tx_hash}"); info!("transfer tx hash: {}", tx_hash); - self.proxy.retrieve_tx_on_network(tx_hash.clone()).await; + retrieve_tx_on_network(&self.proxy, tx_hash.clone()).await; self.post_runners.run_transfer_step(&transfer_step); diff --git a/framework/snippets/src/interactor_scenario/interactor_vm_query.rs b/framework/snippets/src/interactor_scenario/interactor_vm_query.rs index e11d753fbb..1b4383e1b3 100644 --- a/framework/snippets/src/interactor_scenario/interactor_vm_query.rs +++ b/framework/snippets/src/interactor_scenario/interactor_vm_query.rs @@ -1,6 +1,6 @@ #![allow(deprecated)] -use crate::Interactor; +use crate::InteractorBase; use log::info; use multiversx_sc_scenario::{ api::StaticApi, @@ -8,9 +8,13 @@ use multiversx_sc_scenario::{ multiversx_sc::{abi::TypeAbiFrom, codec::TopDecodeMulti, types::ContractCall}, scenario_model::{ScQueryStep, TxResponse}, }; +use multiversx_sdk::gateway::{GatewayAsyncService, VMQueryRequest}; use multiversx_sdk_http::core::{data::vm::VMQueryInput, utils::base64_decode}; -impl Interactor { +impl InteractorBase +where + GatewayProxy: GatewayAsyncService, +{ pub async fn sc_query(&mut self, mut step: S) -> &mut Self where S: AsMut, @@ -33,7 +37,7 @@ impl Interactor { }; let result = self .proxy - .execute_vmquery(&req) + .request(VMQueryRequest(&req)) .await .expect("error executing VM query"); diff --git a/framework/snippets/src/interactor_sender.rs b/framework/snippets/src/interactor_sender.rs index 4d99e1f483..8e81a7d82b 100644 --- a/framework/snippets/src/interactor_sender.rs +++ b/framework/snippets/src/interactor_sender.rs @@ -1,8 +1,9 @@ use crate::sdk::{data::transaction::Transaction, wallet::Wallet}; use log::debug; use multiversx_sc_scenario::multiversx_sc::types::Address; +use multiversx_sdk::gateway::{GatewayAsyncService, GetAccountRequest}; -use crate::Interactor; +use crate::InteractorBase; /// A user account that can sign transactions (a pem is present). pub struct Sender { @@ -11,11 +12,14 @@ pub struct Sender { pub current_nonce: Option, } -impl Interactor { +impl InteractorBase +where + GatewayProxy: GatewayAsyncService, +{ pub async fn recall_nonce(&self, address: &Address) -> u64 { let account = self .proxy - .get_account(&address.clone().into()) + .request(GetAccountRequest::new(&address.clone().into())) .await .expect("failed to retrieve account nonce"); account.nonce diff --git a/framework/snippets/src/interactor_tx/interactor_exec_call.rs b/framework/snippets/src/interactor_tx/interactor_exec_call.rs index 261ce44989..e7c593c774 100644 --- a/framework/snippets/src/interactor_tx/interactor_exec_call.rs +++ b/framework/snippets/src/interactor_tx/interactor_exec_call.rs @@ -11,8 +11,9 @@ use multiversx_sc_scenario::{ scenario_model::{ScCallStep, TxResponse}, ScenarioTxEnvData, }; +use multiversx_sdk::gateway::GatewayAsyncService; -use crate::Interactor; +use crate::InteractorBase; use super::{InteractorEnvExec, InteractorExecStep, InteractorPrepareAsync}; @@ -50,7 +51,10 @@ where } } -impl Interactor { +impl InteractorBase +where + GatewayProxy: GatewayAsyncService, +{ pub async fn chain_call(&mut self, f: F) -> &mut Self where From: TxFromSpecified, diff --git a/framework/snippets/src/interactor_tx/interactor_exec_deploy.rs b/framework/snippets/src/interactor_tx/interactor_exec_deploy.rs index 6070158258..a7872cdcec 100644 --- a/framework/snippets/src/interactor_tx/interactor_exec_deploy.rs +++ b/framework/snippets/src/interactor_tx/interactor_exec_deploy.rs @@ -10,8 +10,9 @@ use multiversx_sc_scenario::{ scenario_model::{ScDeployStep, TxResponse}, ScenarioTxEnvData, }; +use multiversx_sdk::gateway::GatewayAsyncService; -use crate::Interactor; +use crate::InteractorBase; use super::{InteractorEnvExec, InteractorExecStep, InteractorPrepareAsync}; @@ -57,7 +58,10 @@ where } } -impl Interactor { +impl InteractorBase +where + GatewayProxy: GatewayAsyncService, +{ pub async fn chain_deploy(&mut self, f: F) -> &mut Self where From: TxFromSpecified, diff --git a/framework/snippets/src/interactor_tx/interactor_exec_env.rs b/framework/snippets/src/interactor_tx/interactor_exec_env.rs index 436e65ac0c..e1148b8e82 100644 --- a/framework/snippets/src/interactor_tx/interactor_exec_env.rs +++ b/framework/snippets/src/interactor_tx/interactor_exec_env.rs @@ -6,10 +6,12 @@ use multiversx_sc_scenario::{ scenario_model::TxExpect, ScenarioTxEnv, ScenarioTxEnvData, }; +use multiversx_sdk::gateway::GatewayAsyncService; +use multiversx_sdk_http::GatewayHttpProxy; -use crate::Interactor; +use crate::InteractorBase; -impl Interactor { +impl InteractorBase { pub fn tx(&mut self) -> TxBaseWithEnv> { let data = self.new_env_data(); let env = InteractorEnvExec { world: self, data }; @@ -19,7 +21,7 @@ impl Interactor { /// Environment for executing transactions. pub struct InteractorEnvExec<'w> { - pub world: &'w mut Interactor, + pub world: &'w mut InteractorBase, pub data: ScenarioTxEnvData, } diff --git a/framework/snippets/src/interactor_tx/interactor_exec_upgrade.rs b/framework/snippets/src/interactor_tx/interactor_exec_upgrade.rs index af68999830..0f4bb6882e 100644 --- a/framework/snippets/src/interactor_tx/interactor_exec_upgrade.rs +++ b/framework/snippets/src/interactor_tx/interactor_exec_upgrade.rs @@ -12,7 +12,7 @@ use multiversx_sc_scenario::{ ScenarioTxEnvData, }; -use crate::Interactor; +use crate::InteractorBase; use super::{InteractorEnvExec, InteractorExecStep, InteractorPrepareAsync}; diff --git a/framework/snippets/src/interactor_tx/interactor_prepare_async.rs b/framework/snippets/src/interactor_tx/interactor_prepare_async.rs index 073641f811..62131b78a2 100644 --- a/framework/snippets/src/interactor_tx/interactor_prepare_async.rs +++ b/framework/snippets/src/interactor_tx/interactor_prepare_async.rs @@ -1,8 +1,12 @@ use multiversx_sc_scenario::{imports::InterpreterContext, ScenarioTxEnvData}; +use multiversx_sdk::gateway::GatewayAsyncService; -use crate::Interactor; +use crate::InteractorBase; -impl Interactor { +impl InteractorBase +where + GatewayProxy: GatewayAsyncService, +{ pub(crate) fn new_env_data(&self) -> ScenarioTxEnvData { ScenarioTxEnvData { interpreter_context: InterpreterContext::new().with_dir(self.current_dir.clone()), diff --git a/framework/snippets/src/interactor_tx/interactor_query_call.rs b/framework/snippets/src/interactor_tx/interactor_query_call.rs index 5e35b5409b..df84ad0acc 100644 --- a/framework/snippets/src/interactor_tx/interactor_query_call.rs +++ b/framework/snippets/src/interactor_tx/interactor_query_call.rs @@ -8,8 +8,9 @@ use multiversx_sc_scenario::{ scenario_model::TxResponse, ScenarioTxEnvData, }; +use multiversx_sdk::gateway::GatewayAsyncService; -use crate::Interactor; +use crate::InteractorBase; use super::{InteractorEnvQuery, InteractorPrepareAsync, InteractorQueryStep}; @@ -45,7 +46,10 @@ where } } -impl Interactor { +impl InteractorBase +where + GatewayProxy: GatewayAsyncService, +{ pub async fn chain_query(&mut self, f: F) -> &mut Self where To: TxToSpecified, diff --git a/framework/snippets/src/interactor_tx/interactor_query_env.rs b/framework/snippets/src/interactor_tx/interactor_query_env.rs index 71dcd2f3b4..42c9bb5f8f 100644 --- a/framework/snippets/src/interactor_tx/interactor_query_env.rs +++ b/framework/snippets/src/interactor_tx/interactor_query_env.rs @@ -4,10 +4,12 @@ use multiversx_sc_scenario::{ scenario_model::TxExpect, ScenarioTxEnv, ScenarioTxEnvData, }; +use multiversx_sdk::gateway::GatewayAsyncService; +use multiversx_sdk_http::GatewayHttpProxy; -use crate::Interactor; +use crate::InteractorBase; -impl Interactor { +impl InteractorBase { pub fn query(&mut self) -> TxBaseWithEnv> { let data = self.new_env_data(); let env = InteractorEnvQuery { world: self, data }; @@ -16,7 +18,7 @@ impl Interactor { } pub struct InteractorEnvQuery<'w> { - pub world: &'w mut Interactor, + pub world: &'w mut InteractorBase, pub data: ScenarioTxEnvData, } diff --git a/framework/snippets/src/multi/homogenous_tx_buffer.rs b/framework/snippets/src/multi/homogenous_tx_buffer.rs index 66f5dec79f..a4e4e75c92 100644 --- a/framework/snippets/src/multi/homogenous_tx_buffer.rs +++ b/framework/snippets/src/multi/homogenous_tx_buffer.rs @@ -7,15 +7,16 @@ use multiversx_sc_scenario::{ scenario_model::TxResponse, ScenarioTxEnvData, }; +use multiversx_sdk_http::GatewayHttpProxy; -use crate::{Interactor, InteractorEnvExec, InteractorStep, StepBuffer}; +use crate::{InteractorBase, InteractorEnvExec, InteractorStep, StepBuffer}; pub struct HomogenousTxBuffer<'w, Step, RH> { env: InteractorEnvExec<'w>, steps: Vec>, } -impl Interactor { +impl InteractorBase { /// Creates a buffer that can hold multiple transactions, and then execute them all at once. /// /// This buffer holds transactions of the same type (call/deploy) and with identical result handler types. diff --git a/framework/snippets/src/multi/interactor_multi_sc_exec.rs b/framework/snippets/src/multi/interactor_multi_sc_exec.rs index 255224f86f..658896d8f0 100644 --- a/framework/snippets/src/multi/interactor_multi_sc_exec.rs +++ b/framework/snippets/src/multi/interactor_multi_sc_exec.rs @@ -1,8 +1,10 @@ +use multiversx_sdk_http::GatewayHttpProxy; + use super::interactor_multi_sc_process::{update_nonces_and_sign_tx, SenderSet, Txs}; use crate::sdk::data::transaction::Transaction; -use crate::{network_response, Interactor, InteractorStep, StepBuffer}; +use crate::{network_response, InteractorBase, InteractorStep, StepBuffer}; -impl Interactor { +impl InteractorBase { pub async fn multi_sc_exec(&mut self, mut buffer: StepBuffer<'_>) { for step in buffer.refs.iter_mut() { step.run_step(&mut self.pre_runners); diff --git a/framework/snippets/src/multi/interactor_multi_sc_process.rs b/framework/snippets/src/multi/interactor_multi_sc_process.rs index de5a138ce2..a71369a958 100644 --- a/framework/snippets/src/multi/interactor_multi_sc_process.rs +++ b/framework/snippets/src/multi/interactor_multi_sc_process.rs @@ -1,12 +1,17 @@ use crate::sdk::data::transaction::{Transaction, TransactionOnNetwork}; -use crate::{multiversx_sc::types::Address, Interactor, Sender}; +use crate::{multiversx_sc::types::Address, InteractorBase, Sender}; use futures::future::join_all; +use multiversx_sdk::gateway::{GatewayAsyncService, SendTxRequest}; +use multiversx_sdk::retrieve_tx_on_network; use std::collections::HashSet; pub(crate) type Txs = Vec; pub(crate) type SenderSet = HashSet
; -impl Interactor { +impl InteractorBase +where + GatewayProxy: GatewayAsyncService, +{ pub(crate) async fn recall_senders_nonce(&mut self, senders: HashSet
) { for sender_address in &senders { let nonce = self.recall_nonce(sender_address).await; @@ -26,12 +31,12 @@ impl Interactor { for tx in &txs { let tx_hash = self .proxy - .send_transaction(tx) + .request(SendTxRequest(tx)) .await .expect("failed to send transaction"); println!("process tx hash: {tx_hash} with nonce: {}", tx.nonce); - futures.push(self.proxy.retrieve_tx_on_network(tx_hash.clone())); + futures.push(retrieve_tx_on_network(&self.proxy, tx_hash.clone())); } self.generate_blocks(4).await.unwrap(); diff --git a/framework/snippets/src/multi/interactor_step.rs b/framework/snippets/src/multi/interactor_step.rs index c0d38dec8c..4d27b59496 100644 --- a/framework/snippets/src/multi/interactor_step.rs +++ b/framework/snippets/src/multi/interactor_step.rs @@ -3,12 +3,13 @@ use multiversx_sc_scenario::{ mandos_system::ScenarioRunner, scenario_model::{AddressValue, ScCallStep, ScDeployStep, TxResponse}, }; +use multiversx_sdk_http::GatewayHttpProxy; -use crate::Interactor; +use crate::InteractorBase; /// Describes a scenario step that can be executed in an interactor. pub trait InteractorStep { - fn to_transaction(&self, interactor: &Interactor) -> Transaction; + fn to_transaction(&self, interactor: &InteractorBase) -> Transaction; fn sender_address(&self) -> &AddressValue; @@ -18,7 +19,7 @@ pub trait InteractorStep { } impl InteractorStep for ScCallStep { - fn to_transaction(&self, interactor: &Interactor) -> Transaction { + fn to_transaction(&self, interactor: &InteractorBase) -> Transaction { interactor.tx_call_to_blockchain_tx(&self.tx) } @@ -37,7 +38,7 @@ impl InteractorStep for ScCallStep { } impl InteractorStep for ScDeployStep { - fn to_transaction(&self, interactor: &Interactor) -> Transaction { + fn to_transaction(&self, interactor: &InteractorBase) -> Transaction { interactor.sc_deploy_to_blockchain_tx(self) } diff --git a/sdk/core/src/gateway.rs b/sdk/core/src/gateway.rs index 91292a361b..b158a0ef2b 100644 --- a/sdk/core/src/gateway.rs +++ b/sdk/core/src/gateway.rs @@ -87,10 +87,19 @@ pub trait GatewayRequest: Send { } pub trait GatewayAsyncService: Send { + /// Keeps track of elapsed time. + type Instant; + fn request( &self, request: G, ) -> impl std::future::Future> + Send where G: GatewayRequest; + + fn sleep(&self, millis: u64) -> impl std::future::Future + Send; + + fn now(&self) -> Self::Instant; + + fn elapsed_seconds(&self, instant: &Self::Instant) -> f32; } diff --git a/sdk/core/src/lib.rs b/sdk/core/src/lib.rs index 2713b112e1..5e984580fd 100644 --- a/sdk/core/src/lib.rs +++ b/sdk/core/src/lib.rs @@ -1,6 +1,9 @@ pub mod crypto; pub mod data; pub mod gateway; +mod retrieve_tx_on_network; pub mod test_wallets; pub mod utils; pub mod wallet; + +pub use retrieve_tx_on_network::retrieve_tx_on_network; diff --git a/sdk/core/src/retrieve_tx_on_network.rs b/sdk/core/src/retrieve_tx_on_network.rs new file mode 100644 index 0000000000..c68a649d9c --- /dev/null +++ b/sdk/core/src/retrieve_tx_on_network.rs @@ -0,0 +1,106 @@ +use crate::{ + data::transaction::TransactionOnNetwork, + gateway::{GetTxInfo, GetTxProcessStatus}, +}; +use log::info; + +use crate::gateway::GatewayAsyncService; + +const INITIAL_BACKOFF_DELAY: u64 = 1400; +const MAX_RETRIES: usize = 8; +const MAX_BACKOFF_DELAY: u64 = 6000; + +/// Retrieves a transaction from the network. +pub async fn retrieve_tx_on_network( + proxy: &GatewayProxy, + tx_hash: String, +) -> TransactionOnNetwork { + let mut retries = 0; + let mut backoff_delay = INITIAL_BACKOFF_DELAY; + let start_time = proxy.now(); + + loop { + match proxy.request(GetTxProcessStatus::new(&tx_hash)).await { + Ok((status, reason)) => { + // checks if transaction status is final + match status.as_str() { + "success" => { + // retrieve transaction info with results + let transaction_info_with_results = proxy + .request(GetTxInfo::new(&tx_hash).with_results()) + .await + .unwrap(); + + info!( + "Transaction retrieved successfully, with status {}: {:#?}", + status, transaction_info_with_results + ); + return transaction_info_with_results; + }, + "fail" => { + // status failed and no reason means invalid transaction + if reason.is_empty() { + info!("Transaction failed. Invalid transaction: {tx_hash}"); + panic!("Transaction failed. Invalid transaction: {tx_hash}"); + } + + let result = parse_reason(&reason); + + match result { + Ok((code, err)) => { + info!("Transaction failed. Code: {code}, message: {err}"); + panic!("Transaction failed. Code: {code}, message: {err}") + }, + Err(err) => { + info!("Reason parsing error for failed transaction: {err}"); + panic!("Reason parsing error for failed transaction: {err}") + }, + } + }, + _ => { + continue; + }, + } + }, + Err(err) => { + retries += 1; + if retries >= MAX_RETRIES { + info!("Transaction failed, max retries exceeded: {}", err); + println!("Transaction failed, max retries exceeded: {}", err); + break; + } + + let backoff_time = backoff_delay.min(MAX_BACKOFF_DELAY); + proxy.sleep(backoff_time).await; + backoff_delay *= 2; // exponential backoff + }, + } + } + + // retries have been exhausted + println!( + "Fetching transaction failed and retries exhausted, returning default transaction. Total elapsed time: {:?}s", + proxy.elapsed_seconds(&start_time) + ); + TransactionOnNetwork::default() +} + +pub fn parse_reason(reason: &str) -> Result<(u64, String), String> { + let parts: Vec<&str> = reason.split('@').collect(); + + if parts.len() < 2 { + return Err("Invalid reason format".to_string()); + } + + let error_code_hex = parts[1]; + let error_message_hex = parts[2]; + + let error_code = + u64::from_str_radix(error_code_hex, 16).expect("Failed to decode error code as u64"); + + let error_message = + String::from_utf8(hex::decode(error_message_hex).expect("Failed to decode error message")) + .expect("Failed to decode error message as UTF-8"); + + Ok((error_code, error_message)) +} diff --git a/sdk/http/src/gateway_http_proxy.rs b/sdk/http/src/gateway_http_proxy.rs index 61b6990b8e..1417db3db5 100644 --- a/sdk/http/src/gateway_http_proxy.rs +++ b/sdk/http/src/gateway_http_proxy.rs @@ -3,7 +3,8 @@ mod http_block; mod http_chain_simulator; mod http_network; mod http_tx; -mod http_tx_retrieve; + +use std::time::Duration; use multiversx_sdk::gateway::{GatewayAsyncService, GatewayRequest}; @@ -54,6 +55,8 @@ impl GatewayHttpProxy { } impl GatewayAsyncService for GatewayHttpProxy { + type Instant = std::time::Instant; + fn request( &self, request: G, @@ -63,4 +66,16 @@ impl GatewayAsyncService for GatewayHttpProxy { { self.http_request(request) } + + fn sleep(&self, millis: u64) -> impl std::future::Future + Send { + tokio::time::sleep(Duration::from_millis(millis)) + } + + fn now(&self) -> Self::Instant { + std::time::Instant::now() + } + + fn elapsed_seconds(&self, instant: &Self::Instant) -> f32 { + instant.elapsed().as_secs_f32() + } } diff --git a/sdk/http/src/gateway_http_proxy/http_tx_retrieve.rs b/sdk/http/src/gateway_http_proxy/http_tx_retrieve.rs deleted file mode 100644 index e39b87621b..0000000000 --- a/sdk/http/src/gateway_http_proxy/http_tx_retrieve.rs +++ /dev/null @@ -1,104 +0,0 @@ -use log::info; -use multiversx_sdk::data::transaction::TransactionOnNetwork; -use std::time::{Duration, Instant}; - -use super::GatewayHttpProxy; - -const INITIAL_BACKOFF_DELAY: f32 = 1.4; -const MAX_RETRIES: usize = 8; -const MAX_BACKOFF_DELAY: Duration = Duration::from_secs(6); - -impl GatewayHttpProxy { - /// Retrieves a transaction from the network. - pub async fn retrieve_tx_on_network(&self, tx_hash: String) -> TransactionOnNetwork { - let mut retries = 0; - let mut backoff_delay = Duration::from_secs_f32(INITIAL_BACKOFF_DELAY); - let start_time = Instant::now(); - - loop { - match self.get_transaction_process_status(&tx_hash).await { - Ok((status, reason)) => { - // checks if transaction status is final - match status.as_str() { - "success" => { - // retrieve transaction info with results - let transaction_info_with_results = self - .get_transaction_info_with_results(&tx_hash) - .await - .unwrap(); - - info!( - "Transaction retrieved successfully, with status {}: {:#?}", - status, transaction_info_with_results - ); - return transaction_info_with_results; - }, - "fail" => { - // status failed and no reason means invalid transaction - if reason.is_empty() { - info!("Transaction failed. Invalid transaction: {tx_hash}"); - panic!("Transaction failed. Invalid transaction: {tx_hash}"); - } - - let result = parse_reason(&reason); - - match result { - Ok((code, err)) => { - info!("Transaction failed. Code: {code}, message: {err}"); - panic!("Transaction failed. Code: {code}, message: {err}") - }, - Err(err) => { - info!("Reason parsing error for failed transaction: {err}"); - panic!("Reason parsing error for failed transaction: {err}") - }, - } - }, - _ => { - continue; - }, - } - }, - Err(err) => { - retries += 1; - if retries >= MAX_RETRIES { - info!("Transaction failed, max retries exceeded: {}", err); - println!("Transaction failed, max retries exceeded: {}", err); - break; - } - - let backoff_time = backoff_delay.min(MAX_BACKOFF_DELAY); - tokio::time::sleep(backoff_time).await; - backoff_delay *= 2; // exponential backoff - }, - } - } - - // retries have been exhausted - let elapsed_time = start_time.elapsed(); - println!( - "Fetching transaction failed and retries exhausted, returning default transaction. Total elapsed time: {:?}", - elapsed_time - ); - TransactionOnNetwork::default() - } -} - -pub fn parse_reason(reason: &str) -> Result<(u64, String), String> { - let parts: Vec<&str> = reason.split('@').collect(); - - if parts.len() < 2 { - return Err("Invalid reason format".to_string()); - } - - let error_code_hex = parts[1]; - let error_message_hex = parts[2]; - - let error_code = - u64::from_str_radix(error_code_hex, 16).expect("Failed to decode error code as u64"); - - let error_message = - String::from_utf8(hex::decode(error_message_hex).expect("Failed to decode error message")) - .expect("Failed to decode error message as UTF-8"); - - Ok((error_code, error_message)) -}