From 04e59ef11fd4ab1991bab0dfb0484e094b1ebce8 Mon Sep 17 00:00:00 2001 From: Mihai Calin Luca Date: Wed, 20 Nov 2024 17:10:15 +0100 Subject: [PATCH] set state initial implementation for chain simulator, test in adder --- .../adder/interactor/src/basic_interactor.rs | 2 +- .../tests/basic_interactor_cs_test.rs | 28 ++++++ .../interactor/interactor_chain_simulator.rs | 13 ++- .../src/interactor/interactor_sender.rs | 19 +++- sdk/core/src/gateway.rs | 3 + .../gateway_chain_simulator_set_state.rs | 94 +++++++++++++++++++ 6 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 sdk/core/src/gateway/gateway_chain_simulator_set_state.rs diff --git a/contracts/examples/adder/interactor/src/basic_interactor.rs b/contracts/examples/adder/interactor/src/basic_interactor.rs index 63d71de11a..64dff9673e 100644 --- a/contracts/examples/adder/interactor/src/basic_interactor.rs +++ b/contracts/examples/adder/interactor/src/basic_interactor.rs @@ -57,7 +57,7 @@ impl AdderInteract { let adder_owner_address = interactor.register_wallet(test_wallets::heidi()).await; let wallet_address = interactor.register_wallet(test_wallets::ivan()).await; - interactor.generate_blocks_until_epoch(1).await.unwrap(); + let _ = interactor.generate_blocks(30u64).await; AdderInteract { interactor, diff --git a/contracts/examples/adder/interactor/tests/basic_interactor_cs_test.rs b/contracts/examples/adder/interactor/tests/basic_interactor_cs_test.rs index 1f07ee4c87..d6b98b73e5 100644 --- a/contracts/examples/adder/interactor/tests/basic_interactor_cs_test.rs +++ b/contracts/examples/adder/interactor/tests/basic_interactor_cs_test.rs @@ -1,4 +1,5 @@ use basic_interactor::{AdderInteract, Config}; +use multiversx_sc_snippets::{sdk::gateway::SetStateAccount, test_wallets}; #[tokio::test] #[cfg_attr(not(feature = "chain-simulator-tests"), ignore)] @@ -33,3 +34,30 @@ async fn simulator_upgrade_test() { let sum = basic_interact.get_sum().await; assert_eq!(sum, 7u32.into()); } + +#[tokio::test] +#[cfg_attr(not(feature = "chain-simulator-tests"), ignore)] +async fn set_state_cs_test() { + let account_address = test_wallets::mike(); + + let real_chain_interact = AdderInteract::new(Config::load_config()).await; + let simulator_interact = AdderInteract::new(Config::chain_simulator_config()).await; + + let account = real_chain_interact + .interactor + .get_account(&account_address.to_address()) + .await; + let keys = real_chain_interact + .interactor + .get_account_storage(&account_address.to_address()) + .await; + + let set_state_account = SetStateAccount::from(account).with_keys(keys); + let vec_state = vec![set_state_account]; + + let set_state_response = simulator_interact.interactor.set_state(vec_state).await; + + let _ = simulator_interact.interactor.generate_blocks(2u64).await; + + assert!(set_state_response.is_ok()); +} diff --git a/framework/snippets/src/interactor/interactor_chain_simulator.rs b/framework/snippets/src/interactor/interactor_chain_simulator.rs index 44943fe243..24dfa5390e 100644 --- a/framework/snippets/src/interactor/interactor_chain_simulator.rs +++ b/framework/snippets/src/interactor/interactor_chain_simulator.rs @@ -1,7 +1,8 @@ use anyhow::Error; use multiversx_sc_scenario::imports::Address; use multiversx_sdk::gateway::{ - ChainSimulatorGenerateBlocksRequest, ChainSimulatorSendFundsRequest, GatewayAsyncService, + ChainSimulatorGenerateBlocksRequest, ChainSimulatorSendFundsRequest, + ChainSimulatorSetStateRequest, GatewayAsyncService, SetStateAccount, }; use crate::InteractorBase; @@ -53,4 +54,14 @@ where )) .await } + + pub async fn set_state(&self, account: Vec) -> Result { + if !self.use_chain_simulator { + return Ok(String::from("no-simulator")); + } + + self.proxy + .request(ChainSimulatorSetStateRequest::for_account(account)) + .await + } } diff --git a/framework/snippets/src/interactor/interactor_sender.rs b/framework/snippets/src/interactor/interactor_sender.rs index e3877dec0a..4ba0efa162 100644 --- a/framework/snippets/src/interactor/interactor_sender.rs +++ b/framework/snippets/src/interactor/interactor_sender.rs @@ -1,7 +1,10 @@ +use std::collections::HashMap; + 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 multiversx_sdk::data::account::Account; +use multiversx_sdk::gateway::{GatewayAsyncService, GetAccountRequest, GetAccountStorageRequest}; use crate::InteractorBase; @@ -25,6 +28,20 @@ where account.nonce } + pub async fn get_account(&self, address: &Address) -> Account { + self.proxy + .request(GetAccountRequest::new(address)) + .await + .expect("failed to retrieve account") + } + + pub async fn get_account_storage(&self, address: &Address) -> HashMap { + self.proxy + .request(GetAccountStorageRequest::new(address)) + .await + .expect("failed to retrieve account") + } + pub(crate) async fn set_nonce_and_sign_tx( &mut self, sender_address: &Address, diff --git a/sdk/core/src/gateway.rs b/sdk/core/src/gateway.rs index 1512717a85..f3e08a4af2 100644 --- a/sdk/core/src/gateway.rs +++ b/sdk/core/src/gateway.rs @@ -5,6 +5,7 @@ mod gateway_account_storage; mod gateway_block; mod gateway_chain_simulator_blocks; mod gateway_chain_simulator_send_funds; +mod gateway_chain_simulator_set_state; mod gateway_network_config; mod gateway_network_economics; mod gateway_network_status; @@ -23,6 +24,7 @@ pub use gateway_account_storage::GetAccountStorageRequest; pub use gateway_block::GetHyperBlockRequest; pub use gateway_chain_simulator_blocks::ChainSimulatorGenerateBlocksRequest; pub use gateway_chain_simulator_send_funds::ChainSimulatorSendFundsRequest; +pub use gateway_chain_simulator_set_state::{ChainSimulatorSetStateRequest, SetStateAccount}; pub use gateway_network_config::NetworkConfigRequest; pub use gateway_network_economics::NetworkEconimicsRequest; pub use gateway_network_status::NetworkStatusRequest; @@ -61,6 +63,7 @@ const GENERATE_BLOCKS_UNTIL_TX_PROCESSED_ENDPOINT: &str = "simulator/generate-blocks-until-transaction-processed"; const GENERATE_BLOCKS_UNTIL_EPOCH_REACHED_ENDPOINT: &str = "simulator/generate-blocks-until-epoch-reached"; +const SET_STATE_ENDPOINT: &str = "simulator/set-state"; pub enum GatewayRequestType { Get, diff --git a/sdk/core/src/gateway/gateway_chain_simulator_set_state.rs b/sdk/core/src/gateway/gateway_chain_simulator_set_state.rs new file mode 100644 index 0000000000..33644e72a3 --- /dev/null +++ b/sdk/core/src/gateway/gateway_chain_simulator_set_state.rs @@ -0,0 +1,94 @@ +use anyhow::anyhow; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +use crate::data::account::Account; + +use super::{GatewayRequest, GatewayRequestType, SET_STATE_ENDPOINT}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SetStateResponse { + pub data: serde_json::Value, + pub error: String, + pub code: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct SetStateAccount { + pub address: String, + pub nonce: u64, + pub balance: String, + pub keys: HashMap, + pub code: String, + #[serde(default)] + pub code_hash: String, + #[serde(default)] + pub root_hash: String, + #[serde(default)] + pub code_metadata: String, + #[serde(default)] + pub owner_address: String, + #[serde(default)] + pub developer_reward: String, +} + +impl From for SetStateAccount { + fn from(value: Account) -> Self { + Self { + address: value.address.to_bech32_string().unwrap_or_default(), + nonce: value.nonce, + balance: value.balance.to_string(), + keys: HashMap::new(), + code: value.code, + code_hash: value.code_hash.unwrap_or_default(), + root_hash: value.root_hash.unwrap_or_default(), + code_metadata: value.code_metadata.unwrap_or_default(), + owner_address: value.owner_address.unwrap_or_default(), + developer_reward: value.developer_reward.unwrap_or_default(), + } + } +} + +impl SetStateAccount { + pub fn with_keys(mut self, keys: HashMap) -> Self { + self.keys = keys; + + self + } +} + +/// Sets state for a list of accounts using the chain simulator API. +pub struct ChainSimulatorSetStateRequest { + pub account: Vec, +} + +impl ChainSimulatorSetStateRequest { + pub fn for_account(account: Vec) -> Self { + Self { account } + } +} + +impl GatewayRequest for ChainSimulatorSetStateRequest { + type Payload = Vec; + type DecodedJson = SetStateResponse; + type Result = String; + + fn get_payload(&self) -> Option<&Self::Payload> { + Some(&self.account) + } + + fn request_type(&self) -> GatewayRequestType { + GatewayRequestType::Post + } + + fn get_endpoint(&self) -> String { + SET_STATE_ENDPOINT.to_owned() + } + + fn process_json(&self, decoded: Self::DecodedJson) -> anyhow::Result { + match decoded.code.as_str() { + "successful" => Ok(decoded.code), + _ => Err(anyhow!("{}", decoded.error)), + } + } +}