Skip to content

Commit

Permalink
Merge pull request #1131 from multiversx/vh-api-7d-consistency
Browse files Browse the repository at this point in the history
DebuggerApi - handle safety & context
  • Loading branch information
andrei-marinica committed Jun 27, 2023
2 parents 91957b4 + 5b3c0ea commit f66bc75
Show file tree
Hide file tree
Showing 23 changed files with 341 additions and 99 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use multiversx_sc::{
types::{Address, BigUint, EsdtLocalRole, EsdtTokenPayment, ManagedVec, TokenIdentifier},
};
use multiversx_sc_scenario::{
assert_values_eq, managed_address, managed_biguint, managed_buffer, managed_token_id,
rust_biguint, testing_framework::*, DebugApi,
api::DebuggerApi as DebugApi, assert_values_eq, managed_address, managed_biguint,
managed_buffer, managed_token_id, rust_biguint, testing_framework::*,
};
use rust_testing_framework_tester::{dummy_module::DummyModule, *};

Expand Down Expand Up @@ -1187,6 +1187,7 @@ fn managed_environment_test() {
}

#[test]
#[should_panic] // VMHooksApi misuse: operation called with handles from 2 different contexts
fn managed_environment_consistency_test() {
let mut wrapper = BlockchainStateWrapper::new();
let adder_wrapper = wrapper.create_sc_account(
Expand All @@ -1208,6 +1209,7 @@ fn managed_environment_consistency_test() {
}

#[test]
#[should_panic] // VMHooksApi misuse: operation called with handles from 2 different contexts
fn test_managed_values_standalone_consistency() {
let _ = DebugApi::dummy();

Expand Down
32 changes: 27 additions & 5 deletions framework/scenario/src/api/core_api_vh/blockchain_api_vh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ impl<VHB: VMHooksApiBackend> BlockchainApiImpl for VMHooksApi<VHB> {
}

fn load_caller_managed(&self, dest: Self::ManagedBufferHandle) {
self.assert_live_handle(&dest);
self.with_vm_hooks(|vh| vh.managed_caller(dest.get_raw_handle_unchecked()));
}

Expand All @@ -27,6 +28,7 @@ impl<VHB: VMHooksApiBackend> BlockchainApiImpl for VMHooksApi<VHB> {
}

fn load_sc_address_managed(&self, dest: Self::ManagedBufferHandle) {
self.assert_live_handle(&dest);
self.with_vm_hooks(|vh| vh.managed_sc_address(dest.get_raw_handle_unchecked()));
}

Expand All @@ -39,6 +41,7 @@ impl<VHB: VMHooksApiBackend> BlockchainApiImpl for VMHooksApi<VHB> {
}

fn get_shard_of_address(&self, address_handle: Self::ManagedBufferHandle) -> u32 {
self.assert_live_handle(&address_handle);
self.with_temp_address_ptr(address_handle, |address_ptr| {
self.with_vm_hooks(|vh| vh.get_shard_of_address(address_ptr))
}) as u32
Expand All @@ -49,6 +52,7 @@ impl<VHB: VMHooksApiBackend> BlockchainApiImpl for VMHooksApi<VHB> {
}

fn is_smart_contract(&self, address_handle: Self::ManagedBufferHandle) -> bool {
self.assert_live_handle(&address_handle);
let result = self.with_temp_address_ptr(address_handle, |address_ptr| {
self.with_vm_hooks(|vh| vh.is_smart_contract(address_ptr))
});
Expand All @@ -60,6 +64,8 @@ impl<VHB: VMHooksApiBackend> BlockchainApiImpl for VMHooksApi<VHB> {
}

fn load_balance(&self, dest: Self::BigIntHandle, address_handle: Self::ManagedBufferHandle) {
self.assert_live_handle(&dest);
self.assert_live_handle(&address_handle);
self.with_temp_address_ptr(address_handle, |address_ptr: isize| {
self.with_vm_hooks(|vh| {
vh.big_int_get_external_balance(address_ptr, dest.get_raw_handle_unchecked())
Expand All @@ -76,6 +82,7 @@ impl<VHB: VMHooksApiBackend> BlockchainApiImpl for VMHooksApi<VHB> {
}

fn load_tx_hash_managed(&self, dest: Self::ManagedBufferHandle) {
self.assert_live_handle(&dest);
self.with_vm_hooks(|vh| vh.managed_get_original_tx_hash(dest.get_raw_handle_unchecked()));
}

Expand All @@ -100,6 +107,7 @@ impl<VHB: VMHooksApiBackend> BlockchainApiImpl for VMHooksApi<VHB> {
}

fn load_block_random_seed_managed(&self, dest: Self::ManagedBufferHandle) {
self.assert_live_handle(&dest);
self.with_vm_hooks(|vh| vh.managed_get_block_random_seed(dest.get_raw_handle_unchecked()));
}

Expand All @@ -124,14 +132,19 @@ impl<VHB: VMHooksApiBackend> BlockchainApiImpl for VMHooksApi<VHB> {
}

fn load_prev_block_random_seed_managed(&self, dest: Self::ManagedBufferHandle) {
self.with_vm_hooks(|vh| vh.managed_get_prev_block_random_seed(dest.get_raw_handle_unchecked()));
self.assert_live_handle(&dest);
self.with_vm_hooks(|vh| {
vh.managed_get_prev_block_random_seed(dest.get_raw_handle_unchecked())
});
}

fn get_current_esdt_nft_nonce(
&self,
address_handle: Self::ManagedBufferHandle,
token_id_handle: Self::ManagedBufferHandle,
) -> u64 {
self.assert_live_handle(&address_handle);
self.assert_live_handle(&token_id_handle);
let token_id_len = self.mb_len(token_id_handle.clone());
let result = self.with_temp_address_ptr(address_handle, |address_ptr| {
self.with_temp_buffer_ptr(token_id_handle, token_id_len, |token_id_ptr| {
Expand All @@ -150,6 +163,8 @@ impl<VHB: VMHooksApiBackend> BlockchainApiImpl for VMHooksApi<VHB> {
nonce: u64,
dest: Self::BigIntHandle,
) {
self.assert_live_handle(&address_handle);
self.assert_live_handle(&token_id_handle);
let token_id_len = self.mb_len(token_id_handle.clone());
self.with_temp_address_ptr(address_handle, |address_ptr| {
self.with_temp_buffer_ptr(token_id_handle, token_id_len, |token_id_ptr| {
Expand Down Expand Up @@ -203,6 +218,8 @@ impl<VHB: VMHooksApiBackend> BlockchainApiImpl for VMHooksApi<VHB> {
token_id_handle: Self::ManagedBufferHandle,
nonce: u64,
) -> bool {
self.assert_live_handle(&address_handle);
self.assert_live_handle(&token_id_handle);
let result = self.with_vm_hooks(|vh| {
vh.managed_is_esdt_frozen(
address_handle.get_raw_handle_unchecked(),
Expand All @@ -214,12 +231,15 @@ impl<VHB: VMHooksApiBackend> BlockchainApiImpl for VMHooksApi<VHB> {
}

fn check_esdt_paused(&self, token_id_handle: Self::ManagedBufferHandle) -> bool {
let result =
self.with_vm_hooks(|vh| vh.managed_is_esdt_paused(token_id_handle.get_raw_handle_unchecked()));
self.assert_live_handle(&token_id_handle);
let result = self.with_vm_hooks(|vh| {
vh.managed_is_esdt_paused(token_id_handle.get_raw_handle_unchecked())
});
i32_to_bool(result)
}

fn check_esdt_limited_transfer(&self, token_id_handle: Self::ManagedBufferHandle) -> bool {
self.assert_live_handle(&token_id_handle);
let result = self.with_vm_hooks(|vh| {
vh.managed_is_esdt_limited_transfer(token_id_handle.get_raw_handle_unchecked())
});
Expand All @@ -230,8 +250,10 @@ impl<VHB: VMHooksApiBackend> BlockchainApiImpl for VMHooksApi<VHB> {
&self,
token_id_handle: Self::ManagedBufferHandle,
) -> EsdtLocalRoleFlags {
let result =
self.with_vm_hooks(|vh| vh.get_esdt_local_roles(token_id_handle.get_raw_handle_unchecked()));
self.assert_live_handle(&token_id_handle);
let result = self.with_vm_hooks(|vh| {
vh.get_esdt_local_roles(token_id_handle.get_raw_handle_unchecked())
});
unsafe { EsdtLocalRoleFlags::from_bits_unchecked(result as u64) }
}
}
6 changes: 5 additions & 1 deletion framework/scenario/src/api/core_api_vh/call_value_api_vh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ impl<VHB: VMHooksApiBackend> CallValueApiImpl for VMHooksApi<VHB> {
}

fn load_egld_value(&self, dest: Self::BigIntHandle) {
self.assert_live_handle(&dest);
self.with_vm_hooks(|vh| vh.big_int_get_call_value(dest.get_raw_handle_unchecked()));
}

fn load_all_esdt_transfers(&self, dest_handle: Self::ManagedBufferHandle) {
self.with_vm_hooks(|vh| vh.managed_get_multi_esdt_call_value(dest_handle.get_raw_handle_unchecked()));
self.assert_live_handle(&dest_handle);
self.with_vm_hooks(|vh| {
vh.managed_get_multi_esdt_call_value(dest_handle.get_raw_handle_unchecked())
});
}

fn esdt_num_transfers(&self) -> usize {
Expand Down
16 changes: 11 additions & 5 deletions framework/scenario/src/api/core_api_vh/crypto_api_vh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ impl<VHB: VMHooksApiBackend> CryptoApiImpl for VMHooksApi<VHB> {
result_handle: Self::ManagedBufferHandle,
data_handle: Self::ManagedBufferHandle,
) {
self.with_vm_hooks(|vh| {
vh.managed_sha256(data_handle.get_raw_handle_unchecked(), result_handle.get_raw_handle_unchecked())
self.with_vm_hooks_ctx_2(&result_handle, &data_handle, |vh| {
vh.managed_sha256(
data_handle.get_raw_handle_unchecked(),
result_handle.get_raw_handle_unchecked(),
)
});
}

Expand All @@ -29,8 +32,11 @@ impl<VHB: VMHooksApiBackend> CryptoApiImpl for VMHooksApi<VHB> {
result_handle: Self::ManagedBufferHandle,
data_handle: Self::ManagedBufferHandle,
) {
self.with_vm_hooks(|vh| {
vh.managed_keccak256(data_handle.get_raw_handle_unchecked(), result_handle.get_raw_handle_unchecked())
self.with_vm_hooks_ctx_2(&result_handle, &data_handle, |vh| {
vh.managed_keccak256(
data_handle.get_raw_handle_unchecked(),
result_handle.get_raw_handle_unchecked(),
)
});
}

Expand All @@ -57,7 +63,7 @@ impl<VHB: VMHooksApiBackend> CryptoApiImpl for VMHooksApi<VHB> {
message: Self::ManagedBufferHandle,
signature: Self::ManagedBufferHandle,
) {
self.with_vm_hooks(|vh| {
self.with_vm_hooks_ctx_3(&key, &message, &signature, |vh| {
vh.managed_verify_ed25519(
key.get_raw_handle_unchecked(),
message.get_raw_handle_unchecked(),
Expand Down
2 changes: 2 additions & 0 deletions framework/scenario/src/api/core_api_vh/endpoint_arg_api_vh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ impl<VHB: VMHooksApiBackend> EndpointArgumentApiImpl for VMHooksApi<VHB> {
}

fn load_argument_managed_buffer(&self, arg_id: i32, dest: Self::ManagedBufferHandle) {
self.assert_live_handle(&dest);
self.with_vm_hooks(|vh| vh.mbuffer_get_argument(arg_id, dest.get_raw_handle_unchecked()));
}

fn load_callback_closure_buffer(&self, dest: Self::ManagedBufferHandle) {
self.assert_live_handle(&dest);
self.with_vm_hooks(|vh| vh.managed_get_callback_closure(dest.get_raw_handle_unchecked()));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@ impl<VHB: VMHooksApiBackend> EndpointFinishApiImpl for VMHooksApi<VHB> {
}

fn finish_big_int_raw(&self, handle: Self::BigIntHandle) {
self.assert_live_handle(&handle);
self.with_vm_hooks(|vh| vh.big_int_finish_signed(handle.get_raw_handle_unchecked()));
}

fn finish_big_uint_raw(&self, handle: Self::BigIntHandle) {
self.assert_live_handle(&handle);
self.with_vm_hooks(|vh| vh.big_int_finish_unsigned(handle.get_raw_handle_unchecked()));
}

fn finish_managed_buffer_raw(&self, handle: Self::ManagedBufferHandle) {
self.assert_live_handle(&handle);
self.with_vm_hooks(|vh| vh.mbuffer_finish(handle.get_raw_handle_unchecked()));
}

Expand Down
3 changes: 2 additions & 1 deletion framework/scenario/src/api/core_api_vh/error_api_vh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ impl<VHB: VMHooksApiBackend> ErrorApiImpl for VMHooksApi<VHB> {
}

fn signal_error_from_buffer(&self, message_handle: Self::ManagedBufferHandle) -> ! {
self.with_vm_hooks(|vh| vh.managed_signal_error(message_handle.get_raw_handle_unchecked()));
self.assert_live_handle(&message_handle);
self.with_vm_hooks(|vh| vh.managed_signal_error(message_handle.get_raw_handle()));

// even though not explicitly stated in the VM hooks definition,
// `managed_signal_error` is expected to terminate execution
Expand Down
5 changes: 4 additions & 1 deletion framework/scenario/src/api/core_api_vh/log_api_vh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ impl<VHB: VMHooksApiBackend> LogApiImpl for VMHooksApi<VHB> {
data_handle: Self::ManagedBufferHandle,
) {
self.with_vm_hooks(|vh| {
vh.managed_write_log(topics_handle.get_raw_handle_unchecked(), data_handle.get_raw_handle_unchecked())
vh.managed_write_log(
topics_handle.get_raw_handle_unchecked(),
data_handle.get_raw_handle_unchecked(),
)
});
}
}
17 changes: 15 additions & 2 deletions framework/scenario/src/api/core_api_vh/storage_api_vh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@ impl<VHB: VMHooksApiBackend> StorageReadApiImpl for VMHooksApi<VHB> {
key_handle: Self::ManagedBufferHandle,
dest: Self::ManagedBufferHandle,
) {
self.assert_live_handle(&key_handle);
self.assert_live_handle(&dest);
self.with_vm_hooks(|vh| {
vh.mbuffer_storage_load(key_handle.get_raw_handle_unchecked(), dest.get_raw_handle_unchecked())
vh.mbuffer_storage_load(
key_handle.get_raw_handle_unchecked(),
dest.get_raw_handle_unchecked(),
)
});
}

Expand All @@ -29,6 +34,9 @@ impl<VHB: VMHooksApiBackend> StorageReadApiImpl for VMHooksApi<VHB> {
key_handle: Self::ManagedBufferHandle,
dest: Self::ManagedBufferHandle,
) {
self.assert_live_handle(&address_handle);
self.assert_live_handle(&key_handle);
self.assert_live_handle(&dest);
self.with_vm_hooks(|vh| {
vh.mbuffer_storage_load_from_address(
address_handle.get_raw_handle_unchecked(),
Expand All @@ -53,8 +61,13 @@ impl<VHB: VMHooksApiBackend> StorageWriteApiImpl for VMHooksApi<VHB> {
key_handle: Self::ManagedBufferHandle,
value_handle: Self::ManagedBufferHandle,
) {
self.assert_live_handle(&key_handle);
self.assert_live_handle(&value_handle);
self.with_vm_hooks(|vh| {
vh.mbuffer_storage_store(key_handle.get_raw_handle_unchecked(), value_handle.get_raw_handle_unchecked());
vh.mbuffer_storage_store(
key_handle.get_raw_handle_unchecked(),
value_handle.get_raw_handle_unchecked(),
);
});
}
}
44 changes: 44 additions & 0 deletions framework/scenario/src/api/impl_vh/debug_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,50 @@ impl VMHooksApiBackend for DebugApiBackend {
f(&dispatcher)
}

fn with_vm_hooks_ctx_1<R, F>(handle: Self::HandleType, f: F) -> R
where
F: FnOnce(&dyn VMHooks) -> R,
{
let wrapper = TxContextWrapper::new(handle.context);
let dispatcher = VMHooksDispatcher::new(Box::new(wrapper));
f(&dispatcher)
}

fn with_vm_hooks_ctx_2<R, F>(handle1: Self::HandleType, handle2: Self::HandleType, f: F) -> R
where
F: FnOnce(&dyn VMHooks) -> R,
{
assert!(
Rc::ptr_eq(&handle1.context, &handle2.context),
"VMHooksApi misuse: operation called with handles from 2 different contexts"
);
Self::with_vm_hooks_ctx_1(handle1, f)
}

fn with_vm_hooks_ctx_3<R, F>(
handle1: Self::HandleType,
handle2: Self::HandleType,
handle3: Self::HandleType,
f: F,
) -> R
where
F: FnOnce(&dyn VMHooks) -> R,
{
assert!(
Rc::ptr_eq(&handle1.context, &handle2.context),
"VMHooksApi misuse: operation called with handles from 2 different contexts"
);
assert!(
Rc::ptr_eq(&handle1.context, &handle3.context),
"VMHooksApi misuse: operation called with handles from 2 different contexts"
);
Self::with_vm_hooks_ctx_1(handle1, f)
}

fn assert_live_handle(handle: &Self::HandleType) {
handle.assert_current_context()
}

fn with_static_data<R, F>(f: F) -> R
where
F: FnOnce(&StaticVarData) -> R,
Expand Down
2 changes: 1 addition & 1 deletion framework/scenario/src/api/impl_vh/debug_handle_vh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub struct DebugHandle {
}

impl DebugHandle {
fn assert_current_context(&self) {
pub fn assert_current_context(&self) {
assert!(
Rc::ptr_eq(&self.context, &TxContextStack::static_peek()),
"Managed value not used in original context"
Expand Down
Loading

0 comments on commit f66bc75

Please sign in to comment.