diff --git a/chain/vm/src/host/context/managed_type_container/handle_map.rs b/chain/vm/src/host/context/managed_type_container/handle_map.rs index 4473e9104b..f121389696 100644 --- a/chain/vm/src/host/context/managed_type_container/handle_map.rs +++ b/chain/vm/src/host/context/managed_type_container/handle_map.rs @@ -47,4 +47,8 @@ impl HandleMap { pub fn insert(&mut self, handle: RawHandle, value: V) { let _ = self.map.insert(handle, value); } + + pub fn remove_handle(&mut self, handle: RawHandle) { + let _ = self.map.remove(&handle); + } } diff --git a/chain/vm/src/host/context/managed_type_container/tx_big_float.rs b/chain/vm/src/host/context/managed_type_container/tx_big_float.rs index 3da9b0333b..002a5635b9 100644 --- a/chain/vm/src/host/context/managed_type_container/tx_big_float.rs +++ b/chain/vm/src/host/context/managed_type_container/tx_big_float.rs @@ -10,4 +10,8 @@ impl ManagedTypeContainer { pub fn bf_overwrite(&mut self, handle: RawHandle, value: f64) { self.big_float_map.insert(handle, value); } + + pub fn bf_remove(&mut self, handle: RawHandle) { + self.big_float_map.remove_handle(handle); + } } diff --git a/chain/vm/src/host/context/managed_type_container/tx_big_int.rs b/chain/vm/src/host/context/managed_type_container/tx_big_int.rs index 7930c534bb..bf2bf911c2 100644 --- a/chain/vm/src/host/context/managed_type_container/tx_big_int.rs +++ b/chain/vm/src/host/context/managed_type_container/tx_big_int.rs @@ -11,6 +11,10 @@ impl ManagedTypeContainer { self.big_int_map.insert_new_handle_raw(value) } + pub fn bi_remove(&mut self, handle: RawHandle) { + self.big_int_map.remove_handle(handle); + } + pub fn bi_overwrite(&mut self, destination: RawHandle, value: num_bigint::BigInt) { self.big_int_map.insert(destination, value); } diff --git a/chain/vm/src/host/context/managed_type_container/tx_managed_buffer.rs b/chain/vm/src/host/context/managed_type_container/tx_managed_buffer.rs index 5f8aeccf4d..0fff43c1c4 100644 --- a/chain/vm/src/host/context/managed_type_container/tx_managed_buffer.rs +++ b/chain/vm/src/host/context/managed_type_container/tx_managed_buffer.rs @@ -183,6 +183,10 @@ impl ManagedTypeContainer { num_bytes_copied } + + pub fn mb_remove(&mut self, handle: RawHandle) { + self.managed_buffer_map.remove_handle(handle); + } } pub fn handle_to_be_bytes(handle: RawHandle) -> [u8; 4] { diff --git a/chain/vm/src/host/context/managed_type_container/tx_managed_map.rs b/chain/vm/src/host/context/managed_type_container/tx_managed_map.rs index 37891b2296..2a2efff96f 100644 --- a/chain/vm/src/host/context/managed_type_container/tx_managed_map.rs +++ b/chain/vm/src/host/context/managed_type_container/tx_managed_map.rs @@ -31,4 +31,8 @@ impl ManagedTypeContainer { let mmap = self.managed_map_map.get_mut(map_handle); mmap.remove(key).unwrap_or_default() } + + pub fn mm_remove(&mut self, handle: RawHandle) { + self.managed_map_map.remove_handle(handle); + } } diff --git a/chain/vm/src/host/vm_hooks/vh_dispatcher.rs b/chain/vm/src/host/vm_hooks/vh_dispatcher.rs index ddb911418e..8e2f927796 100644 --- a/chain/vm/src/host/vm_hooks/vh_dispatcher.rs +++ b/chain/vm/src/host/vm_hooks/vh_dispatcher.rs @@ -10,7 +10,7 @@ pub(super) const RESULT_ERROR: i32 = 1; /// Dispatches messages coming via VMHooks to the underlying implementation (the VMHooksHandler). #[derive(Debug)] pub struct VMHooksDispatcher { - pub(crate) handler: VMHooksHandler, + pub handler: VMHooksHandler, } impl VMHooksDispatcher { diff --git a/chain/vm/src/host/vm_hooks/vh_handler/vh_managed_types/vh_big_float.rs b/chain/vm/src/host/vm_hooks/vh_handler/vh_managed_types/vh_big_float.rs index 254f50f427..b548f7c53c 100644 --- a/chain/vm/src/host/vm_hooks/vh_handler/vh_managed_types/vh_big_float.rs +++ b/chain/vm/src/host/vm_hooks/vh_handler/vh_managed_types/vh_big_float.rs @@ -289,4 +289,8 @@ impl VMHooksHandler { Ok(()) } + + pub fn bf_drop(&self, map_handle: RawHandle) { + self.context.m_types_lock().bf_remove(map_handle); + } } diff --git a/chain/vm/src/host/vm_hooks/vh_handler/vh_managed_types/vh_big_int.rs b/chain/vm/src/host/vm_hooks/vh_handler/vh_managed_types/vh_big_int.rs index 8341b1135c..d605c516ac 100644 --- a/chain/vm/src/host/vm_hooks/vh_handler/vh_managed_types/vh_big_int.rs +++ b/chain/vm/src/host/vm_hooks/vh_handler/vh_managed_types/vh_big_int.rs @@ -311,4 +311,8 @@ impl VMHooksHandler { Ok(()) } + + pub fn bi_drop(&self, map_handle: RawHandle) { + self.context.m_types_lock().bi_remove(map_handle); + } } diff --git a/chain/vm/src/host/vm_hooks/vh_handler/vh_managed_types/vh_managed_buffer.rs b/chain/vm/src/host/vm_hooks/vh_handler/vh_managed_types/vh_managed_buffer.rs index 4797df14a3..baa2439b8f 100644 --- a/chain/vm/src/host/vm_hooks/vh_handler/vh_managed_types/vh_managed_buffer.rs +++ b/chain/vm/src/host/vm_hooks/vh_handler/vh_managed_types/vh_managed_buffer.rs @@ -210,4 +210,8 @@ impl VMHooksHandler { .mb_set(dest_handle, encoded.into_bytes()); Ok(()) } + + pub fn mb_drop(&self, handle: RawHandle) { + self.context.m_types_lock().mb_remove(handle); + } } diff --git a/chain/vm/src/host/vm_hooks/vh_handler/vh_managed_types/vh_managed_map.rs b/chain/vm/src/host/vm_hooks/vh_handler/vh_managed_types/vh_managed_map.rs index 25280af635..1584a6063d 100644 --- a/chain/vm/src/host/vm_hooks/vh_handler/vh_managed_types/vh_managed_map.rs +++ b/chain/vm/src/host/vm_hooks/vh_handler/vh_managed_types/vh_managed_map.rs @@ -50,4 +50,8 @@ impl VMHooksHandler { .m_types_lock() .mm_contains(map_handle, key.as_slice()) } + + pub fn mm_drop(&self, map_handle: RawHandle) { + self.context.m_types_lock().mm_remove(map_handle); + } } diff --git a/contracts/feature-tests/basic-features/tests/basic_features_managed_buffer_test.rs b/contracts/feature-tests/basic-features/tests/basic_features_managed_buffer_test.rs index 88320b17f6..e775c5e167 100644 --- a/contracts/feature-tests/basic-features/tests/basic_features_managed_buffer_test.rs +++ b/contracts/feature-tests/basic-features/tests/basic_features_managed_buffer_test.rs @@ -15,3 +15,10 @@ fn test_managed_address_zero() { let result = bf.managed_address_zero(); assert_eq!(ManagedAddress::zero(), result); } + +#[test] +fn test_managed_buffer_destructor() { + let my_buffer = ManagedBuffer::::from(b"my buffer"); + assert_eq!(my_buffer, managed_buffer!(b"my buffer")); + drop(my_buffer); +} diff --git a/framework/base/src/api/managed_types/managed_type_api_impl.rs b/framework/base/src/api/managed_types/managed_type_api_impl.rs index 024ed79537..64fc31d81e 100644 --- a/framework/base/src/api/managed_types/managed_type_api_impl.rs +++ b/framework/base/src/api/managed_types/managed_type_api_impl.rs @@ -59,4 +59,10 @@ pub trait ManagedTypeApiImpl: fn get_token_ticker_len(&self, token_id_len: usize) -> usize { token_identifier_util::get_token_ticker_len(token_id_len) } + + fn drop_managed_buffer(&self, _handle: Self::ManagedBufferHandle) {} + fn drop_big_float(&self, _handle: Self::BigFloatHandle) {} + fn drop_big_int(&self, _handle: Self::BigIntHandle) {} + fn drop_elliptic_curve(&self, _handle: Self::EllipticCurveHandle) {} + fn drop_managed_map(&self, _handle: Self::ManagedMapHandle) {} } diff --git a/framework/base/src/types/managed/basic/managed_buffer.rs b/framework/base/src/types/managed/basic/managed_buffer.rs index 79bb96f4a8..68b6a13192 100644 --- a/framework/base/src/types/managed/basic/managed_buffer.rs +++ b/framework/base/src/types/managed/basic/managed_buffer.rs @@ -425,6 +425,13 @@ impl Clone for ManagedBuffer { } } +impl Drop for ManagedBuffer { + fn drop(&mut self) { + // TODO: enable, after fixing all ownership issues + // M::managed_type_impl().drop_managed_buffer(self.handle.clone()); + } +} + impl PartialEq for ManagedBuffer { #[inline] fn eq(&self, other: &Self) -> bool { diff --git a/framework/scenario/src/api/impl_vh/debug_api.rs b/framework/scenario/src/api/impl_vh/debug_api.rs index 3076d6a24a..c7af196f3b 100644 --- a/framework/scenario/src/api/impl_vh/debug_api.rs +++ b/framework/scenario/src/api/impl_vh/debug_api.rs @@ -1,5 +1,5 @@ use multiversx_chain_vm::{ - executor::{VMHooks, VMHooksEarlyExit}, + executor::VMHooksEarlyExit, host::context::TxContextRef, host::vm_hooks::{TxVMHooksContext, VMHooksDispatcher}, }; @@ -7,6 +7,7 @@ use multiversx_sc::{chain_core::types::ReturnCode, err_msg}; use crate::executor::debug::{ ContractDebugInstance, ContractDebugInstanceState, ContractDebugStack, StaticVarData, + VMHooksDebugger, }; use super::{DebugHandle, VMHooksApi, VMHooksApiBackend}; @@ -19,7 +20,7 @@ impl VMHooksApiBackend for DebugApiBackend { fn with_vm_hooks(f: F) -> R where - F: FnOnce(&mut dyn VMHooks) -> Result, + F: FnOnce(&mut dyn VMHooksDebugger) -> Result, { let instance = ContractDebugStack::static_peek(); let tx_context_ref = instance.tx_context_ref.clone(); @@ -30,7 +31,7 @@ impl VMHooksApiBackend for DebugApiBackend { fn with_vm_hooks_ctx_1(handle: Self::HandleType, f: F) -> R where - F: FnOnce(&mut dyn VMHooks) -> Result, + F: FnOnce(&mut dyn VMHooksDebugger) -> Result, { let tx_context_ref = TxContextRef(handle.context.clone()); let vh_context = TxVMHooksContext::new(tx_context_ref, ContractDebugInstanceState); @@ -40,7 +41,7 @@ impl VMHooksApiBackend for DebugApiBackend { fn with_vm_hooks_ctx_2(handle1: Self::HandleType, handle2: Self::HandleType, f: F) -> R where - F: FnOnce(&mut dyn VMHooks) -> Result, + F: FnOnce(&mut dyn VMHooksDebugger) -> Result, { assert_handles_on_same_context(&handle1, &handle2); Self::with_vm_hooks_ctx_1(handle1, f) @@ -53,7 +54,7 @@ impl VMHooksApiBackend for DebugApiBackend { f: F, ) -> R where - F: FnOnce(&mut dyn VMHooks) -> Result, + F: FnOnce(&mut dyn VMHooksDebugger) -> Result, { assert_handles_on_same_context(&handle1, &handle2); assert_handles_on_same_context(&handle1, &handle3); diff --git a/framework/scenario/src/api/impl_vh/single_tx_api.rs b/framework/scenario/src/api/impl_vh/single_tx_api.rs index 00b0299143..9357f5b094 100644 --- a/framework/scenario/src/api/impl_vh/single_tx_api.rs +++ b/framework/scenario/src/api/impl_vh/single_tx_api.rs @@ -1,13 +1,12 @@ use std::sync::Mutex; use multiversx_chain_vm::{ - blockchain::state::AccountData, executor::VMHooks, host::vm_hooks::VMHooksDispatcher, - types::VMAddress, + blockchain::state::AccountData, host::vm_hooks::VMHooksDispatcher, types::VMAddress, }; use multiversx_chain_vm_executor::VMHooksEarlyExit; use multiversx_sc::api::RawHandle; -use crate::executor::debug::{ContractDebugInstanceState, StaticVarData}; +use crate::executor::debug::{ContractDebugInstanceState, StaticVarData, VMHooksDebugger}; use super::{SingleTxApiData, SingleTxApiVMHooksContext, VMHooksApi, VMHooksApiBackend}; @@ -25,7 +24,7 @@ impl VMHooksApiBackend for SingleTxApiBackend { fn with_vm_hooks(f: F) -> R where - F: FnOnce(&mut dyn VMHooks) -> Result, + F: FnOnce(&mut dyn VMHooksDebugger) -> Result, { SINGLE_TX_API_VH_CELL.with(|cell| { let vh_context = cell.lock().unwrap().clone(); diff --git a/framework/scenario/src/api/impl_vh/static_api.rs b/framework/scenario/src/api/impl_vh/static_api.rs index 8155172b22..1e5e61b140 100644 --- a/framework/scenario/src/api/impl_vh/static_api.rs +++ b/framework/scenario/src/api/impl_vh/static_api.rs @@ -1,9 +1,9 @@ -use multiversx_chain_vm::{executor::VMHooks, host::vm_hooks::VMHooksDispatcher}; +use multiversx_chain_vm::host::vm_hooks::VMHooksDispatcher; use multiversx_chain_vm_executor::VMHooksEarlyExit; use multiversx_sc::{api::RawHandle, types::Address}; use std::sync::Mutex; -use crate::executor::debug::{ContractDebugInstanceState, StaticVarData}; +use crate::executor::debug::{ContractDebugInstanceState, StaticVarData, VMHooksDebugger}; use super::{StaticApiVMHooksContext, VMHooksApi, VMHooksApiBackend}; @@ -25,7 +25,7 @@ impl VMHooksApiBackend for StaticApiBackend { fn with_vm_hooks(f: F) -> R where - F: FnOnce(&mut dyn VMHooks) -> Result, + F: FnOnce(&mut dyn VMHooksDebugger) -> Result, { STATIC_API_VH_CELL.with(|vh_mutex| { let mut vh = vh_mutex.lock().unwrap(); diff --git a/framework/scenario/src/api/impl_vh/vm_hooks_api.rs b/framework/scenario/src/api/impl_vh/vm_hooks_api.rs index 0384b5f8e1..a22fec08c5 100644 --- a/framework/scenario/src/api/impl_vh/vm_hooks_api.rs +++ b/framework/scenario/src/api/impl_vh/vm_hooks_api.rs @@ -1,10 +1,10 @@ -use crate::executor::debug::StaticVarData; +use crate::executor::debug::{StaticVarData, VMHooksDebugger}; use super::VMHooksApiBackend; use std::marker::PhantomData; -use multiversx_chain_vm::executor::{MemPtr, VMHooks}; +use multiversx_chain_vm::executor::MemPtr; use multiversx_chain_vm_executor::VMHooksEarlyExit; use multiversx_sc::api::{HandleTypeInfo, ManagedBufferApiImpl}; @@ -23,7 +23,7 @@ impl VMHooksApi { /// All communication with the VM happens via this method. pub fn with_vm_hooks(&self, f: F) -> R where - F: FnOnce(&mut dyn VMHooks) -> Result, + F: FnOnce(&mut dyn VMHooksDebugger) -> Result, { VHB::with_vm_hooks(f) } @@ -31,7 +31,7 @@ impl VMHooksApi { /// Works with the VM hooks given by the context of 1 handle. pub fn with_vm_hooks_ctx_1(&self, handle: &VHB::HandleType, f: F) -> R where - F: FnOnce(&mut dyn VMHooks) -> Result, + F: FnOnce(&mut dyn VMHooksDebugger) -> Result, { VHB::with_vm_hooks_ctx_1(handle.clone(), f) } @@ -44,7 +44,7 @@ impl VMHooksApi { f: F, ) -> R where - F: FnOnce(&mut dyn VMHooks) -> Result, + F: FnOnce(&mut dyn VMHooksDebugger) -> Result, { VHB::with_vm_hooks_ctx_2(handle1.clone(), handle2.clone(), f) } @@ -58,7 +58,7 @@ impl VMHooksApi { f: F, ) -> R where - F: FnOnce(&mut dyn VMHooks) -> Result, + F: FnOnce(&mut dyn VMHooksDebugger) -> Result, { VHB::with_vm_hooks_ctx_3(handle1.clone(), handle2.clone(), handle3.clone(), f) } diff --git a/framework/scenario/src/api/impl_vh/vm_hooks_backend.rs b/framework/scenario/src/api/impl_vh/vm_hooks_backend.rs index a54d5d0ae3..80b2c8f960 100644 --- a/framework/scenario/src/api/impl_vh/vm_hooks_backend.rs +++ b/framework/scenario/src/api/impl_vh/vm_hooks_backend.rs @@ -1,8 +1,7 @@ -use multiversx_chain_vm::executor::VMHooks; use multiversx_chain_vm_executor::VMHooksEarlyExit; use multiversx_sc::api::HandleConstraints; -use crate::executor::debug::StaticVarData; +use crate::executor::debug::{StaticVarData, VMHooksDebugger}; pub trait VMHooksApiBackend: Clone + Send + Sync + 'static { /// We use a single handle type for all handles. @@ -11,18 +10,18 @@ pub trait VMHooksApiBackend: Clone + Send + Sync + 'static { /// All communication with the VM happens via this method. fn with_vm_hooks(f: F) -> R where - F: FnOnce(&mut dyn VMHooks) -> Result; + F: FnOnce(&mut dyn VMHooksDebugger) -> Result; fn with_vm_hooks_ctx_1(_handle: Self::HandleType, f: F) -> R where - F: FnOnce(&mut dyn VMHooks) -> Result, + F: FnOnce(&mut dyn VMHooksDebugger) -> Result, { Self::with_vm_hooks(f) } fn with_vm_hooks_ctx_2(_handle1: Self::HandleType, _handle2: Self::HandleType, f: F) -> R where - F: FnOnce(&mut dyn VMHooks) -> Result, + F: FnOnce(&mut dyn VMHooksDebugger) -> Result, { Self::with_vm_hooks(f) } @@ -34,7 +33,7 @@ pub trait VMHooksApiBackend: Clone + Send + Sync + 'static { f: F, ) -> R where - F: FnOnce(&mut dyn VMHooks) -> Result, + F: FnOnce(&mut dyn VMHooksDebugger) -> Result, { Self::with_vm_hooks(f) } diff --git a/framework/scenario/src/api/managed_type_api_vh.rs b/framework/scenario/src/api/managed_type_api_vh.rs index 62c9f4e4f6..e3a547ba6b 100644 --- a/framework/scenario/src/api/managed_type_api_vh.rs +++ b/framework/scenario/src/api/managed_type_api_vh.rs @@ -127,4 +127,28 @@ impl ManagedTypeApiImpl for VMHooksApi { }); i32_to_bool(result) } + + fn drop_managed_buffer(&self, handle: Self::ManagedBufferHandle) { + self.with_vm_hooks_ctx_1(&handle, |vh| { + vh.drop_managed_buffer(handle.get_raw_handle_unchecked()) + }); + } + fn drop_big_float(&self, handle: Self::BigFloatHandle) { + self.with_vm_hooks_ctx_1(&handle, |vh| { + vh.drop_big_float(handle.get_raw_handle_unchecked()) + }); + } + fn drop_big_int(&self, handle: Self::BigIntHandle) { + self.with_vm_hooks_ctx_1(&handle, |vh| { + vh.drop_big_int(handle.get_raw_handle_unchecked()) + }); + } + fn drop_elliptic_curve(&self, _handle: Self::EllipticCurveHandle) { + // TODO + } + fn drop_managed_map(&self, handle: Self::ManagedMapHandle) { + self.with_vm_hooks_ctx_1(&handle, |vh| { + vh.drop_managed_map(handle.get_raw_handle_unchecked()) + }); + } } diff --git a/framework/scenario/src/executor/debug.rs b/framework/scenario/src/executor/debug.rs index 1d8f31a04b..a2890d240e 100644 --- a/framework/scenario/src/executor/debug.rs +++ b/framework/scenario/src/executor/debug.rs @@ -9,6 +9,7 @@ mod contract_debug_whitebox_lambda; mod contract_map; mod static_var_data; mod tx_static_vars; +mod vm_hooks_debugger; pub use catch_tx_panic::catch_tx_panic; pub use contract_container::{ContractContainer, ContractContainerRef}; @@ -21,3 +22,4 @@ pub use contract_debug_whitebox_lambda::ContractDebugWhiteboxLambda; pub use contract_map::{ContractMap, ContractMapRef}; pub use static_var_data::StaticVarData; pub use tx_static_vars::TxStaticVars; +pub use vm_hooks_debugger::VMHooksDebugger; diff --git a/framework/scenario/src/executor/debug/vm_hooks_debugger.rs b/framework/scenario/src/executor/debug/vm_hooks_debugger.rs new file mode 100644 index 0000000000..86194eae43 --- /dev/null +++ b/framework/scenario/src/executor/debug/vm_hooks_debugger.rs @@ -0,0 +1,37 @@ +use multiversx_chain_vm::host::vm_hooks::{VMHooksContext, VMHooksDispatcher}; +use multiversx_chain_vm_executor::{VMHooks, VMHooksEarlyExit}; + +pub trait VMHooksDebugger: VMHooks { + fn drop_managed_buffer(&self, handle: i32) -> Result<(), VMHooksEarlyExit>; + fn drop_big_float(&self, handle: i32) -> Result<(), VMHooksEarlyExit>; + fn drop_big_int(&self, handle: i32) -> Result<(), VMHooksEarlyExit>; + fn drop_elliptic_curve(&self, handle: i32) -> Result<(), VMHooksEarlyExit>; + fn drop_managed_map(&self, handle: i32) -> Result<(), VMHooksEarlyExit>; +} + +impl VMHooksDebugger for VMHooksDispatcher { + fn drop_managed_buffer(&self, handle: i32) -> Result<(), VMHooksEarlyExit> { + self.handler.mb_drop(handle); + Ok(()) + } + + fn drop_big_float(&self, handle: i32) -> Result<(), VMHooksEarlyExit> { + self.handler.bf_drop(handle); + Ok(()) + } + + fn drop_big_int(&self, handle: i32) -> Result<(), VMHooksEarlyExit> { + self.handler.bi_drop(handle); + Ok(()) + } + + fn drop_elliptic_curve(&self, _handle: i32) -> Result<(), VMHooksEarlyExit> { + // TODO: not implemented + Ok(()) + } + + fn drop_managed_map(&self, handle: i32) -> Result<(), VMHooksEarlyExit> { + self.handler.mm_drop(handle); + Ok(()) + } +}