Skip to content

Commit

Permalink
impl write to/ read from state file in interactor and new set state f…
Browse files Browse the repository at this point in the history
…unction
  • Loading branch information
mihaicalinluca committed Nov 26, 2024
1 parent 445d7bc commit 3f400e2
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 17 deletions.
82 changes: 82 additions & 0 deletions contracts/examples/adder/interactor/set_state.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
[
{
"address": "erd1uv40ahysflse896x4ktnh6ecx43u7cmy9wnxnvcyp7deg299a4sq6vaywa",
"nonce": 5947,
"balance": "491982310359999986",
"keys": {
"454c524f4e446573647450544d2d35333666616201": "08021202000122ef0108011212546573742d5061696e742d486172766573741a20e32afedc904fe1939746ad973beb383563cf63642ba669b3040f9b9428a5ed6020c4132a2e516d57564239575362674b52655a64615a434344766b454b70705a6b4d696d397563736e7857565041414c6a4374324368747470733a2f2f697066732e696f2f697066732f516d57564239575362674b52655a64615a434344766b454b70705a6b4d696d397563736e7857565041414c6a43743a3d746167733a3b6d657461646174613a516d52635039346b5872357a5a6a52477669376d4a36756e374c7078556859565234523452706963787a67596b74",
"454c524f4e44657364745453542d643964336136": "1209004563918244f40000",
"454c524f4e44657364745745474c442d613238633539": "120900389351ce08f09e12",
"454c524f4e44657364745453542d633636666535": "1209004563918244f40000",
"454c524f4e44657364745453542d623130616461": "1209004563918244f40000",
"454c524f4e4465736474475245454e2d306531363163": "120b00152d02c7e14af67fffdc",
"454c524f4e44657364745453542d656338383735": "12020064",
"454c524f4e44657364744c5453542d376266336431": "1209000de0b6b3a763fc19",
"454c524f4e44657364745453542d343265356138": "1209004563918244f40000",
"454c524f4e44726f6c656573647450544d2d353336666162": "0a1145534454526f6c654e46544372656174650a0f45534454526f6c654e46544275726e",
"454c524f4e44657364745453542d393836646663": "12020064",
"454c524f4e44657364745453542d323833633361": "12020064",
"454c524f4e4465736474424358535542542d33393264366172": "080112020001",
"454c524f4e44657364744c5453542d346638343965": "1209000de0b6b3a763fc19",
"454c524f4e44657364745453542d386564363538": "1209004563918244f40000",
"454c524f4e44657364745453542d343562383235": "12020064",
"454c524f4e446e6f6e636550544d2d353336666162": "01",
"454c524f4e44657364745453542d363835303064": "1209004563918244f40000",
"454c524f4e44657364745453542d336339363762": "12020064",
"454c524f4e446573647455544b2d313464353764": "120b0001e6ce88d5ebbfd00000",
"454c524f4e44657364745453542d363434633935": "12020064",
"454c524f4e44657364745453542d306632306637": "12020064",
"454c524f4e44657364745453542d333331386638": "1209004563918244f40000",
"454c524f4e44657364745453542d353538616434": "12020064",
"454c524f4e44657364745453542d363437383930": "1209004563918244f40000",
"454c524f4e44657364745453542d633933336139": "1209004563918244f40000",
"454c524f4e44657364745453542d393864633566": "1209004563918244f40000",
"454c524f4e44657364745453542d303637373232": "1209004563918244f40000",
"454c524f4e44657364745453542d346634303238": "12020064",
"454c524f4e44657364745453542d643862306438": "12020064",
"454c524f4e44657364745453542d346230653865": "1209004563918244f40000",
"454c524f4e44657364745453542d343138613232": "1209004563918244f40000",
"454c524f4e44657364745453542d396230323030": "1209004563918244f40000",
"454c524f4e44657364745453542d373639313337": "1209004563918244f40000",
"454c524f4e44657364745453542d303362373664": "12020064",
"454c524f4e44657364745453542d613562663131": "12020064",
"454c524f4e44657364745453542d353966316165": "1209004563918244f40000",
"454c524f4e44657364745453542d623136363735": "1209004563918244f40000",
"454c524f4e44657364745453542d333639646531": "1209004563918244f40000",
"454c524f4e44657364745453542d623830663863": "1209004563918244f40000",
"454c524f4e44657364745453542d633565303835": "1209004563918244f40000"
},
"code": "",
"code_hash": "",
"root_hash": "2zSeJjLqgozEQmmgDU8L0/GidcKzJOlJgwoaTUqvDFg=",
"code_metadata": "",
"owner_address": "",
"developer_reward": "0"
},
{
"address": "erd13x29rvmp4qlgn4emgztd8jgvyzdj0p6vn37tqxas3v9mfhq4dy7shalqrx",
"nonce": 1417,
"balance": "1753855617144056",
"keys": {
"454c524f4e446573647445564e544e4f544946592d393634383835": "120b00152d02c7e14af6800000",
"454c524f4e4465736474494e5445524e532d63393332356601": "0801120b0013097d1fb962e12fff47",
"454c524f4e44657364744e455453432d623635306261": "120b00d137965aa7a731800000",
"454c524f4e446e6f6e6365494e5445524e532d633933323566": "01",
"454c524f4e44657364745745474c442d613238633539": "120800010593b233281b",
"454c524f4e446e6f6e63654d4554414e46542d643062623339": "01",
"454c524f4e44726f6c6565736474494e5445524e532d633933323566": "0a1145534454526f6c654e46544372656174650a1645534454526f6c654e46544164645175616e74697479",
"454c524f4e44726f6c65657364744d4554414e46542d643062623339": "0a1145534454526f6c654e4654437265617465",
"454c524f4e446573647442534b2d343736343730": "120b00021e19e0c9bab23fff7b",
"454c524f4e44657364744e45543253432d306438663962": "120f0004ee2d6d3f3d6bcc25c64dc00000",
"454c524f4e4465736474424358535542542d3339326436616c": "080112020001",
"454c524f4e44657364744e4943552d393730323932": "120b00d3c21bcecceda1000000",
"454c524f4e4465736474424358535542542d3339326436616e": "080112020001"
},
"code": "",
"code_hash": "",
"root_hash": "AJ2jyOcPXgZAl0kHAlbWZIlG3F1VDtcoLAHR6eqehBA=",
"code_metadata": "",
"owner_address": "",
"developer_reward": "0"
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -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;

let _ = interactor.generate_blocks(30u64).await;
interactor.generate_blocks(30u64).await.unwrap();

AdderInteract {
interactor,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use basic_interactor::{AdderInteract, Config};
use multiversx_sc_snippets::{sdk::gateway::SetStateAccount, test_wallets};
use multiversx_sc_snippets::{imports::Bech32Address, sdk::gateway::SetStateAccount, test_wallets};

#[tokio::test]
#[cfg_attr(not(feature = "chain-simulator-tests"), ignore)]
Expand Down Expand Up @@ -61,3 +61,37 @@ async fn set_state_cs_test() {

assert!(set_state_response.is_ok());
}

#[tokio::test]
#[cfg_attr(not(feature = "chain-simulator-tests"), ignore)]
async fn set_state_from_file_cs_test() {
let account_address = test_wallets::mike();
let account_address_2 = test_wallets::ivan();

let mut real_chain_interact = AdderInteract::new(Config::load_config()).await;
let simulator_interact = AdderInteract::new(Config::chain_simulator_config()).await;

// now we should have current mike account in the set state file
real_chain_interact
.interactor
.retrieve_account(&Bech32Address::from(&account_address.to_address()))
.await;

real_chain_interact
.interactor
.retrieve_account(&Bech32Address::from(&account_address_2.to_address()))
.await;

let set_state_response = simulator_interact
.interactor
.set_state_for_saved_accounts()
.await;

simulator_interact
.interactor
.generate_blocks(2u64)
.await
.unwrap();

assert!(set_state_response.is_ok());
}
6 changes: 2 additions & 4 deletions framework/snippets/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ log = "0.4.17"
env_logger = "0.11"
futures = "0.3"
anyhow = "1.0.44"
serde_json = "1.0"

tokio = { version = "1.24", features = ["full"], optional = true}
tokio = { version = "1.24", features = ["full"], optional = true }

[dependencies.multiversx-sc-scenario]
version = "=0.54.1"
Expand All @@ -52,6 +53,3 @@ default-features = false
version = "=0.7.0"
path = "../../sdk/dapp"
optional = true

[dev-dependencies]
serde_json = "1.0"
16 changes: 10 additions & 6 deletions framework/snippets/src/account_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use multiversx_sc_scenario::{
imports::Bech32Address,
scenario_model::{Account, BytesKey, BytesValue, Scenario, SetStateStep, Step},
};
use multiversx_sdk::gateway::GatewayAsyncService;
use multiversx_sdk::gateway::{GatewayAsyncService, SetStateAccount};
use multiversx_sdk::gateway::{
GetAccountEsdtRolesRequest, GetAccountEsdtTokensRequest, GetAccountRequest,
GetAccountStorageRequest,
Expand All @@ -20,7 +20,7 @@ pub async fn print_account_as_scenario_set_state<GatewayProxy: GatewayAsyncServi
address_bech32_string: String,
) {
let address = Bech32Address::from_bech32_string(address_bech32_string);
let set_state = retrieve_account_as_scenario_set_state(&gateway_proxy, &address).await;
let (_, set_state) = retrieve_account_as_scenario_set_state(&gateway_proxy, &address).await;
let scenario = build_scenario(set_state);
println!("{}", scenario.into_raw().to_json_string());
}
Expand All @@ -37,7 +37,7 @@ fn build_scenario(set_state: SetStateStep) -> Scenario {
pub async fn retrieve_account_as_scenario_set_state<GatewayProxy: GatewayAsyncService>(
api: &GatewayProxy,
bech32_address: &Bech32Address,
) -> SetStateStep {
) -> (SetStateAccount, SetStateStep) {
let address = bech32_address.as_address();
let sdk_account = api.request(GetAccountRequest::new(address)).await.unwrap();

Expand All @@ -63,14 +63,18 @@ pub async fn retrieve_account_as_scenario_set_state<GatewayProxy: GatewayAsyncSe
});

let account_state = set_account(
sdk_account,
account_storage,
sdk_account.clone(),
account_storage.clone(),
account_esdt,
account_esdt_roles,
);

let set_state_account = SetStateAccount::from(sdk_account).with_keys(account_storage);
let set_state_step = SetStateStep::new();
set_state_step.put_account(bech32_address, account_state)
(
set_state_account,
set_state_step.put_account(bech32_address, account_state),
)
}

fn set_account(
Expand Down
35 changes: 31 additions & 4 deletions framework/snippets/src/interactor/interactor_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@ use multiversx_sc_scenario::{
meta::tools::find_current_workspace,
multiversx_sc::types::Address,
};
use multiversx_sdk::gateway::{GatewayAsyncService, NetworkConfigRequest};
use multiversx_sdk::gateway::{GatewayAsyncService, NetworkConfigRequest, SetStateAccount};
use std::{
collections::HashMap,
fs::File,
io::BufReader,
path::{Path, PathBuf},
time::Duration,
};

use crate::{account_tool::retrieve_account_as_scenario_set_state, Sender};

pub const INTERACTOR_SCENARIO_TRACE_PATH: &str = "interactor_trace.scen.json";
pub const INTERACTOR_SET_STATE_PATH: &str = "set_state.json";

pub struct InteractorBase<GatewayProxy>
where
Expand Down Expand Up @@ -85,9 +88,33 @@ where
}

pub async fn retrieve_account(&mut self, wallet_address: &Bech32Address) {
let set_state = retrieve_account_as_scenario_set_state(&self.proxy, wallet_address).await;
self.pre_runners.run_set_state_step(&set_state);
self.post_runners.run_set_state_step(&set_state);
let (set_state_account, set_state_step) =
retrieve_account_as_scenario_set_state(&self.proxy, wallet_address).await;
self.pre_runners.run_set_state_step(&set_state_step);
self.post_runners.run_set_state_step(&set_state_step);

let path = self.get_state_file_path();
set_state_account.add_to_state_file(path.as_path());
}

pub fn get_state_file_path(&self) -> PathBuf {
self.current_dir.join(INTERACTOR_SET_STATE_PATH)
}

pub fn get_accounts_from_file(&self) -> Vec<SetStateAccount> {
let file_path = self.get_state_file_path();

if !file_path.exists() {
return Vec::new();
}

let file = File::open(file_path).expect("Failed to open state file");
let reader = BufReader::new(file);

serde_json::from_reader(reader).unwrap_or_else(|_| {
println!("Failed to parse state file; returning an empty list of accounts");
Vec::new()
})
}

/// Tells the interactor where the crate lies relative to the workspace.
Expand Down
11 changes: 11 additions & 0 deletions framework/snippets/src/interactor/interactor_chain_simulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,15 @@ where
.request(ChainSimulatorSetStateRequest::for_accounts(accounts))
.await
}

pub async fn set_state_for_saved_accounts(&self) -> Result<String, Error> {
if !self.use_chain_simulator {
return Ok(String::from("no-simulator"));
}

let accounts = self.get_accounts_from_file();
self.proxy
.request(ChainSimulatorSetStateRequest::for_accounts(accounts))
.await
}
}
41 changes: 40 additions & 1 deletion sdk/core/src/gateway/gateway_chain_simulator_set_state.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
use anyhow::anyhow;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::{
collections::HashMap,
fs::{File, OpenOptions},
io::{BufReader, BufWriter},
path::Path,
};

use crate::data::account::Account;

Expand Down Expand Up @@ -55,6 +60,40 @@ impl SetStateAccount {

self
}

pub fn add_to_state_file(self, path: &Path) {
let mut accounts = if path.exists() {
let file = File::open(path)
.unwrap_or_else(|_| panic!("Failed to open state file at path {path:#?}"));

let reader = BufReader::new(file);

serde_json::from_reader::<_, Vec<SetStateAccount>>(reader).unwrap_or_default()
} else {
Vec::new()
};

if let Some(existing_account) = accounts
.iter_mut()
.find(|account| account.address == self.address)
{
*existing_account = self;
} else {
accounts.push(self);
}

let file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(path)
.unwrap_or_else(|_| panic!("Failed to open or create state file at path {path:#?}"));

let writer = BufWriter::new(file);
serde_json::to_writer_pretty(writer, &accounts).unwrap_or_else(|_| {
panic!("Failed to write updated state accounts to file at path {path:#?}")
});
}
}

/// Sets state for a list of accounts using the chain simulator API.
Expand Down

0 comments on commit 3f400e2

Please sign in to comment.