diff --git a/framework/base/src/api/managed_types.rs b/framework/base/src/api/managed_types.rs index 3562020b95..1322ede5ee 100644 --- a/framework/base/src/api/managed_types.rs +++ b/framework/base/src/api/managed_types.rs @@ -8,6 +8,7 @@ mod managed_map_api; mod managed_type_api; mod managed_type_api_impl; mod static_var_api; +mod static_var_api_flags; mod token_identifier_util; pub use big_float_api::*; @@ -19,3 +20,4 @@ pub use managed_map_api::*; pub use managed_type_api::*; pub use managed_type_api_impl::*; pub use static_var_api::*; +pub use static_var_api_flags::StaticVarApiFlags; diff --git a/framework/base/src/api/managed_types/static_var_api.rs b/framework/base/src/api/managed_types/static_var_api.rs index 8eaf474ef3..9044cd6b06 100644 --- a/framework/base/src/api/managed_types/static_var_api.rs +++ b/framework/base/src/api/managed_types/static_var_api.rs @@ -1,6 +1,6 @@ use crate::types::LockableStaticBuffer; -use super::RawHandle; +use super::{RawHandle, StaticVarApiFlags}; pub trait StaticVarApi { type StaticVarApiImpl: StaticVarApiImpl; @@ -24,13 +24,21 @@ pub trait StaticVarApiImpl { fn get_num_arguments(&self) -> i32; - fn set_call_value_egld_handle(&self, handle: RawHandle); - - fn get_call_value_egld_handle(&self) -> RawHandle; - - fn set_call_value_multi_esdt_handle(&self, handle: RawHandle); - - fn get_call_value_multi_esdt_handle(&self) -> RawHandle; + fn set_flags(&self, flags: StaticVarApiFlags); + + fn get_flags(&self) -> StaticVarApiFlags; + + /// Returns true if the flag is set, false if is default (false). + /// + /// If the flag is unset (false), will set it. + fn flag_is_set_or_update(&self, flag: StaticVarApiFlags) -> bool { + let mut current_flags = self.get_flags(); + let contains_flag = current_flags.check_and_set(flag); + if !contains_flag { + self.set_flags(current_flags); + } + contains_flag + } fn is_scaling_factor_cached(&self, decimals: usize) -> bool; diff --git a/framework/base/src/api/managed_types/static_var_api_flags.rs b/framework/base/src/api/managed_types/static_var_api_flags.rs new file mode 100644 index 0000000000..1c9e153e69 --- /dev/null +++ b/framework/base/src/api/managed_types/static_var_api_flags.rs @@ -0,0 +1,53 @@ +use bitflags::bitflags; + +bitflags! { + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + pub struct StaticVarApiFlags: u8 { + const NONE = 0b00000000; + const CALL_VALUE_EGLD_INITIALIZED = 0b00000001; + const CALL_VALUE_EGLD_MULTI_INITIALIZED = 0b00000010; + const CALL_VALUE_MULTI_ESDT_INITIALIZED = 0b00000100; + const CALL_VALUE_ALL_INITIALIZED = 0b00001000; + } +} + +impl StaticVarApiFlags { + pub fn check_and_set(&mut self, other: StaticVarApiFlags) -> bool { + let contains_flag = self.contains(other); + if !contains_flag { + *self |= other; + } + contains_flag + } +} + +#[cfg(test)] +pub mod tests { + use super::StaticVarApiFlags; + + #[test] + fn test_check_and_set() { + let mut current = StaticVarApiFlags::NONE; + + assert!(current.check_and_set(StaticVarApiFlags::NONE)); + assert_eq!(current, StaticVarApiFlags::NONE); + + assert!(!current.check_and_set(StaticVarApiFlags::CALL_VALUE_EGLD_INITIALIZED)); + assert_eq!(current, StaticVarApiFlags::CALL_VALUE_EGLD_INITIALIZED); + assert!(current.check_and_set(StaticVarApiFlags::CALL_VALUE_EGLD_INITIALIZED)); + assert_eq!(current, StaticVarApiFlags::CALL_VALUE_EGLD_INITIALIZED); + + assert!(!current.check_and_set(StaticVarApiFlags::CALL_VALUE_ALL_INITIALIZED)); + assert_eq!( + current, + StaticVarApiFlags::CALL_VALUE_EGLD_INITIALIZED + | StaticVarApiFlags::CALL_VALUE_ALL_INITIALIZED + ); + assert!(current.check_and_set(StaticVarApiFlags::CALL_VALUE_ALL_INITIALIZED)); + assert_eq!( + current, + StaticVarApiFlags::CALL_VALUE_EGLD_INITIALIZED + | StaticVarApiFlags::CALL_VALUE_ALL_INITIALIZED + ); + } +} diff --git a/framework/base/src/api/uncallable/static_var_api_uncallable.rs b/framework/base/src/api/uncallable/static_var_api_uncallable.rs index 1da3c772cf..005a302e53 100644 --- a/framework/base/src/api/uncallable/static_var_api_uncallable.rs +++ b/framework/base/src/api/uncallable/static_var_api_uncallable.rs @@ -1,5 +1,5 @@ use crate::{ - api::{RawHandle, StaticVarApi, StaticVarApiImpl}, + api::{RawHandle, StaticVarApi, StaticVarApiFlags, StaticVarApiImpl}, types::LockableStaticBuffer, }; @@ -41,19 +41,11 @@ impl StaticVarApiImpl for UncallableApi { unreachable!() } - fn set_call_value_egld_handle(&self, _handle: RawHandle) { + fn set_flags(&self, _flags: StaticVarApiFlags) { unreachable!() } - fn get_call_value_egld_handle(&self) -> RawHandle { - unreachable!() - } - - fn set_call_value_multi_esdt_handle(&self, _handle: RawHandle) { - unreachable!() - } - - fn get_call_value_multi_esdt_handle(&self) -> RawHandle { + fn get_flags(&self) -> StaticVarApiFlags { unreachable!() } diff --git a/framework/base/src/contract_base/wrappers/call_value_wrapper.rs b/framework/base/src/contract_base/wrappers/call_value_wrapper.rs index 3fb85e1658..1edb635a9d 100644 --- a/framework/base/src/contract_base/wrappers/call_value_wrapper.rs +++ b/framework/base/src/contract_base/wrappers/call_value_wrapper.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use crate::{ api::{ const_handles, use_raw_handle, CallValueApi, CallValueApiImpl, ErrorApi, ErrorApiImpl, - HandleConstraints, ManagedTypeApi, StaticVarApiImpl, + ManagedTypeApi, StaticVarApiFlags, StaticVarApiImpl, }, err_msg, types::{ @@ -34,11 +34,10 @@ where /// Retrieves the EGLD call value from the VM. /// Will return 0 in case of an ESDT transfer (cannot have both EGLD and ESDT transfer simultaneously). pub fn egld_value(&self) -> ManagedRef<'static, A, BigUint> { - let mut call_value_handle: A::BigIntHandle = - use_raw_handle(A::static_var_api_impl().get_call_value_egld_handle()); - if call_value_handle == const_handles::UNINITIALIZED_HANDLE { - call_value_handle = use_raw_handle(const_handles::CALL_VALUE_EGLD); - A::static_var_api_impl().set_call_value_egld_handle(call_value_handle.get_raw_handle()); + let call_value_handle: A::BigIntHandle = use_raw_handle(const_handles::CALL_VALUE_EGLD); + if !A::static_var_api_impl() + .flag_is_set_or_update(StaticVarApiFlags::CALL_VALUE_EGLD_INITIALIZED) + { A::call_value_api_impl().load_egld_value(call_value_handle.clone()); } unsafe { ManagedRef::wrap_handle(call_value_handle) } @@ -55,12 +54,11 @@ where /// Will return 0 results if nothing was transfered, or just EGLD. /// Fully managed underlying types, very efficient. pub fn all_esdt_transfers(&self) -> ManagedRef<'static, A, ManagedVec>> { - let mut call_value_handle: A::ManagedBufferHandle = - use_raw_handle(A::static_var_api_impl().get_call_value_multi_esdt_handle()); - if call_value_handle == const_handles::UNINITIALIZED_HANDLE { - call_value_handle = use_raw_handle(const_handles::CALL_VALUE_MULTI_ESDT); - A::static_var_api_impl() - .set_call_value_multi_esdt_handle(call_value_handle.get_raw_handle()); + let call_value_handle: A::ManagedBufferHandle = + use_raw_handle(const_handles::CALL_VALUE_MULTI_ESDT); + if !A::static_var_api_impl() + .flag_is_set_or_update(StaticVarApiFlags::CALL_VALUE_MULTI_ESDT_INITIALIZED) + { A::call_value_api_impl().load_all_esdt_transfers(call_value_handle.clone()); } unsafe { ManagedRef::wrap_handle(call_value_handle) } diff --git a/framework/scenario/src/api/local_api_vh/static_var_api_vh.rs b/framework/scenario/src/api/local_api_vh/static_var_api_vh.rs index e72ae45f74..903094279e 100644 --- a/framework/scenario/src/api/local_api_vh/static_var_api_vh.rs +++ b/framework/scenario/src/api/local_api_vh/static_var_api_vh.rs @@ -1,6 +1,6 @@ use crate::api::{VMHooksApi, VMHooksApiBackend}; use multiversx_sc::{ - api::{use_raw_handle, RawHandle, StaticVarApi, StaticVarApiImpl}, + api::{RawHandle, StaticVarApi, StaticVarApiFlags, StaticVarApiImpl}, types::LockableStaticBuffer, }; @@ -55,30 +55,14 @@ impl StaticVarApiImpl for VMHooksApi { self.with_static_data(|data| data.static_vars_cell.borrow().num_arguments) } - fn set_call_value_egld_handle(&self, handle: RawHandle) { + fn set_flags(&self, flags: StaticVarApiFlags) { self.with_static_data(|data| { - data.static_vars_cell.borrow_mut().call_value_egld_handle = handle; + data.static_vars_cell.borrow_mut().flags = flags; }) } - fn get_call_value_egld_handle(&self) -> RawHandle { - self.with_static_data(|data| { - use_raw_handle(data.static_vars_cell.borrow().call_value_egld_handle) - }) - } - - fn set_call_value_multi_esdt_handle(&self, handle: RawHandle) { - self.with_static_data(|data| { - data.static_vars_cell - .borrow_mut() - .call_value_multi_esdt_handle = handle; - }) - } - - fn get_call_value_multi_esdt_handle(&self) -> RawHandle { - self.with_static_data(|data| { - use_raw_handle(data.static_vars_cell.borrow().call_value_multi_esdt_handle) - }) + fn get_flags(&self) -> StaticVarApiFlags { + self.with_static_data(|data| data.static_vars_cell.borrow().flags) } fn is_scaling_factor_cached(&self, decimals: usize) -> bool { diff --git a/framework/scenario/src/debug_executor/tx_static_vars.rs b/framework/scenario/src/debug_executor/tx_static_vars.rs index 88277694c4..3468d14da6 100644 --- a/framework/scenario/src/debug_executor/tx_static_vars.rs +++ b/framework/scenario/src/debug_executor/tx_static_vars.rs @@ -1,13 +1,13 @@ -use multiversx_sc::api::{const_handles, RawHandle}; +use multiversx_sc::api::{const_handles, RawHandle, StaticVarApiFlags}; #[derive(Debug)] pub struct TxStaticVars { pub external_view_target_address_handle: RawHandle, pub next_handle: RawHandle, pub num_arguments: i32, - pub call_value_egld_handle: RawHandle, - pub call_value_multi_esdt_handle: RawHandle, - //vec of true/false, true if bit from handle = scaling_start + index is not empty + pub flags: StaticVarApiFlags, + + /// Vec of true/false, true if bit from handle = scaling_start + index is not empty pub scaling_factor_init: [bool; const_handles::SCALING_FACTOR_LENGTH], } @@ -17,9 +17,8 @@ impl Default for TxStaticVars { external_view_target_address_handle: 0, next_handle: const_handles::NEW_HANDLE_START_FROM, num_arguments: -1, - call_value_egld_handle: const_handles::UNINITIALIZED_HANDLE, - call_value_multi_esdt_handle: const_handles::UNINITIALIZED_HANDLE, scaling_factor_init: [false; const_handles::SCALING_FACTOR_LENGTH], + flags: StaticVarApiFlags::NONE, } } } diff --git a/framework/wasm-adapter/src/api/managed_types/static_var_api_node.rs b/framework/wasm-adapter/src/api/managed_types/static_var_api_node.rs index 501d53d68f..3c6b19996f 100644 --- a/framework/wasm-adapter/src/api/managed_types/static_var_api_node.rs +++ b/framework/wasm-adapter/src/api/managed_types/static_var_api_node.rs @@ -1,5 +1,5 @@ use multiversx_sc::{ - api::{const_handles, RawHandle, StaticVarApi, StaticVarApiImpl}, + api::{const_handles, RawHandle, StaticVarApi, StaticVarApiFlags, StaticVarApiImpl}, types::LockableStaticBuffer, }; @@ -9,8 +9,7 @@ static mut STATIC_BUFFER: LockableStaticBuffer = LockableStaticBuffer::new(); static mut EXTERNAL_VIEW_TARGET_ADDRESS_HANDLE: i32 = 0; static mut NEXT_HANDLE: i32 = const_handles::NEW_HANDLE_START_FROM; static mut NUM_ARGUMENTS: i32 = 0; -static mut CALL_VALUE_EGLD_HANDLE: i32 = const_handles::UNINITIALIZED_HANDLE; -static mut CALL_VALUE_MULTI_ESDT_HANDLE: i32 = const_handles::UNINITIALIZED_HANDLE; +static mut FLAGS: StaticVarApiFlags = StaticVarApiFlags::NONE; static mut SCALING_FACTOR_INIT: [bool; const_handles::SCALING_FACTOR_LENGTH] = [false; const_handles::SCALING_FACTOR_LENGTH]; @@ -62,24 +61,14 @@ impl StaticVarApiImpl for VmApiImpl { unsafe { NUM_ARGUMENTS } } - fn set_call_value_egld_handle(&self, handle: RawHandle) { + fn set_flags(&self, flags: StaticVarApiFlags) { unsafe { - CALL_VALUE_EGLD_HANDLE = handle; + FLAGS = flags; } } - fn get_call_value_egld_handle(&self) -> RawHandle { - unsafe { CALL_VALUE_EGLD_HANDLE } - } - - fn set_call_value_multi_esdt_handle(&self, handle: RawHandle) { - unsafe { - CALL_VALUE_MULTI_ESDT_HANDLE = handle; - } - } - - fn get_call_value_multi_esdt_handle(&self) -> RawHandle { - unsafe { CALL_VALUE_MULTI_ESDT_HANDLE } + fn get_flags(&self) -> StaticVarApiFlags { + unsafe { FLAGS } } fn is_scaling_factor_cached(&self, decimals: usize) -> bool {