From 43edef0cb8a36f1d59d408b155b5c9f666c70bb5 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Wed, 17 Apr 2024 17:44:12 +0300 Subject: [PATCH 1/3] scenario tx file rename --- framework/scenario/src/facade/world_tx.rs | 14 +++++++------- ...{scenario_env_exec.rs => scenario_exec_call.rs} | 0 ...nario_env_deploy.rs => scenario_exec_deploy.rs} | 0 ...cenario_env_query.rs => scenario_query_call.rs} | 0 .../{scenario_env.rs => scenario_tx_env.rs} | 0 5 files changed, 7 insertions(+), 7 deletions(-) rename framework/scenario/src/facade/world_tx/{scenario_env_exec.rs => scenario_exec_call.rs} (100%) rename framework/scenario/src/facade/world_tx/{scenario_env_deploy.rs => scenario_exec_deploy.rs} (100%) rename framework/scenario/src/facade/world_tx/{scenario_env_query.rs => scenario_query_call.rs} (100%) rename framework/scenario/src/facade/world_tx/{scenario_env.rs => scenario_tx_env.rs} (100%) diff --git a/framework/scenario/src/facade/world_tx.rs b/framework/scenario/src/facade/world_tx.rs index 2fa69c744e..005421c933 100644 --- a/framework/scenario/src/facade/world_tx.rs +++ b/framework/scenario/src/facade/world_tx.rs @@ -1,11 +1,11 @@ #![allow(unused)] // TEMP -mod scenario_env; -mod scenario_env_deploy; -mod scenario_env_exec; -mod scenario_env_query; +mod scenario_exec_call; +mod scenario_exec_deploy; +mod scenario_query_call; mod scenario_rh_impl; +mod scenario_tx_env; -pub use scenario_env::{ScenarioTxEnv, ScenarioTxEnvData, ScenarioTxRun}; -pub use scenario_env_exec::ScenarioEnvExec; -pub use scenario_env_query::ScenarioEnvQuery; +pub use scenario_exec_call::ScenarioEnvExec; +pub use scenario_query_call::ScenarioEnvQuery; +pub use scenario_tx_env::{ScenarioTxEnv, ScenarioTxEnvData, ScenarioTxRun}; diff --git a/framework/scenario/src/facade/world_tx/scenario_env_exec.rs b/framework/scenario/src/facade/world_tx/scenario_exec_call.rs similarity index 100% rename from framework/scenario/src/facade/world_tx/scenario_env_exec.rs rename to framework/scenario/src/facade/world_tx/scenario_exec_call.rs diff --git a/framework/scenario/src/facade/world_tx/scenario_env_deploy.rs b/framework/scenario/src/facade/world_tx/scenario_exec_deploy.rs similarity index 100% rename from framework/scenario/src/facade/world_tx/scenario_env_deploy.rs rename to framework/scenario/src/facade/world_tx/scenario_exec_deploy.rs diff --git a/framework/scenario/src/facade/world_tx/scenario_env_query.rs b/framework/scenario/src/facade/world_tx/scenario_query_call.rs similarity index 100% rename from framework/scenario/src/facade/world_tx/scenario_env_query.rs rename to framework/scenario/src/facade/world_tx/scenario_query_call.rs diff --git a/framework/scenario/src/facade/world_tx/scenario_env.rs b/framework/scenario/src/facade/world_tx/scenario_tx_env.rs similarity index 100% rename from framework/scenario/src/facade/world_tx/scenario_env.rs rename to framework/scenario/src/facade/world_tx/scenario_tx_env.rs From 02556f8a8b2b216ac3adfcb751690ac4d1587f72 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Wed, 17 Apr 2024 18:12:43 +0300 Subject: [PATCH 2/3] scenario exec - rename, reorg, cleanup --- framework/scenario/src/facade/world_tx.rs | 4 +- .../facade/world_tx/scenario_check_state.rs | 227 ++++++++++++++++ .../src/facade/world_tx/scenario_exec_call.rs | 243 +----------------- .../facade/world_tx/scenario_exec_deploy.rs | 14 +- .../facade/world_tx/scenario_query_call.rs | 231 +---------------- .../src/facade/world_tx/scenario_rh_impl.rs | 12 +- .../src/facade/world_tx/scenario_set_state.rs | 239 +++++++++++++++++ .../src/facade/world_tx/scenario_tx_env.rs | 8 +- 8 files changed, 485 insertions(+), 493 deletions(-) create mode 100644 framework/scenario/src/facade/world_tx/scenario_check_state.rs create mode 100644 framework/scenario/src/facade/world_tx/scenario_set_state.rs diff --git a/framework/scenario/src/facade/world_tx.rs b/framework/scenario/src/facade/world_tx.rs index 005421c933..a2d7373a42 100644 --- a/framework/scenario/src/facade/world_tx.rs +++ b/framework/scenario/src/facade/world_tx.rs @@ -1,9 +1,9 @@ -#![allow(unused)] // TEMP - +mod scenario_check_state; mod scenario_exec_call; mod scenario_exec_deploy; mod scenario_query_call; mod scenario_rh_impl; +mod scenario_set_state; mod scenario_tx_env; pub use scenario_exec_call::ScenarioEnvExec; diff --git a/framework/scenario/src/facade/world_tx/scenario_check_state.rs b/framework/scenario/src/facade/world_tx/scenario_check_state.rs new file mode 100644 index 0000000000..ab54d7411f --- /dev/null +++ b/framework/scenario/src/facade/world_tx/scenario_check_state.rs @@ -0,0 +1,227 @@ +use std::collections::{btree_map::Entry, BTreeMap}; + +use multiversx_chain_scenario_format::interpret_trait::{InterpretableFrom, InterpreterContext}; +use multiversx_sc::{codec::test_util::top_encode_to_vec_u8_or_panic, proxy_imports::TopEncode}; + +use crate::{ + scenario::ScenarioRunner, + scenario_model::{ + AddressKey, BigUintValue, BytesKey, BytesValue, CheckAccount, CheckEsdt, CheckEsdtData, + CheckEsdtInstances, CheckEsdtMap, CheckEsdtMapContents, CheckStateStep, CheckStorage, + CheckStorageDetails, CheckValue, U64Value, + }, + ScenarioWorld, +}; + +impl ScenarioWorld { + pub fn check_state_account(&mut self, address: A) -> CheckStateBuilder<'_> + where + AddressKey: From, + { + CheckStateBuilder::new(self, address.into()) + } +} + +pub struct CheckStateBuilder<'w> { + world: &'w mut ScenarioWorld, + check_state_step: CheckStateStep, + current_account: CheckAccount, + current_address: AddressKey, +} + +impl<'w> CheckStateBuilder<'w> { + pub(crate) fn new(world: &'w mut ScenarioWorld, address: AddressKey) -> CheckStateBuilder<'w> { + let mut builder = CheckStateBuilder { + world, + check_state_step: CheckStateStep::new(), + current_account: CheckAccount::new(), + current_address: AddressKey::default(), + }; + builder.reset_account(address); + builder + } + + /// Starts building of a new account. + pub fn check_state_account(mut self, address_expr: A) -> Self + where + AddressKey: From, + { + self.add_current_acount(); + self.reset_account(address_expr.into()); + self + } + + fn add_current_acount(&mut self) { + if let Entry::Vacant(entry) = self + .check_state_step + .accounts + .accounts + .entry(core::mem::take(&mut self.current_address)) + { + entry.insert(core::mem::take(&mut self.current_account)); + }; + } + + fn reset_account(&mut self, address: AddressKey) { + self.current_address = address; + self.current_account = CheckAccount::default(); + } + + /// Finished and sets all account in the blockchain mock. + fn commit_accounts(&mut self) { + self.add_current_acount(); + self.world.run_check_state_step(&self.check_state_step); + } + + /// Forces value drop and commit accounts. + pub fn commit(self) {} + + pub fn nonce(mut self, nonce: V) -> Self + where + U64Value: InterpretableFrom, + { + self.current_account.nonce = CheckValue::Equal(U64Value::interpret_from( + nonce, + &InterpreterContext::default(), + )); + self + } + + pub fn balance(mut self, balance_expr: V) -> Self + where + BigUintValue: InterpretableFrom, + { + self.current_account.balance = CheckValue::Equal(BigUintValue::interpret_from( + balance_expr, + &InterpreterContext::default(), + )); + self + } + + pub fn code(mut self, code_expr: V) -> Self + where + BytesValue: InterpretableFrom, + { + self.current_account.code = CheckValue::Equal(BytesValue::interpret_from( + code_expr, + &InterpreterContext::default(), + )); + self + } + + pub fn code_metadata(mut self, code_metadata_expr: V) -> Self + where + BytesValue: InterpretableFrom, + { + self.current_account.code_metadata = CheckValue::Equal(BytesValue::interpret_from( + code_metadata_expr, + &InterpreterContext::default(), + )); + self + } + + pub fn esdt_balance(mut self, token_id_expr: K, balance_expr: V) -> Self + where + BytesKey: From, + BigUintValue: From, + { + let token_id = BytesKey::from(token_id_expr); + let balance = BigUintValue::from(balance_expr); + + match &mut self.current_account.esdt { + CheckEsdtMap::Unspecified | CheckEsdtMap::Star => { + let mut new_esdt_map = BTreeMap::new(); + let _ = new_esdt_map.insert(token_id, CheckEsdt::Short(balance)); + + let new_check_esdt_map = CheckEsdtMapContents { + contents: new_esdt_map, + other_esdts_allowed: true, + }; + + self.current_account.esdt = CheckEsdtMap::Equal(new_check_esdt_map); + }, + CheckEsdtMap::Equal(check_esdt_map) => { + if check_esdt_map.contents.contains_key(&token_id) { + let prev_entry = check_esdt_map.contents.get_mut(&token_id).unwrap(); + match prev_entry { + CheckEsdt::Short(prev_balance_check) => *prev_balance_check = balance, + CheckEsdt::Full(prev_esdt_check) => match prev_esdt_check.instances { + CheckEsdtInstances::Star => todo!(), + CheckEsdtInstances::Equal(_) => todo!(), + }, + } + } + }, + } + + self + } + + pub fn esdt_nft_balance_and_attributes( + mut self, + token_id_expr: K, + nonce_expr: N, + balance_expr: V, + attributes_expr: Option, + ) -> Self + where + BytesKey: From, + U64Value: From, + BigUintValue: From, + T: TopEncode, + { + let token_id = BytesKey::from(token_id_expr); + + if let CheckEsdtMap::Unspecified = &self.current_account.esdt { + let mut check_esdt = CheckEsdt::Full(CheckEsdtData::default()); + + if let Some(attributes_expr) = attributes_expr { + check_esdt.add_balance_and_attributes_check( + nonce_expr, + balance_expr, + top_encode_to_vec_u8_or_panic(&attributes_expr), + ); + } else { + check_esdt.add_balance_and_attributes_check( + nonce_expr, + balance_expr, + Vec::::new(), + ); + } + + let mut new_esdt_map = BTreeMap::new(); + let _ = new_esdt_map.insert(token_id, check_esdt); + + let new_check_esdt_map = CheckEsdtMapContents { + contents: new_esdt_map, + other_esdts_allowed: true, + }; + + self.current_account.esdt = CheckEsdtMap::Equal(new_check_esdt_map); + } + + self + } + + pub fn check_storage(mut self, key: &str, value: &str) -> Self { + let mut details = match &self.current_account.storage { + CheckStorage::Star => CheckStorageDetails::default(), + CheckStorage::Equal(details) => details.clone(), + }; + details.storages.insert( + BytesKey::interpret_from(key, &InterpreterContext::default()), + CheckValue::Equal(BytesValue::interpret_from( + value, + &InterpreterContext::default(), + )), + ); + self.current_account.storage = CheckStorage::Equal(details); + self + } +} + +impl<'w> Drop for CheckStateBuilder<'w> { + fn drop(&mut self) { + self.commit_accounts(); + } +} 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 5eef522784..e92e38087c 100644 --- a/framework/scenario/src/facade/world_tx/scenario_exec_call.rs +++ b/framework/scenario/src/facade/world_tx/scenario_exec_call.rs @@ -1,23 +1,15 @@ -use std::{collections::btree_map::Entry, ops::Add, path::PathBuf}; - -use multiversx_chain_scenario_format::serde_raw::ValueSubTree; use multiversx_sc::{ tuple_util::NestedTupleFlatten, types::{ - Address, AddressExpr, AnnotatedValue, Code, DeployCall, FunctionCall, ManagedAddress, - ManagedBuffer, RHListExec, Tx, TxBaseWithEnv, TxCodeSource, TxCodeSourceSpecified, - TxCodeValue, TxEnv, TxFromSpecified, TxGas, TxPayment, TxTo, TxToSpecified, + FunctionCall, ManagedAddress, ManagedBuffer, RHListExec, Tx, TxBaseWithEnv, TxEnv, + TxFromSpecified, TxGas, TxPayment, TxToSpecified, }, }; -use serde_json::map::OccupiedEntry; use crate::{ api::StaticApi, - scenario::{tx_to_step::TxToStep, ScenarioRunner}, - scenario_model::{ - Account, AddressKey, AddressValue, BigUintValue, BytesKey, BytesValue, Esdt, EsdtObject, - NewAddress, ScCallStep, ScDeployStep, SetStateStep, TxExpect, TxResponse, U64Value, - }, + scenario::tx_to_step::TxToStep, + scenario_model::{TxExpect, TxResponse}, ScenarioTxEnv, ScenarioTxRun, ScenarioWorld, }; @@ -99,231 +91,4 @@ impl ScenarioWorld { step_wrapper.process_result(); self } - - pub fn account(&mut self, address_expr: A) -> SetStateBuilder<'_> - where - AddressKey: From, - { - SetStateBuilder::new(self, address_expr.into()) - } -} - -pub struct SetStateBuilder<'w> { - world: &'w mut ScenarioWorld, - set_state_step: SetStateStep, - current_account: Account, - current_address: AddressKey, -} - -impl<'w> SetStateBuilder<'w> { - pub(crate) fn new(world: &'w mut ScenarioWorld, address: AddressKey) -> SetStateBuilder<'w> { - let mut builder = SetStateBuilder { - world, - set_state_step: SetStateStep::new(), - current_address: AddressKey::default(), - current_account: Account::new(), - }; - builder.reset_account(address); - builder - } - - fn add_current_acount(&mut self) { - if let Entry::Vacant(entry) = self - .set_state_step - .accounts - .entry(core::mem::take(&mut self.current_address)) - { - entry.insert(core::mem::take(&mut self.current_account)); - }; - } - - fn reset_account(&mut self, address: AddressKey) { - assert!( - !self - .world - .get_debugger_backend() - .vm_runner - .blockchain_mock - .state - .account_exists(&address.to_vm_address()), - "updating existing accounts currently not supported" - ); - - self.current_address = address; - self.current_account = Account::default(); - } - - /// Starts building of a new account. - pub fn account(mut self, address_expr: A) -> Self - where - AddressKey: From, - { - self.add_current_acount(); - self.reset_account(address_expr.into()); - self - } - - /// Finished and sets all account in the blockchain mock. - fn commit_accounts(&mut self) { - self.add_current_acount(); - self.world.run_set_state_step(&self.set_state_step); - } - - /// Forces value drop and commit accounts. - pub fn commit(self) {} - - pub fn nonce(mut self, nonce: V) -> Self - where - U64Value: From, - { - self.current_account.nonce = Some(U64Value::from(nonce)); - self - } - - pub fn balance(mut self, balance_expr: V) -> Self - where - BigUintValue: From, - { - self.current_account.balance = Some(BigUintValue::from(balance_expr)); - self - } - - pub fn esdt_balance(mut self, token_id_expr: K, balance_expr: V) -> Self - where - BytesKey: From, - BigUintValue: From, - { - let token_id = BytesKey::from(token_id_expr); - let esdt_data_ref = self.get_esdt_data_or_create(&token_id); - esdt_data_ref.set_balance(0u64, balance_expr); - - self - } - - pub fn esdt_nft_balance( - mut self, - token_id_expr: K, - nonce_expr: N, - balance_expr: V, - opt_attributes_expr: Option, - ) -> Self - where - N: Clone, - BytesKey: From, - U64Value: From, - BigUintValue: From, - BytesValue: From, - { - let token_id = BytesKey::from(token_id_expr); - - let esdt_obj_ref = self - .get_esdt_data_or_create(&token_id) - .get_mut_esdt_object(); - esdt_obj_ref.set_balance(nonce_expr.clone(), balance_expr); - - if let Some(attributes_expr) = opt_attributes_expr { - esdt_obj_ref.set_token_attributes(nonce_expr, attributes_expr); - } - - self - } - - #[allow(clippy::too_many_arguments)] - pub fn esdt_nft_all_properties( - mut self, - token_id_expr: K, - nonce_expr: N, - balance_expr: V, - opt_attributes_expr: Option, - royalties_expr: N, - creator_expr: Option, - hash_expr: Option, - uris_expr: Vec, - ) -> Self - where - BytesKey: From, - U64Value: From, - BigUintValue: From, - BytesValue: From, - { - let token_id = BytesKey::from(token_id_expr); - - let esdt_obj_ref = self - .get_esdt_data_or_create(&token_id) - .get_mut_esdt_object(); - - esdt_obj_ref.set_token_all_properties( - nonce_expr, - balance_expr, - opt_attributes_expr, - royalties_expr, - creator_expr, - hash_expr, - uris_expr, - ); - - self - } - - pub fn esdt_nft_last_nonce(mut self, token_id_expr: K, last_nonce_expr: N) -> Self - where - BytesKey: From, - U64Value: From, - { - let token_id = BytesKey::from(token_id_expr); - - let esdt_obj_ref = self - .get_esdt_data_or_create(&token_id) - .get_mut_esdt_object(); - esdt_obj_ref.set_last_nonce(last_nonce_expr); - - self - } - - // TODO: Find a better way to pass roles - pub fn esdt_roles(mut self, token_id_expr: K, roles: Vec) -> Self - where - BytesKey: From, - { - let token_id = BytesKey::from(token_id_expr); - - let esdt_obj_ref = self - .get_esdt_data_or_create(&token_id) - .get_mut_esdt_object(); - esdt_obj_ref.set_roles(roles); - - self - } - - fn get_esdt_data_or_create(&mut self, token_id: &BytesKey) -> &mut Esdt { - if !self.current_account.esdt.contains_key(token_id) { - self.current_account - .esdt - .insert(token_id.clone(), Esdt::Full(EsdtObject::default())); - } - - self.current_account.esdt.get_mut(token_id).unwrap() - } - - pub fn code(mut self, code_expr: V) -> Self - where - BytesValue: From, - { - self.current_account.code = Some(BytesValue::from(code_expr)); - self - } - - pub fn owner(mut self, owner_expr: V) -> Self - where - AddressValue: From, - { - self.current_account.owner = Some(AddressValue::from(owner_expr)); - self - } -} - -impl<'w> Drop for SetStateBuilder<'w> { - fn drop(&mut self) { - self.commit_accounts(); - } } 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 c218f06869..866d4f562f 100644 --- a/framework/scenario/src/facade/world_tx/scenario_exec_deploy.rs +++ b/framework/scenario/src/facade/world_tx/scenario_exec_deploy.rs @@ -1,20 +1,14 @@ -use std::path::PathBuf; - -use multiversx_chain_scenario_format::serde_raw::ValueSubTree; use multiversx_sc::{ tuple_util::NestedTupleFlatten, types::{ - AnnotatedValue, Code, DeployCall, FunctionCall, ManagedAddress, ManagedBuffer, RHListExec, - Tx, TxBaseWithEnv, TxCodeSource, TxCodeSourceSpecified, TxCodeValue, TxEnv, - TxFromSpecified, TxGas, TxPayment, TxToSpecified, + Code, DeployCall, RHListExec, Tx, TxBaseWithEnv, TxCodeValue, TxFromSpecified, TxGas, + TxPayment, }, }; use crate::{ - api::StaticApi, - scenario::tx_to_step::TxToStep, - scenario_model::{AddressValue, BytesValue, ScCallStep, ScDeployStep, TxResponse}, - ScenarioEnvExec, ScenarioTxEnv, ScenarioTxRun, ScenarioWorld, + scenario::tx_to_step::TxToStep, scenario_model::TxResponse, ScenarioEnvExec, ScenarioTxRun, + ScenarioWorld, }; use super::ScenarioTxEnvData; diff --git a/framework/scenario/src/facade/world_tx/scenario_query_call.rs b/framework/scenario/src/facade/world_tx/scenario_query_call.rs index 387ad0f444..dbcf3130f5 100644 --- a/framework/scenario/src/facade/world_tx/scenario_query_call.rs +++ b/framework/scenario/src/facade/world_tx/scenario_query_call.rs @@ -1,27 +1,15 @@ -use std::{ - collections::{btree_map::Entry, BTreeMap}, - path::PathBuf, -}; - -use multiversx_chain_scenario_format::interpret_trait::{InterpretableFrom, InterpreterContext}; use multiversx_sc::{ - codec::test_util::top_encode_to_vec_u8_or_panic, - proxy_imports::TopEncode, tuple_util::NestedTupleFlatten, types::{ - AnnotatedValue, FunctionCall, ManagedAddress, ManagedBuffer, RHListExec, Tx, TxBaseWithEnv, - TxEnv, TxFromSpecified, TxGas, TxPayment, TxToSpecified, + FunctionCall, ManagedAddress, ManagedBuffer, RHListExec, Tx, TxBaseWithEnv, TxEnv, + TxToSpecified, }, }; use crate::{ api::StaticApi, - scenario::{tx_to_step::TxToQueryStep, ScenarioRunner}, - scenario_model::{ - AddressKey, BigUintValue, BytesKey, BytesValue, CheckAccount, CheckEsdt, CheckEsdtData, - CheckEsdtInstances, CheckEsdtMap, CheckEsdtMapContents, CheckStateStep, CheckStorage, - CheckStorageDetails, CheckValue, TxExpect, TxResponse, U64Value, - }, + scenario::tx_to_step::TxToQueryStep, + scenario_model::{TxExpect, TxResponse}, ScenarioTxEnv, ScenarioTxEnvData, ScenarioTxRun, ScenarioWorld, }; @@ -93,215 +81,4 @@ impl ScenarioWorld { step_wrapper.process_result(); self } - - pub fn check_state_account(&mut self, address: A) -> CheckStateBuilder<'_> - where - AddressKey: From, - { - CheckStateBuilder::new(self, address.into()) - } -} - -pub struct CheckStateBuilder<'w> { - world: &'w mut ScenarioWorld, - check_state_step: CheckStateStep, - current_account: CheckAccount, - current_address: AddressKey, -} - -impl<'w> CheckStateBuilder<'w> { - pub(crate) fn new(world: &'w mut ScenarioWorld, address: AddressKey) -> CheckStateBuilder<'w> { - let mut builder = CheckStateBuilder { - world, - check_state_step: CheckStateStep::new(), - current_account: CheckAccount::new(), - current_address: AddressKey::default(), - }; - builder.reset_account(address); - builder - } - - /// Starts building of a new account. - pub fn check_state_account(mut self, address_expr: A) -> Self - where - AddressKey: From, - { - self.add_current_acount(); - self.reset_account(address_expr.into()); - self - } - - fn add_current_acount(&mut self) { - if let Entry::Vacant(entry) = self - .check_state_step - .accounts - .accounts - .entry(core::mem::take(&mut self.current_address)) - { - entry.insert(core::mem::take(&mut self.current_account)); - }; - } - - fn reset_account(&mut self, address: AddressKey) { - self.current_address = address; - self.current_account = CheckAccount::default(); - } - - /// Finished and sets all account in the blockchain mock. - fn commit_accounts(&mut self) { - self.add_current_acount(); - self.world.run_check_state_step(&self.check_state_step); - } - - /// Forces value drop and commit accounts. - pub fn commit(self) {} - - pub fn nonce(mut self, nonce: V) -> Self - where - U64Value: InterpretableFrom, - { - self.current_account.nonce = CheckValue::Equal(U64Value::interpret_from( - nonce, - &InterpreterContext::default(), - )); - self - } - - pub fn balance(mut self, balance_expr: V) -> Self - where - BigUintValue: InterpretableFrom, - { - self.current_account.balance = CheckValue::Equal(BigUintValue::interpret_from( - balance_expr, - &InterpreterContext::default(), - )); - self - } - - pub fn code(mut self, code_expr: V) -> Self - where - BytesValue: InterpretableFrom, - { - self.current_account.code = CheckValue::Equal(BytesValue::interpret_from( - code_expr, - &InterpreterContext::default(), - )); - self - } - - pub fn code_metadata(mut self, code_metadata_expr: V) -> Self - where - BytesValue: InterpretableFrom, - { - self.current_account.code_metadata = CheckValue::Equal(BytesValue::interpret_from( - code_metadata_expr, - &InterpreterContext::default(), - )); - self - } - - pub fn esdt_balance(mut self, token_id_expr: K, balance_expr: V) -> Self - where - BytesKey: From, - BigUintValue: From, - { - let token_id = BytesKey::from(token_id_expr); - let balance = BigUintValue::from(balance_expr); - - match &mut self.current_account.esdt { - CheckEsdtMap::Unspecified | CheckEsdtMap::Star => { - let mut new_esdt_map = BTreeMap::new(); - let _ = new_esdt_map.insert(token_id, CheckEsdt::Short(balance)); - - let new_check_esdt_map = CheckEsdtMapContents { - contents: new_esdt_map, - other_esdts_allowed: true, - }; - - self.current_account.esdt = CheckEsdtMap::Equal(new_check_esdt_map); - }, - CheckEsdtMap::Equal(check_esdt_map) => { - if check_esdt_map.contents.contains_key(&token_id) { - let prev_entry = check_esdt_map.contents.get_mut(&token_id).unwrap(); - match prev_entry { - CheckEsdt::Short(prev_balance_check) => *prev_balance_check = balance, - CheckEsdt::Full(prev_esdt_check) => match prev_esdt_check.instances { - CheckEsdtInstances::Star => todo!(), - CheckEsdtInstances::Equal(_) => todo!(), - }, - } - } - }, - } - - self - } - - pub fn esdt_nft_balance_and_attributes( - mut self, - token_id_expr: K, - nonce_expr: N, - balance_expr: V, - attributes_expr: Option, - ) -> Self - where - BytesKey: From, - U64Value: From, - BigUintValue: From, - T: TopEncode, - { - let token_id = BytesKey::from(token_id_expr); - - if let CheckEsdtMap::Unspecified = &self.current_account.esdt { - let mut check_esdt = CheckEsdt::Full(CheckEsdtData::default()); - - if let Some(attributes_expr) = attributes_expr { - check_esdt.add_balance_and_attributes_check( - nonce_expr, - balance_expr, - top_encode_to_vec_u8_or_panic(&attributes_expr), - ); - } else { - check_esdt.add_balance_and_attributes_check( - nonce_expr, - balance_expr, - Vec::::new(), - ); - } - - let mut new_esdt_map = BTreeMap::new(); - let _ = new_esdt_map.insert(token_id, check_esdt); - - let new_check_esdt_map = CheckEsdtMapContents { - contents: new_esdt_map, - other_esdts_allowed: true, - }; - - self.current_account.esdt = CheckEsdtMap::Equal(new_check_esdt_map); - } - - self - } - - pub fn check_storage(mut self, key: &str, value: &str) -> Self { - let mut details = match &self.current_account.storage { - CheckStorage::Star => CheckStorageDetails::default(), - CheckStorage::Equal(details) => details.clone(), - }; - details.storages.insert( - BytesKey::interpret_from(key, &InterpreterContext::default()), - CheckValue::Equal(BytesValue::interpret_from( - value, - &InterpreterContext::default(), - )), - ); - self.current_account.storage = CheckStorage::Equal(details); - self - } -} - -impl<'w> Drop for CheckStateBuilder<'w> { - fn drop(&mut self) { - self.commit_accounts(); - } } diff --git a/framework/scenario/src/facade/world_tx/scenario_rh_impl.rs b/framework/scenario/src/facade/world_tx/scenario_rh_impl.rs index bbf29a0d03..d040f0bc3a 100644 --- a/framework/scenario/src/facade/world_tx/scenario_rh_impl.rs +++ b/framework/scenario/src/facade/world_tx/scenario_rh_impl.rs @@ -1,18 +1,12 @@ use multiversx_sc::{ codec::{CodecFrom, TopDecodeMulti, TopEncodeMulti}, types::{ - ManagedAddress, RHList, RHListItem, RHListItemExec, ReturnsNewAddress, - ReturnsNewManagedAddress, ReturnsResult, ReturnsResultConv, TxEnv, WithNewAddress, - WithResultConv, + ManagedAddress, RHListItemExec, ReturnsNewAddress, ReturnsNewManagedAddress, ReturnsResult, + ReturnsResultConv, TxEnv, WithNewAddress, WithResultConv, }, }; -use crate::{ - api::StaticApi, - scenario_model::{TxResponse, TypedResponse}, -}; - -use super::ScenarioTxEnvData; +use crate::scenario_model::{TxResponse, TypedResponse}; impl RHListItemExec for ReturnsResult where diff --git a/framework/scenario/src/facade/world_tx/scenario_set_state.rs b/framework/scenario/src/facade/world_tx/scenario_set_state.rs new file mode 100644 index 0000000000..110b1b9692 --- /dev/null +++ b/framework/scenario/src/facade/world_tx/scenario_set_state.rs @@ -0,0 +1,239 @@ +use std::collections::btree_map::Entry; + +use crate::{ + scenario::ScenarioRunner, + scenario_model::{ + Account, AddressKey, AddressValue, BigUintValue, BytesKey, BytesValue, Esdt, EsdtObject, + SetStateStep, U64Value, + }, + ScenarioWorld, +}; + +impl ScenarioWorld { + pub fn account(&mut self, address_expr: A) -> SetStateBuilder<'_> + where + AddressKey: From, + { + SetStateBuilder::new(self, address_expr.into()) + } +} + +pub struct SetStateBuilder<'w> { + world: &'w mut ScenarioWorld, + set_state_step: SetStateStep, + current_account: Account, + current_address: AddressKey, +} + +impl<'w> SetStateBuilder<'w> { + pub(crate) fn new(world: &'w mut ScenarioWorld, address: AddressKey) -> SetStateBuilder<'w> { + let mut builder = SetStateBuilder { + world, + set_state_step: SetStateStep::new(), + current_address: AddressKey::default(), + current_account: Account::new(), + }; + builder.reset_account(address); + builder + } + + fn add_current_acount(&mut self) { + if let Entry::Vacant(entry) = self + .set_state_step + .accounts + .entry(core::mem::take(&mut self.current_address)) + { + entry.insert(core::mem::take(&mut self.current_account)); + }; + } + + fn reset_account(&mut self, address: AddressKey) { + assert!( + !self + .world + .get_debugger_backend() + .vm_runner + .blockchain_mock + .state + .account_exists(&address.to_vm_address()), + "updating existing accounts currently not supported" + ); + + self.current_address = address; + self.current_account = Account::default(); + } + + /// Starts building of a new account. + pub fn account(mut self, address_expr: A) -> Self + where + AddressKey: From, + { + self.add_current_acount(); + self.reset_account(address_expr.into()); + self + } + + /// Finished and sets all account in the blockchain mock. + fn commit_accounts(&mut self) { + self.add_current_acount(); + self.world.run_set_state_step(&self.set_state_step); + } + + /// Forces value drop and commit accounts. + pub fn commit(self) {} + + pub fn nonce(mut self, nonce: V) -> Self + where + U64Value: From, + { + self.current_account.nonce = Some(U64Value::from(nonce)); + self + } + + pub fn balance(mut self, balance_expr: V) -> Self + where + BigUintValue: From, + { + self.current_account.balance = Some(BigUintValue::from(balance_expr)); + self + } + + pub fn esdt_balance(mut self, token_id_expr: K, balance_expr: V) -> Self + where + BytesKey: From, + BigUintValue: From, + { + let token_id = BytesKey::from(token_id_expr); + let esdt_data_ref = self.get_esdt_data_or_create(&token_id); + esdt_data_ref.set_balance(0u64, balance_expr); + + self + } + + pub fn esdt_nft_balance( + mut self, + token_id_expr: K, + nonce_expr: N, + balance_expr: V, + opt_attributes_expr: Option, + ) -> Self + where + N: Clone, + BytesKey: From, + U64Value: From, + BigUintValue: From, + BytesValue: From, + { + let token_id = BytesKey::from(token_id_expr); + + let esdt_obj_ref = self + .get_esdt_data_or_create(&token_id) + .get_mut_esdt_object(); + esdt_obj_ref.set_balance(nonce_expr.clone(), balance_expr); + + if let Some(attributes_expr) = opt_attributes_expr { + esdt_obj_ref.set_token_attributes(nonce_expr, attributes_expr); + } + + self + } + + #[allow(clippy::too_many_arguments)] + pub fn esdt_nft_all_properties( + mut self, + token_id_expr: K, + nonce_expr: N, + balance_expr: V, + opt_attributes_expr: Option, + royalties_expr: N, + creator_expr: Option, + hash_expr: Option, + uris_expr: Vec, + ) -> Self + where + BytesKey: From, + U64Value: From, + BigUintValue: From, + BytesValue: From, + { + let token_id = BytesKey::from(token_id_expr); + + let esdt_obj_ref = self + .get_esdt_data_or_create(&token_id) + .get_mut_esdt_object(); + + esdt_obj_ref.set_token_all_properties( + nonce_expr, + balance_expr, + opt_attributes_expr, + royalties_expr, + creator_expr, + hash_expr, + uris_expr, + ); + + self + } + + pub fn esdt_nft_last_nonce(mut self, token_id_expr: K, last_nonce_expr: N) -> Self + where + BytesKey: From, + U64Value: From, + { + let token_id = BytesKey::from(token_id_expr); + + let esdt_obj_ref = self + .get_esdt_data_or_create(&token_id) + .get_mut_esdt_object(); + esdt_obj_ref.set_last_nonce(last_nonce_expr); + + self + } + + // TODO: Find a better way to pass roles + pub fn esdt_roles(mut self, token_id_expr: K, roles: Vec) -> Self + where + BytesKey: From, + { + let token_id = BytesKey::from(token_id_expr); + + let esdt_obj_ref = self + .get_esdt_data_or_create(&token_id) + .get_mut_esdt_object(); + esdt_obj_ref.set_roles(roles); + + self + } + + fn get_esdt_data_or_create(&mut self, token_id: &BytesKey) -> &mut Esdt { + if !self.current_account.esdt.contains_key(token_id) { + self.current_account + .esdt + .insert(token_id.clone(), Esdt::Full(EsdtObject::default())); + } + + self.current_account.esdt.get_mut(token_id).unwrap() + } + + pub fn code(mut self, code_expr: V) -> Self + where + BytesValue: From, + { + self.current_account.code = Some(BytesValue::from(code_expr)); + self + } + + pub fn owner(mut self, owner_expr: V) -> Self + where + AddressValue: From, + { + self.current_account.owner = Some(AddressValue::from(owner_expr)); + self + } +} + +impl<'w> Drop for SetStateBuilder<'w> { + fn drop(&mut self) { + self.commit_accounts(); + } +} 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 aac1952a34..d195a7600d 100644 --- a/framework/scenario/src/facade/world_tx/scenario_tx_env.rs +++ b/framework/scenario/src/facade/world_tx/scenario_tx_env.rs @@ -1,12 +1,8 @@ use std::path::PathBuf; -use multiversx_sc::types::{AnnotatedValue, ManagedAddress, ManagedBuffer, TxBaseWithEnv, TxEnv}; +use multiversx_sc::types::{ManagedAddress, ManagedBuffer, TxEnv}; -use crate::{ - api::StaticApi, - scenario_model::{TxExpect, TxResponse}, - ScenarioWorld, -}; +use crate::{api::StaticApi, scenario_model::TxExpect, ScenarioWorld}; /// Designates a tx environment suitable for running scenarios locally. pub trait ScenarioTxEnv: TxEnv { From 9549b7e327c5020a95691e30ed413e4c9010ad69 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Wed, 17 Apr 2024 18:23:02 +0300 Subject: [PATCH 3/3] check state refactor --- .../adder/tests/adder_blackbox_test.rs | 8 +++----- .../tests/crowdfunding_esdt_blackbox_test.rs | 2 +- .../scenario-tester/tests/st_blackbox_test.rs | 20 +++++++++---------- .../facade/world_tx/scenario_check_state.rs | 4 ++-- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/contracts/examples/adder/tests/adder_blackbox_test.rs b/contracts/examples/adder/tests/adder_blackbox_test.rs index 1dafca181a..4b0f740343 100644 --- a/contracts/examples/adder/tests/adder_blackbox_test.rs +++ b/contracts/examples/adder/tests/adder_blackbox_test.rs @@ -61,11 +61,9 @@ fn adder_blackbox() { .returns(ExpectValue(6u32)) .run(); - world.check_state_step( - CheckStateStep::new() - .put_account(OWNER, CheckAccount::new()) - .put_account(SC_ADDER, CheckAccount::new().check_storage("str:sum", "6")), - ); + world.check_account(OWNER); + + world.check_account(SC_ADDER).check_storage("str:sum", "6"); world.write_scenario_trace("trace1.scen.json"); } diff --git a/contracts/examples/crowdfunding-esdt/tests/crowdfunding_esdt_blackbox_test.rs b/contracts/examples/crowdfunding-esdt/tests/crowdfunding_esdt_blackbox_test.rs index cc4235704c..c3a1e383f3 100644 --- a/contracts/examples/crowdfunding-esdt/tests/crowdfunding_esdt_blackbox_test.rs +++ b/contracts/examples/crowdfunding-esdt/tests/crowdfunding_esdt_blackbox_test.rs @@ -118,7 +118,7 @@ impl CrowdfundingESDTTestState { fn check_esdt_balance(&mut self, address: AddressExpr, balance_expr: &str) { self.world - .check_state_account(address) + .check_account(address) .esdt_balance(CF_TOKEN_ID_EXPR, balance_expr); } 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 ae3e29da45..de877fb76b 100644 --- a/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs +++ b/contracts/feature-tests/scenario-tester/tests/st_blackbox_test.rs @@ -42,10 +42,10 @@ fn st_blackbox() { .commit(); world - .check_state_account(owner_address) + .check_account(owner_address) .nonce("1") .balance("100") - .check_state_account(other_address) + .check_account(other_address) .nonce("2") .balance("300") .esdt_balance("str:TOKEN-123456", "500") @@ -81,10 +81,10 @@ fn st_blackbox() { .run(); world - .check_state_account(owner_address) + .check_account(owner_address) .nonce("3") .balance("100") - .check_state_account(st_contract) + .check_account(st_contract) .check_storage("str:sum", "6") .commit(); @@ -122,10 +122,10 @@ fn set_state_test() { .commit(); world - .check_state_account(first) + .check_account(first) .nonce(1) .balance("100") - .check_state_account(second) + .check_account(second) .nonce(2) .balance("300") .esdt_balance("str:TOKEN-123456", "500") @@ -139,7 +139,7 @@ fn set_state_test() { .commit(); world - .check_state_account(third) + .check_account(third) .nonce(3) .balance("50") .esdt_nft_balance_and_attributes("str:NFT-123456", "2", "1", Some(Vec::::new())) @@ -156,10 +156,10 @@ fn set_state_test() { .esdt_balance("str:TOKEN-123456", "2"); world - .check_state_account(fourth) + .check_account(fourth) .nonce(4) .balance("400") - .check_state_account(fifth) + .check_account(fifth) .nonce(5) .balance("250") .esdt_balance("str:TOKEN-123456", "2"); @@ -171,7 +171,7 @@ fn set_state_test() { .esdt_balance("str:TOKEN-123456", "60"); world - .check_state_account(sixth) + .check_account(sixth) .nonce(6) .balance("600") .esdt_balance("str:TOKEN-123456", "60"); diff --git a/framework/scenario/src/facade/world_tx/scenario_check_state.rs b/framework/scenario/src/facade/world_tx/scenario_check_state.rs index ab54d7411f..ffb4a2754b 100644 --- a/framework/scenario/src/facade/world_tx/scenario_check_state.rs +++ b/framework/scenario/src/facade/world_tx/scenario_check_state.rs @@ -14,7 +14,7 @@ use crate::{ }; impl ScenarioWorld { - pub fn check_state_account(&mut self, address: A) -> CheckStateBuilder<'_> + pub fn check_account(&mut self, address: A) -> CheckStateBuilder<'_> where AddressKey: From, { @@ -42,7 +42,7 @@ impl<'w> CheckStateBuilder<'w> { } /// Starts building of a new account. - pub fn check_state_account(mut self, address_expr: A) -> Self + pub fn check_account(mut self, address_expr: A) -> Self where AddressKey: From, {