diff --git a/chain/vm/src/tx_mock/tx_managed_types/handle_map.rs b/chain/vm/src/tx_mock/tx_managed_types/handle_map.rs index 4473e9104b..f121389696 100644 --- a/chain/vm/src/tx_mock/tx_managed_types/handle_map.rs +++ b/chain/vm/src/tx_mock/tx_managed_types/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/tx_mock/tx_managed_types/tx_big_float.rs b/chain/vm/src/tx_mock/tx_managed_types/tx_big_float.rs index 5152ae9ada..dd69653091 100644 --- a/chain/vm/src/tx_mock/tx_managed_types/tx_big_float.rs +++ b/chain/vm/src/tx_mock/tx_managed_types/tx_big_float.rs @@ -10,4 +10,8 @@ impl TxManagedTypes { 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/tx_mock/tx_managed_types/tx_big_int.rs b/chain/vm/src/tx_mock/tx_managed_types/tx_big_int.rs index 510dee9a51..dabee068e9 100644 --- a/chain/vm/src/tx_mock/tx_managed_types/tx_big_int.rs +++ b/chain/vm/src/tx_mock/tx_managed_types/tx_big_int.rs @@ -11,6 +11,10 @@ impl TxManagedTypes { 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/tx_mock/tx_managed_types/tx_managed_buffer.rs b/chain/vm/src/tx_mock/tx_managed_types/tx_managed_buffer.rs index ba43dde71f..3357f34691 100644 --- a/chain/vm/src/tx_mock/tx_managed_types/tx_managed_buffer.rs +++ b/chain/vm/src/tx_mock/tx_managed_types/tx_managed_buffer.rs @@ -165,6 +165,10 @@ impl TxManagedTypes { self.mb_append_bytes(dest_handle, &handle_to_be_bytes(amount_handle)[..]); } } + + 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/tx_mock/tx_managed_types/tx_managed_map.rs b/chain/vm/src/tx_mock/tx_managed_types/tx_managed_map.rs index 1a61d6de66..fec9116f2d 100644 --- a/chain/vm/src/tx_mock/tx_managed_types/tx_managed_map.rs +++ b/chain/vm/src/tx_mock/tx_managed_types/tx_managed_map.rs @@ -31,4 +31,8 @@ impl TxManagedTypes { 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/vm_hooks/vh_dispatcher.rs b/chain/vm/src/vm_hooks/vh_dispatcher.rs index 1af9bfbb6a..70f257036c 100644 --- a/chain/vm/src/vm_hooks/vh_dispatcher.rs +++ b/chain/vm/src/vm_hooks/vh_dispatcher.rs @@ -9,7 +9,7 @@ use super::VMHooksHandler; /// Dispatches messages coming via VMHooks to the underlying implementation (the VMHooksHandler). #[derive(Debug)] pub struct VMHooksDispatcher { - handler: Box, + pub handler: Box, } impl VMHooksDispatcher { diff --git a/chain/vm/src/vm_hooks/vh_handler/vh_managed_types/vh_big_float.rs b/chain/vm/src/vm_hooks/vh_handler/vh_managed_types/vh_big_float.rs index 4c2c06b49a..952190a222 100644 --- a/chain/vm/src/vm_hooks/vh_handler/vh_managed_types/vh_big_float.rs +++ b/chain/vm/src/vm_hooks/vh_handler/vh_managed_types/vh_big_float.rs @@ -177,4 +177,8 @@ pub trait VMHooksBigFloat: VMHooksHandlerSource + VMHooksError { fn bf_get_const_e(&self, dest: RawHandle) { self.m_types_lock().bf_overwrite(dest, std::f64::consts::E); } + + fn bf_drop(&self, map_handle: RawHandle) { + self.m_types_lock().bf_remove(map_handle); + } } diff --git a/chain/vm/src/vm_hooks/vh_handler/vh_managed_types/vh_big_int.rs b/chain/vm/src/vm_hooks/vh_handler/vh_managed_types/vh_big_int.rs index a541a426c5..31d93e2be3 100644 --- a/chain/vm/src/vm_hooks/vh_handler/vh_managed_types/vh_big_int.rs +++ b/chain/vm/src/vm_hooks/vh_handler/vh_managed_types/vh_big_int.rs @@ -160,4 +160,8 @@ pub trait VMHooksBigInt: VMHooksHandlerSource + VMHooksError { let result = bi_x.shl(bits); self.m_types_lock().bi_overwrite(dest, result); } + + fn bi_drop(&self, map_handle: RawHandle) { + self.m_types_lock().bi_remove(map_handle); + } } diff --git a/chain/vm/src/vm_hooks/vh_handler/vh_managed_types/vh_managed_buffer.rs b/chain/vm/src/vm_hooks/vh_handler/vh_managed_types/vh_managed_buffer.rs index 0761d9b76b..5767c4dad3 100644 --- a/chain/vm/src/vm_hooks/vh_handler/vh_managed_types/vh_managed_buffer.rs +++ b/chain/vm/src/vm_hooks/vh_handler/vh_managed_types/vh_managed_buffer.rs @@ -110,4 +110,8 @@ pub trait VMHooksManagedBuffer: VMHooksHandlerSource { self.m_types_lock() .mb_set(dest_handle, encoded.into_bytes()); } + + fn mb_drop(&self, handle: RawHandle) { + self.m_types_lock().mb_remove(handle); + } } diff --git a/chain/vm/src/vm_hooks/vh_handler/vh_managed_types/vh_managed_map.rs b/chain/vm/src/vm_hooks/vh_handler/vh_managed_types/vh_managed_map.rs index b180dc30fa..b3438eab72 100644 --- a/chain/vm/src/vm_hooks/vh_handler/vh_managed_types/vh_managed_map.rs +++ b/chain/vm/src/vm_hooks/vh_handler/vh_managed_types/vh_managed_map.rs @@ -31,4 +31,8 @@ pub trait VMHooksManagedMap: VMHooksHandlerSource { let key = self.m_types_lock().mb_get(key_handle).to_vec(); self.m_types_lock().mm_contains(map_handle, key.as_slice()) } + + fn mm_drop(&self, map_handle: RawHandle) { + self.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 1d2ead32ec..985678da17 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 @@ -65,4 +65,10 @@ pub trait ManagedTypeApiImpl: fn get_token_ticker_len(&self, token_id_len: usize) -> usize { super::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 01f26277c8..6651aad1ba 100644 --- a/framework/base/src/types/managed/basic/managed_buffer.rs +++ b/framework/base/src/types/managed/basic/managed_buffer.rs @@ -396,6 +396,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 43bed2fe5d..74eb2ef933 100644 --- a/framework/scenario/src/api/impl_vh/debug_api.rs +++ b/framework/scenario/src/api/impl_vh/debug_api.rs @@ -1,13 +1,13 @@ use std::sync::Arc; use multiversx_chain_vm::{ - executor::{BreakpointValue, VMHooks}, + executor::BreakpointValue, tx_mock::{TxContext, TxContextRef, TxContextStack, TxPanic}, vm_hooks::{DebugApiVMHooksHandler, VMHooksDispatcher}, }; use multiversx_sc::{chain_core::types::ReturnCode, err_msg}; -use crate::debug_executor::{StaticVarData, StaticVarStack}; +use crate::debug_executor::{StaticVarData, StaticVarStack, VMHooksDebugger}; use super::{DebugHandle, VMHooksApi, VMHooksApiBackend}; @@ -19,7 +19,7 @@ impl VMHooksApiBackend for DebugApiBackend { fn with_vm_hooks(f: F) -> R where - F: FnOnce(&dyn VMHooks) -> R, + F: FnOnce(&dyn VMHooksDebugger) -> R, { let top_context = TxContextStack::static_peek(); let wrapper = DebugApiVMHooksHandler::new(top_context); @@ -29,7 +29,7 @@ impl VMHooksApiBackend for DebugApiBackend { fn with_vm_hooks_ctx_1(handle: Self::HandleType, f: F) -> R where - F: FnOnce(&dyn VMHooks) -> R, + F: FnOnce(&dyn VMHooksDebugger) -> R, { let wrapper = DebugApiVMHooksHandler::new(handle.context); let dispatcher = VMHooksDispatcher::new(Box::new(wrapper)); @@ -38,7 +38,7 @@ impl VMHooksApiBackend for DebugApiBackend { fn with_vm_hooks_ctx_2(handle1: Self::HandleType, handle2: Self::HandleType, f: F) -> R where - F: FnOnce(&dyn VMHooks) -> R, + F: FnOnce(&dyn VMHooksDebugger) -> R, { assert_handles_on_same_context(&handle1, &handle2); Self::with_vm_hooks_ctx_1(handle1, f) @@ -51,7 +51,7 @@ impl VMHooksApiBackend for DebugApiBackend { f: F, ) -> R where - F: FnOnce(&dyn VMHooks) -> R, + F: FnOnce(&dyn VMHooksDebugger) -> R, { 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 2cf63f74b0..a441a81aef 100644 --- a/framework/scenario/src/api/impl_vh/single_tx_api.rs +++ b/framework/scenario/src/api/impl_vh/single_tx_api.rs @@ -1,14 +1,13 @@ use std::sync::Mutex; use multiversx_chain_vm::{ - executor::VMHooks, types::VMAddress, vm_hooks::{SingleTxApiData, SingleTxApiVMHooksHandler, VMHooksDispatcher}, world_mock::AccountData, }; use multiversx_sc::api::RawHandle; -use crate::debug_executor::StaticVarData; +use crate::debug_executor::{StaticVarData, VMHooksDebugger}; use super::{VMHooksApi, VMHooksApiBackend}; @@ -26,7 +25,7 @@ impl VMHooksApiBackend for SingleTxApiBackend { fn with_vm_hooks(f: F) -> R where - F: FnOnce(&dyn VMHooks) -> R, + F: FnOnce(&dyn VMHooksDebugger) -> R, { SINGLE_TX_API_VH_CELL.with(|cell| { let handler = 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 d4941a60db..27ce03c8dc 100644 --- a/framework/scenario/src/api/impl_vh/static_api.rs +++ b/framework/scenario/src/api/impl_vh/static_api.rs @@ -1,11 +1,8 @@ -use multiversx_chain_vm::{ - executor::VMHooks, - vm_hooks::{StaticApiVMHooksHandler, VMHooksDispatcher, VMHooksHandler}, -}; +use multiversx_chain_vm::vm_hooks::{StaticApiVMHooksHandler, VMHooksDispatcher, VMHooksHandler}; use multiversx_sc::{api::RawHandle, types::Address}; use std::sync::Mutex; -use crate::debug_executor::StaticVarData; +use crate::debug_executor::{StaticVarData, VMHooksDebugger}; use super::{VMHooksApi, VMHooksApiBackend}; @@ -28,7 +25,7 @@ impl VMHooksApiBackend for StaticApiBackend { fn with_vm_hooks(f: F) -> R where - F: FnOnce(&dyn VMHooks) -> R, + F: FnOnce(&dyn VMHooksDebugger) -> R, { STATIC_API_VH_CELL.with(|vh_mutex| { let 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 71f14b1974..a2ff2a183f 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::debug_executor::StaticVarData; +use crate::debug_executor::{StaticVarData, VMHooksDebugger}; use super::VMHooksApiBackend; use std::marker::PhantomData; -use multiversx_chain_vm::executor::{MemPtr, VMHooks}; +use multiversx_chain_vm::executor::MemPtr; use multiversx_sc::api::{HandleTypeInfo, ManagedBufferApiImpl}; #[derive(Clone, Debug)] @@ -22,7 +22,7 @@ impl VMHooksApi { /// All communication with the VM happens via this method. pub fn with_vm_hooks(&self, f: F) -> R where - F: FnOnce(&dyn VMHooks) -> R, + F: FnOnce(&dyn VMHooksDebugger) -> R, { VHB::with_vm_hooks(f) } @@ -30,7 +30,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(&dyn VMHooks) -> R, + F: FnOnce(&dyn VMHooksDebugger) -> R, { VHB::with_vm_hooks_ctx_1(handle.clone(), f) } @@ -43,7 +43,7 @@ impl VMHooksApi { f: F, ) -> R where - F: FnOnce(&dyn VMHooks) -> R, + F: FnOnce(&dyn VMHooksDebugger) -> R, { VHB::with_vm_hooks_ctx_2(handle1.clone(), handle2.clone(), f) } @@ -57,7 +57,7 @@ impl VMHooksApi { f: F, ) -> R where - F: FnOnce(&dyn VMHooks) -> R, + F: FnOnce(&dyn VMHooksDebugger) -> R, { 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 336f228b2d..d55590c625 100644 --- a/framework/scenario/src/api/impl_vh/vm_hooks_backend.rs +++ b/framework/scenario/src/api/impl_vh/vm_hooks_backend.rs @@ -1,7 +1,6 @@ -use multiversx_chain_vm::executor::VMHooks; use multiversx_sc::api::HandleConstraints; -use crate::debug_executor::StaticVarData; +use crate::debug_executor::{StaticVarData, VMHooksDebugger}; pub trait VMHooksApiBackend: Clone + Send + Sync + 'static { /// We use a single handle type for all handles. @@ -10,18 +9,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(&dyn VMHooks) -> R; + F: FnOnce(&dyn VMHooksDebugger) -> R; fn with_vm_hooks_ctx_1(_handle: Self::HandleType, f: F) -> R where - F: FnOnce(&dyn VMHooks) -> R, + F: FnOnce(&dyn VMHooksDebugger) -> R, { Self::with_vm_hooks(f) } fn with_vm_hooks_ctx_2(_handle1: Self::HandleType, _handle2: Self::HandleType, f: F) -> R where - F: FnOnce(&dyn VMHooks) -> R, + F: FnOnce(&dyn VMHooksDebugger) -> R, { Self::with_vm_hooks(f) } @@ -33,7 +32,7 @@ pub trait VMHooksApiBackend: Clone + Send + Sync + 'static { f: F, ) -> R where - F: FnOnce(&dyn VMHooks) -> R, + F: FnOnce(&dyn VMHooksDebugger) -> R, { 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 e7f28ea8b7..6ca415c0c3 100644 --- a/framework/scenario/src/api/managed_type_api_vh.rs +++ b/framework/scenario/src/api/managed_type_api_vh.rs @@ -94,4 +94,28 @@ impl ManagedTypeApiImpl for VMHooksApi { ) }); } + + 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/debug_executor.rs b/framework/scenario/src/debug_executor.rs index 9fbba55308..a8e73241a3 100644 --- a/framework/scenario/src/debug_executor.rs +++ b/framework/scenario/src/debug_executor.rs @@ -3,6 +3,7 @@ mod contract_container; mod contract_map; mod static_var_stack; mod tx_static_vars; +mod vm_hooks_debugger; pub use catch_tx_panic::catch_tx_panic; pub use contract_container::{ @@ -11,3 +12,4 @@ pub use contract_container::{ pub use contract_map::{ContractMap, ContractMapRef}; pub use static_var_stack::{StaticVarData, StaticVarStack}; pub use tx_static_vars::TxStaticVars; +pub use vm_hooks_debugger::VMHooksDebugger; diff --git a/framework/scenario/src/debug_executor/vm_hooks_debugger.rs b/framework/scenario/src/debug_executor/vm_hooks_debugger.rs new file mode 100644 index 0000000000..5e5df80b62 --- /dev/null +++ b/framework/scenario/src/debug_executor/vm_hooks_debugger.rs @@ -0,0 +1,32 @@ +use multiversx_chain_vm::vm_hooks::VMHooksDispatcher; +use multiversx_chain_vm_executor::VMHooks; + +pub trait VMHooksDebugger: VMHooks { + fn drop_managed_buffer(&self, handle: i32); + fn drop_big_float(&self, handle: i32); + fn drop_big_int(&self, handle: i32); + fn drop_elliptic_curve(&self, handle: i32); + fn drop_managed_map(&self, handle: i32); +} + +impl VMHooksDebugger for VMHooksDispatcher { + fn drop_managed_buffer(&self, handle: i32) { + self.handler.mb_drop(handle); + } + + fn drop_big_float(&self, handle: i32) { + self.handler.bf_drop(handle); + } + + fn drop_big_int(&self, handle: i32) { + self.handler.bi_drop(handle); + } + + fn drop_elliptic_curve(&self, _handle: i32) { + // TODO: not implemented + } + + fn drop_managed_map(&self, handle: i32) { + self.handler.mm_drop(handle); + } +}