From d433c598a8b6a132e076177204e41710af3a50c6 Mon Sep 17 00:00:00 2001 From: Laurentiu Ciobanu Date: Mon, 21 Jul 2025 12:10:41 +0300 Subject: [PATCH 01/35] add meetering for bulk memory opcodes --- vm-executor-wasmer/src/wasmer_helpers.rs | 8 +++ vm-executor-wasmer/src/wasmer_metering.rs | 62 ++++++++++++++++++- .../src/wasmer_metering_helpers.rs | 2 + vm-executor/src/opcode_cost.rs | 4 ++ 4 files changed, 73 insertions(+), 3 deletions(-) diff --git a/vm-executor-wasmer/src/wasmer_helpers.rs b/vm-executor-wasmer/src/wasmer_helpers.rs index 476a6aa..34ca39a 100644 --- a/vm-executor-wasmer/src/wasmer_helpers.rs +++ b/vm-executor-wasmer/src/wasmer_helpers.rs @@ -82,3 +82,11 @@ pub(crate) fn is_control_flow_operator(operator: &Operator) -> bool { | Operator::Return ) } + +pub (crate) fn is_supported_bulk_memory_operator(operator: &Operator) -> bool { + matches!( + operator, + Operator::MemoryCopy { src: _, dst: _ } + | Operator::MemoryFill { mem: _ } + ) +} diff --git a/vm-executor-wasmer/src/wasmer_metering.rs b/vm-executor-wasmer/src/wasmer_metering.rs index ce1ad1c..658929c 100644 --- a/vm-executor-wasmer/src/wasmer_metering.rs +++ b/vm-executor-wasmer/src/wasmer_metering.rs @@ -1,8 +1,7 @@ use crate::executor_interface::OpcodeCost; use crate::wasmer_breakpoints::{Breakpoints, BREAKPOINT_VALUE_OUT_OF_GAS}; use crate::wasmer_helpers::{ - create_global_index, get_global_value_u64, is_control_flow_operator, set_global_value_u64, - MiddlewareWithProtectedGlobals, + create_global_index, get_global_value_u64, is_control_flow_operator, is_supported_bulk_memory_operator, set_global_value_u64, MiddlewareWithProtectedGlobals }; use crate::{get_local_cost, get_opcode_cost}; use loupe::{MemoryUsage, MemoryUsageTracker}; @@ -17,12 +16,14 @@ use wasmer_types::{GlobalIndex, ModuleInfo}; const METERING_POINTS_LIMIT: &str = "metering_points_limit"; const METERING_POINTS_USED: &str = "metering_points_used"; +const METERING_BULK_MEMORY_SIZE_OPERAND_BACKUP: &str = "metering_bulk_memory_size_operand_backup"; const MAX_LOCAL_COUNT: u32 = 4000; #[derive(Clone, Debug, MemoryUsage)] struct MeteringGlobalIndexes { points_limit_global_index: GlobalIndex, points_used_global_index: GlobalIndex, + bulk_memory_size_operand_backup_global_index: GlobalIndex, } #[derive(Debug)] @@ -67,6 +68,15 @@ impl Metering { .unwrap() .points_used_global_index } + + fn get_bulk_memory_size_operand_backup_global_index(&self) -> GlobalIndex { + self.global_indexes + .lock() + .unwrap() + .as_ref() + .unwrap() + .bulk_memory_size_operand_backup_global_index + } } unsafe impl Send for Metering {} @@ -105,6 +115,11 @@ impl ModuleMiddleware for Metering { points_limit, ), points_used_global_index: create_global_index(module_info, METERING_POINTS_USED, 0), + bulk_memory_size_operand_backup_global_index: create_global_index( + module_info, + METERING_BULK_MEMORY_SIZE_OPERAND_BACKUP, + 0, + ), }); } } @@ -114,6 +129,7 @@ impl MiddlewareWithProtectedGlobals for Metering { vec![ self.get_points_limit_global_index().as_u32(), self.get_points_used_global_index().as_u32(), + self.get_bulk_memory_size_operand_backup_global_index().as_u32(), ] } } @@ -156,6 +172,39 @@ impl FunctionMetering { self.breakpoints_middleware .inject_breakpoint_condition(state, BREAKPOINT_VALUE_OUT_OF_GAS); } + + fn inject_bulk_memory_cost(&self, state: &mut MiddlewareReaderState, cost_per_byte: u32) { + // backup the bulk memory size + state.extend(&[Operator::GlobalSet { + global_index: self.global_indexes.bulk_memory_size_operand_backup_global_index.as_u32(), + }]); + + // inject bulk memory cost + state.extend(&[ + // memory size * price + Operator::GlobalGet { + global_index: self.global_indexes.bulk_memory_size_operand_backup_global_index.as_u32(), + }, + Operator::I64Const { + value: cost_per_byte as i64, + }, + Operator::I64Mul, + + // points user += memory size * price + Operator::GlobalGet { + global_index: self.global_indexes.points_used_global_index.as_u32(), + }, + Operator::I64Add, + Operator::GlobalSet { + global_index: self.global_indexes.points_used_global_index.as_u32(), + }, + ]); + + // bring back the bulk memory size + state.extend(&[Operator::GlobalGet { + global_index: self.global_indexes.bulk_memory_size_operand_backup_global_index.as_u32(), + }]); + } } impl FunctionMiddleware for FunctionMetering { @@ -169,7 +218,14 @@ impl FunctionMiddleware for FunctionMetering { // corner cases. let option = get_opcode_cost(&operator, &self.opcode_cost.lock().unwrap()); match option { - Some(cost) => self.accumulated_cost += cost as u64, + Some(cost) if is_supported_bulk_memory_operator(&operator) => { + self.inject_bulk_memory_cost(state, cost); + // immediatly insert out of gas check as this operation might be expensive + self.inject_out_of_gas_check(state); + }, + Some(cost) => { + self.accumulated_cost += cost as u64 + }, None => { return Err(MiddlewareError::new( "metering_middleware", diff --git a/vm-executor-wasmer/src/wasmer_metering_helpers.rs b/vm-executor-wasmer/src/wasmer_metering_helpers.rs index dcd1996..9e7432d 100644 --- a/vm-executor-wasmer/src/wasmer_metering_helpers.rs +++ b/vm-executor-wasmer/src/wasmer_metering_helpers.rs @@ -121,6 +121,8 @@ pub fn get_opcode_cost(op: &Operator, opcode_cost: &OpcodeCost) -> Option { Operator::Loop { .. } => Some(opcode_cost.opcode_loop), Operator::MemoryGrow { .. } => Some(opcode_cost.opcode_memorygrow), Operator::MemorySize { .. } => Some(opcode_cost.opcode_memorysize), + Operator::MemoryCopy { .. } => Some(opcode_cost.opcode_memorycopy), + Operator::MemoryFill { .. } => Some(opcode_cost.opcode_memoryfill), Operator::Nop { .. } => Some(opcode_cost.opcode_nop), Operator::RefFunc { .. } => Some(opcode_cost.opcode_reffunc), Operator::RefIsNull { .. } => Some(opcode_cost.opcode_refisnull), diff --git a/vm-executor/src/opcode_cost.rs b/vm-executor/src/opcode_cost.rs index 9c299c8..ad2f7f7 100644 --- a/vm-executor/src/opcode_cost.rs +++ b/vm-executor/src/opcode_cost.rs @@ -227,6 +227,10 @@ pub struct OpcodeCost { pub opcode_memorygrow: u32, #[serde(rename = "MemorySize", default)] pub opcode_memorysize: u32, + #[serde(rename = "MemoryCopy", default)] + pub opcode_memorycopy: u32, + #[serde(rename = "MemoryFill", default)] + pub opcode_memoryfill: u32, #[serde(rename = "Nop", default)] pub opcode_nop: u32, #[serde(rename = "RefFunc", default)] From ee4aba08e6f736b37196664a2caac958d7c36de0 Mon Sep 17 00:00:00 2001 From: Laurentiu Ciobanu Date: Tue, 12 Aug 2025 12:20:52 +0300 Subject: [PATCH 02/35] unsafe mode hooks --- c-api/libvmexeccapi.h | 5 ++++ c-api/src/capi_vm_hook_pointers.rs | 5 ++++ c-api/src/capi_vm_hooks.rs | 20 +++++++++++++ vm-executor-experimental/src/we_imports.rs | 30 +++++++++++++++++++ vm-executor-wasmer/src/wasmer_imports.rs | 30 +++++++++++++++++++ .../src/new_traits/vm_hooks_legacy_adapter.rs | 20 +++++++++++++ vm-executor/src/new_traits/vm_hooks_new.rs | 30 +++++++++++++++++++ vm-executor/src/vm_hooks.rs | 26 ++++++++++++++++ 8 files changed, 166 insertions(+) diff --git a/c-api/libvmexeccapi.h b/c-api/libvmexeccapi.h index 14ab427..bd83b54 100644 --- a/c-api/libvmexeccapi.h +++ b/c-api/libvmexeccapi.h @@ -315,6 +315,11 @@ typedef struct { int32_t (*managed_verify_secp256r1_func_ptr)(void *context, int32_t key_handle, int32_t message_handle, int32_t sig_handle); int32_t (*managed_verify_blssignature_share_func_ptr)(void *context, int32_t key_handle, int32_t message_handle, int32_t sig_handle); int32_t (*managed_verify_blsaggregated_signature_func_ptr)(void *context, int32_t key_handle, int32_t message_handle, int32_t sig_handle); + void (*activate_unsafe_mode_func_ptr)(void *context); + void (*deactivate_unsafe_mode_func_ptr)(void *context); + int32_t (*managed_get_num_errors_func_ptr)(void *context); + void (*managed_get_error_with_index_func_ptr)(void *context, int32_t index, int32_t error_handle); + void (*managed_get_last_error_func_ptr)(void *context, int32_t error_handle); } vm_exec_vm_hook_c_func_pointers; typedef struct { diff --git a/c-api/src/capi_vm_hook_pointers.rs b/c-api/src/capi_vm_hook_pointers.rs index 3029000..1200dae 100644 --- a/c-api/src/capi_vm_hook_pointers.rs +++ b/c-api/src/capi_vm_hook_pointers.rs @@ -288,6 +288,11 @@ pub struct vm_exec_vm_hook_c_func_pointers { pub managed_verify_secp256r1_func_ptr: extern "C" fn(context: *mut c_void, key_handle: i32, message_handle: i32, sig_handle: i32) -> i32, pub managed_verify_blssignature_share_func_ptr: extern "C" fn(context: *mut c_void, key_handle: i32, message_handle: i32, sig_handle: i32) -> i32, pub managed_verify_blsaggregated_signature_func_ptr: extern "C" fn(context: *mut c_void, key_handle: i32, message_handle: i32, sig_handle: i32) -> i32, + pub activate_unsafe_mode_func_ptr: extern "C" fn(context: *mut c_void), + pub deactivate_unsafe_mode_func_ptr: extern "C" fn(context: *mut c_void), + pub managed_get_num_errors_func_ptr: extern "C" fn(context: *mut c_void) -> i32, + pub managed_get_error_with_index_func_ptr: extern "C" fn(context: *mut c_void, index: i32, error_handle: i32), + pub managed_get_last_error_func_ptr: extern "C" fn(context: *mut c_void, error_handle: i32), } impl std::fmt::Debug for vm_exec_vm_hook_c_func_pointers { diff --git a/c-api/src/capi_vm_hooks.rs b/c-api/src/capi_vm_hooks.rs index f1a4295..5936bd3 100644 --- a/c-api/src/capi_vm_hooks.rs +++ b/c-api/src/capi_vm_hooks.rs @@ -1146,4 +1146,24 @@ impl multiversx_chain_vm_executor::VMHooksLegacy for CapiVMHooks { fn managed_verify_blsaggregated_signature(&self, key_handle: i32, message_handle: i32, sig_handle: i32) -> i32 { (self.c_func_pointers_ptr.managed_verify_blsaggregated_signature_func_ptr)(self.vm_hooks_ptr, key_handle, message_handle, sig_handle) } + + fn activate_unsafe_mode(&self) { + (self.c_func_pointers_ptr.activate_unsafe_mode_func_ptr)(self.vm_hooks_ptr) + } + + fn deactivate_unsafe_mode(&self) { + (self.c_func_pointers_ptr.deactivate_unsafe_mode_func_ptr)(self.vm_hooks_ptr) + } + + fn managed_get_num_errors(&self) -> i32 { + (self.c_func_pointers_ptr.managed_get_num_errors_func_ptr)(self.vm_hooks_ptr) + } + + fn managed_get_error_with_index(&self, index: i32, error_handle: i32) { + (self.c_func_pointers_ptr.managed_get_error_with_index_func_ptr)(self.vm_hooks_ptr, index, error_handle) + } + + fn managed_get_last_error(&self, error_handle: i32) { + (self.c_func_pointers_ptr.managed_get_last_error_func_ptr)(self.vm_hooks_ptr, error_handle) + } } diff --git a/vm-executor-experimental/src/we_imports.rs b/vm-executor-experimental/src/we_imports.rs index 39d3f28..78a843e 100644 --- a/vm-executor-experimental/src/we_imports.rs +++ b/vm-executor-experimental/src/we_imports.rs @@ -1396,6 +1396,31 @@ fn wasmer_import_managed_verify_blsaggregated_signature(env: FunctionEnvMut) -> Result<(), VMHooksEarlyExit> { + with_vm_hooks(env, |vh| vh.activate_unsafe_mode()) +} + +#[rustfmt::skip] +fn wasmer_import_deactivate_unsafe_mode(env: FunctionEnvMut) -> Result<(), VMHooksEarlyExit> { + with_vm_hooks(env, |vh| vh.deactivate_unsafe_mode()) +} + +#[rustfmt::skip] +fn wasmer_import_managed_get_num_errors(env: FunctionEnvMut) -> Result { + with_vm_hooks(env, |vh| vh.managed_get_num_errors()) +} + +#[rustfmt::skip] +fn wasmer_import_managed_get_error_with_index(env: FunctionEnvMut, index: i32, error_handle: i32) -> Result<(), VMHooksEarlyExit> { + with_vm_hooks(env, |vh| vh.managed_get_error_with_index(index, error_handle)) +} + +#[rustfmt::skip] +fn wasmer_import_managed_get_last_error(env: FunctionEnvMut, error_handle: i32) -> Result<(), VMHooksEarlyExit> { + with_vm_hooks(env, |vh| vh.managed_get_last_error(error_handle)) +} + pub fn generate_import_object(store: &mut Store, vh_wrapper: VMHooksWrapper) -> Imports { let function_env = FunctionEnv::new(store, vh_wrapper); @@ -1678,6 +1703,11 @@ pub fn generate_import_object(store: &mut Store, vh_wrapper: VMHooksWrapper) -> "managedVerifySecp256r1" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_verify_secp256r1), "managedVerifyBLSSignatureShare" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_verify_blssignature_share), "managedVerifyBLSAggregatedSignature" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_verify_blsaggregated_signature), + "activateUnsafeMode" => Function::new_typed_with_env(store, &function_env, wasmer_import_activate_unsafe_mode), + "deactivateUnsafeMode" => Function::new_typed_with_env(store, &function_env, wasmer_import_deactivate_unsafe_mode), + "managedGetNumErrors" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_get_num_errors), + "managedGetErrorWithIndex" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_get_error_with_index), + "managedGetLastError" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_get_last_error), } } diff --git a/vm-executor-wasmer/src/wasmer_imports.rs b/vm-executor-wasmer/src/wasmer_imports.rs index 7e41d64..0a7a6ab 100644 --- a/vm-executor-wasmer/src/wasmer_imports.rs +++ b/vm-executor-wasmer/src/wasmer_imports.rs @@ -1395,6 +1395,31 @@ fn wasmer_import_managed_verify_blsaggregated_signature(env: &VMHooksWrapper, ke env.vm_hooks.managed_verify_blsaggregated_signature(key_handle, message_handle, sig_handle) } +#[rustfmt::skip] +fn wasmer_import_activate_unsafe_mode(env: &VMHooksWrapper) { + env.vm_hooks.activate_unsafe_mode() +} + +#[rustfmt::skip] +fn wasmer_import_deactivate_unsafe_mode(env: &VMHooksWrapper) { + env.vm_hooks.deactivate_unsafe_mode() +} + +#[rustfmt::skip] +fn wasmer_import_managed_get_num_errors(env: &VMHooksWrapper) -> i32 { + env.vm_hooks.managed_get_num_errors() +} + +#[rustfmt::skip] +fn wasmer_import_managed_get_error_with_index(env: &VMHooksWrapper, index: i32, error_handle: i32) { + env.vm_hooks.managed_get_error_with_index(index, error_handle) +} + +#[rustfmt::skip] +fn wasmer_import_managed_get_last_error(env: &VMHooksWrapper, error_handle: i32) { + env.vm_hooks.managed_get_last_error(error_handle) +} + pub fn generate_import_object(store: &Store, env: &VMHooksWrapper) -> ImportObject { imports! { "env" => { @@ -1675,6 +1700,11 @@ pub fn generate_import_object(store: &Store, env: &VMHooksWrapper) -> ImportObje "managedVerifySecp256r1" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_verify_secp256r1), "managedVerifyBLSSignatureShare" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_verify_blssignature_share), "managedVerifyBLSAggregatedSignature" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_verify_blsaggregated_signature), + "activateUnsafeMode" => Function::new_native_with_env(store, env.clone(), wasmer_import_activate_unsafe_mode), + "deactivateUnsafeMode" => Function::new_native_with_env(store, env.clone(), wasmer_import_deactivate_unsafe_mode), + "managedGetNumErrors" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_get_num_errors), + "managedGetErrorWithIndex" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_get_error_with_index), + "managedGetLastError" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_get_last_error), } } diff --git a/vm-executor/src/new_traits/vm_hooks_legacy_adapter.rs b/vm-executor/src/new_traits/vm_hooks_legacy_adapter.rs index 1637554..c79d9b6 100644 --- a/vm-executor/src/new_traits/vm_hooks_legacy_adapter.rs +++ b/vm-executor/src/new_traits/vm_hooks_legacy_adapter.rs @@ -1154,4 +1154,24 @@ impl VMHooksLegacy for VMHooksLegacyAdapter { fn managed_verify_blsaggregated_signature(&self, key_handle: i32, message_handle: i32, sig_handle: i32) -> i32 { self.adapt_vm_hooks(|inner| VMHooks::managed_verify_blsaggregated_signature(inner, key_handle, message_handle, sig_handle)) } + + fn activate_unsafe_mode(&self) { + self.adapt_vm_hooks(|inner| VMHooks::activate_unsafe_mode(inner)) + } + + fn deactivate_unsafe_mode(&self) { + self.adapt_vm_hooks(|inner| VMHooks::deactivate_unsafe_mode(inner)) + } + + fn managed_get_num_errors(&self) -> i32 { + self.adapt_vm_hooks(|inner| VMHooks::managed_get_num_errors(inner)) + } + + fn managed_get_error_with_index(&self, index: i32, error_handle: i32) { + self.adapt_vm_hooks(|inner| VMHooks::managed_get_error_with_index(inner, index, error_handle)) + } + + fn managed_get_last_error(&self, error_handle: i32) { + self.adapt_vm_hooks(|inner| VMHooks::managed_get_last_error(inner, error_handle)) + } } diff --git a/vm-executor/src/new_traits/vm_hooks_new.rs b/vm-executor/src/new_traits/vm_hooks_new.rs index 0bd5410..26a6aa5 100644 --- a/vm-executor/src/new_traits/vm_hooks_new.rs +++ b/vm-executor/src/new_traits/vm_hooks_new.rs @@ -286,6 +286,11 @@ pub trait VMHooks: core::fmt::Debug { fn managed_verify_secp256r1(&mut self, key_handle: i32, message_handle: i32, sig_handle: i32) -> Result; fn managed_verify_blssignature_share(&mut self, key_handle: i32, message_handle: i32, sig_handle: i32) -> Result; fn managed_verify_blsaggregated_signature(&mut self, key_handle: i32, message_handle: i32, sig_handle: i32) -> Result; + fn activate_unsafe_mode(&mut self) -> Result<(), VMHooksEarlyExit>; + fn deactivate_unsafe_mode(&mut self) -> Result<(), VMHooksEarlyExit>; + fn managed_get_num_errors(&mut self) -> Result; + fn managed_get_error_with_index(&mut self, index: i32, error_handle: i32) -> Result<(), VMHooksEarlyExit>; + fn managed_get_last_error(&mut self, error_handle: i32) -> Result<(), VMHooksEarlyExit>; } /// Dummy implementation for VMHooks. Can be used as placeholder, or in tests. @@ -1679,4 +1684,29 @@ impl VMHooks for VMHooksDefault { println!("Called: managed_verify_blsaggregated_signature"); Ok(0) } + + fn activate_unsafe_mode(&mut self) -> Result<(), VMHooksEarlyExit> { + println!("Called: activate_unsafe_mode"); + Ok(()) + } + + fn deactivate_unsafe_mode(&mut self) -> Result<(), VMHooksEarlyExit> { + println!("Called: deactivate_unsafe_mode"); + Ok(()) + } + + fn managed_get_num_errors(&mut self) -> Result { + println!("Called: managed_get_num_errors"); + Ok(0) + } + + fn managed_get_error_with_index(&mut self, index: i32, error_handle: i32) -> Result<(), VMHooksEarlyExit> { + println!("Called: managed_get_error_with_index"); + Ok(()) + } + + fn managed_get_last_error(&mut self, error_handle: i32) -> Result<(), VMHooksEarlyExit> { + println!("Called: managed_get_last_error"); + Ok(()) + } } diff --git a/vm-executor/src/vm_hooks.rs b/vm-executor/src/vm_hooks.rs index 6cce8fb..07f0dd7 100644 --- a/vm-executor/src/vm_hooks.rs +++ b/vm-executor/src/vm_hooks.rs @@ -290,6 +290,11 @@ pub trait VMHooksLegacy: core::fmt::Debug { fn managed_verify_secp256r1(&self, key_handle: i32, message_handle: i32, sig_handle: i32) -> i32; fn managed_verify_blssignature_share(&self, key_handle: i32, message_handle: i32, sig_handle: i32) -> i32; fn managed_verify_blsaggregated_signature(&self, key_handle: i32, message_handle: i32, sig_handle: i32) -> i32; + fn activate_unsafe_mode(&self); + fn deactivate_unsafe_mode(&self); + fn managed_get_num_errors(&self) -> i32; + fn managed_get_error_with_index(&self, index: i32, error_handle: i32); + fn managed_get_last_error(&self, error_handle: i32); } /// Dummy implementation for VMHooks. Can be used as placeholder, or in tests. @@ -1585,4 +1590,25 @@ impl VMHooksLegacy for VMHooksLegacyDefault { println!("Called: managed_verify_blsaggregated_signature"); 0 } + + fn activate_unsafe_mode(&self) { + println!("Called: activate_unsafe_mode"); + } + + fn deactivate_unsafe_mode(&self) { + println!("Called: deactivate_unsafe_mode"); + } + + fn managed_get_num_errors(&self) -> i32 { + println!("Called: managed_get_num_errors"); + 0 + } + + fn managed_get_error_with_index(&self, index: i32, error_handle: i32) { + println!("Called: managed_get_error_with_index"); + } + + fn managed_get_last_error(&self, error_handle: i32) { + println!("Called: managed_get_last_error"); + } } From b82a9a6c6aa191f8f4d8a325b0b733464436627f Mon Sep 17 00:00:00 2001 From: Laurentiu Ciobanu Date: Wed, 20 Aug 2025 14:40:41 +0300 Subject: [PATCH 03/35] add capi to check opcode usage --- c-api/libvmexeccapi.h | 9 +++++++ c-api/src/capi_instance.rs | 24 ++++++++++++++++++- vm-executor-wasmer/src/wasmer_instance.rs | 23 ++++++++++++++++-- .../src/wasmer_opcode_control.rs | 20 ++++++++++++++-- vm-executor/src/instance.rs | 5 +++- vm-executor/src/lib.rs | 2 ++ vm-executor/src/opcode_check_used.rs | 22 +++++++++++++++++ 7 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 vm-executor/src/opcode_check_used.rs diff --git a/c-api/libvmexeccapi.h b/c-api/libvmexeccapi.h index 14ab427..b93ab76 100644 --- a/c-api/libvmexeccapi.h +++ b/c-api/libvmexeccapi.h @@ -456,6 +456,15 @@ int vm_exec_instance_has_function(vm_exec_instance_t *instance_ptr, const char * int vm_exec_instance_has_imported_function(vm_exec_instance_t *instance_ptr, const char *func_name_ptr); +/** + * Checks whether the given opcode is used in the wasm module. + * + * # Safety + * + * C API function, works with raw object pointers. + */ +int vm_exec_instance_is_opcode_used(vm_exec_instance_t *instance_ptr, uint32_t opcode_value); + /** * Gets a pointer to the beginning of the contiguous memory data * bytes. diff --git a/c-api/src/capi_instance.rs b/c-api/src/capi_instance.rs index a77fe8a..8938213 100644 --- a/c-api/src/capi_instance.rs +++ b/c-api/src/capi_instance.rs @@ -7,7 +7,7 @@ use crate::{ }; use libc::{c_char, c_int}; use meta::capi_safe_unwind; -use multiversx_chain_vm_executor::{CompilationOptionsLegacy, InstanceLegacy}; +use multiversx_chain_vm_executor::{CompilationOptionsLegacy, InstanceLegacy, OpcodeCheckUsed}; use std::{ffi::CStr, slice}; /// Opaque pointer to a `wasmer_runtime::Instance` value in Rust. @@ -187,6 +187,28 @@ pub unsafe extern "C" fn vm_exec_instance_has_imported_function( } +/// Checks whether the given opcode is used in the wasm module. +/// +/// # Safety +/// +/// C API function, works with raw object pointers. +#[allow(clippy::cast_ptr_alignment)] +#[no_mangle] +#[capi_safe_unwind(-1)] +pub unsafe extern "C" fn vm_exec_instance_is_opcode_used( + instance_ptr: *mut vm_exec_instance_t, + opcode_value: u32, +) -> c_int { + let capi_instance = cast_input_ptr!(instance_ptr, CapiInstance, "instance ptr is null", -1); + + let Some(opcode) = OpcodeCheckUsed::from_value(opcode_value) else { + with_service(|service| service.update_last_error_str("invalid opcode value".to_string())); + return -1; + }; + + c_int::from(capi_instance.content.is_opcode_used(opcode)) +} + /// Required to be able to extract all SC endpoint names. See `vm_exported_function_names`. /// /// # Safety diff --git a/vm-executor-wasmer/src/wasmer_instance.rs b/vm-executor-wasmer/src/wasmer_instance.rs index ac350fe..a2521d1 100644 --- a/vm-executor-wasmer/src/wasmer_instance.rs +++ b/vm-executor-wasmer/src/wasmer_instance.rs @@ -9,8 +9,10 @@ use crate::{ wasmer_opcode_control::OpcodeControl, wasmer_vm_hooks::VMHooksWrapper, }; use log::trace; +use multiversx_chain_vm_executor::OpcodeCheckUsed; use std::cell::RefCell; +use std::collections::HashSet; use std::sync::Mutex; use std::{rc::Rc, sync::Arc}; use wasmer::{ExternType, Universal}; @@ -23,6 +25,7 @@ pub struct WasmerInstance { pub(crate) wasmer_instance: wasmer::Instance, memory_name: String, early_exit_cell: RefCell>, + used_opcodes: Arc>>, } impl WasmerInstance { @@ -35,8 +38,10 @@ impl WasmerInstance { // Use Singlepass compiler with the default settings let mut compiler = Singlepass::default(); + let used_opcodes = Arc::new(Mutex::new(HashSet::new())); + // Push middlewares - push_middlewares(&mut compiler, compilation_options, opcode_cost); + push_middlewares(&mut compiler, compilation_options, opcode_cost, used_opcodes.clone()); // Create the store let store = Store::new(&Universal::new(compiler).engine()); @@ -69,6 +74,7 @@ impl WasmerInstance { wasmer_instance, memory_name, early_exit_cell: RefCell::new(None), + used_opcodes, }) } @@ -81,8 +87,10 @@ impl WasmerInstance { // Use Singlepass compiler with the default settings let mut compiler = Singlepass::default(); + let used_opcodes = Arc::new(Mutex::new(HashSet::new())); + // Push middlewares - push_middlewares(&mut compiler, compilation_options, opcode_cost); + push_middlewares(&mut compiler, compilation_options, opcode_cost, used_opcodes.clone()); // Create the store let store = Store::new(&Universal::new(compiler).engine()); @@ -118,6 +126,7 @@ impl WasmerInstance { wasmer_instance, memory_name, early_exit_cell: RefCell::new(None), + used_opcodes, }) } @@ -184,6 +193,7 @@ fn push_middlewares( compiler: &mut Singlepass, compilation_options: &CompilationOptionsLegacy, opcode_cost: Arc>, + used_opcodes: Arc>>, ) { // Create breakpoints middleware let breakpoints_middleware = Arc::new(Breakpoints::new()); @@ -194,6 +204,7 @@ fn push_middlewares( compilation_options.max_memory_grow, compilation_options.max_memory_grow_delta, breakpoints_middleware.clone(), + used_opcodes, )); // Create metering middleware @@ -281,6 +292,14 @@ impl InstanceLegacy for WasmerInstance { false } + fn is_opcode_used(&self, opcode: OpcodeCheckUsed) -> bool { + let Ok(used_opcodes) = self.used_opcodes.lock() else { + return false; + }; + + used_opcodes.contains(&opcode) + } + fn get_exported_function_names(&self) -> Vec { self.wasmer_instance .exports diff --git a/vm-executor-wasmer/src/wasmer_opcode_control.rs b/vm-executor-wasmer/src/wasmer_opcode_control.rs index 631e163..f2dc7b1 100644 --- a/vm-executor-wasmer/src/wasmer_opcode_control.rs +++ b/vm-executor-wasmer/src/wasmer_opcode_control.rs @@ -1,9 +1,9 @@ use std::{ - mem, - sync::{Arc, Mutex}, + collections::HashSet, mem, sync::{Arc, Mutex} }; use loupe::{MemoryUsage, MemoryUsageTracker}; +use multiversx_chain_vm_executor::OpcodeCheckUsed; use wasmer::{ wasmparser::Operator, FunctionMiddleware, LocalFunctionIndex, MiddlewareError, MiddlewareReaderState, ModuleMiddleware, @@ -32,6 +32,7 @@ pub(crate) struct OpcodeControl { max_memory_grow_delta: usize, breakpoints_middleware: Arc, global_indexes: Mutex>, + used_opcodes: Arc>>, } impl OpcodeControl { @@ -40,6 +41,7 @@ impl OpcodeControl { max_memory_grow: usize, max_memory_grow_delta: usize, breakpoints_middleware: Arc, + used_opcodes: Arc>>, ) -> Self { Self { total_memory_grow_count: Arc::new(Mutex::new(0)), @@ -48,6 +50,7 @@ impl OpcodeControl { max_memory_grow_delta, breakpoints_middleware, global_indexes: Mutex::new(None), + used_opcodes, } } @@ -92,6 +95,7 @@ impl ModuleMiddleware for OpcodeControl { max_memory_grow_delta: self.max_memory_grow_delta, breakpoints_middleware: self.breakpoints_middleware.clone(), global_indexes: self.global_indexes.lock().unwrap().clone().unwrap(), + used_opcodes: self.used_opcodes.clone(), }) } @@ -130,6 +134,7 @@ struct FunctionOpcodeControl { max_memory_grow_delta: usize, breakpoints_middleware: Arc, global_indexes: OpcodeControlGlobalIndexes, + used_opcodes: Arc>>, } impl FunctionOpcodeControl { @@ -201,6 +206,17 @@ impl FunctionMiddleware for FunctionOpcodeControl { operator: Operator<'b>, state: &mut MiddlewareReaderState<'b>, ) -> Result<(), MiddlewareError> { + let used_opcode = match operator { + Operator::MemoryGrow { .. } => Some(OpcodeCheckUsed::MemoryCopy), + Operator::MemoryFill { .. } => Some(OpcodeCheckUsed::MemoryFill), + _ => None, + }; + + if let Some(used_opcode) = used_opcode { + let mut used_opcodes = self.used_opcodes.lock().map_err(|_| MiddlewareError::new("UsedOpcodes", "failed to lock used_opcodes"))?; + used_opcodes.insert(used_opcode); + } + if matches!(operator, Operator::MemoryGrow { .. }) { let mut grow_count = self .total_memory_grow_count diff --git a/vm-executor/src/instance.rs b/vm-executor/src/instance.rs index aec8d07..d9b2347 100644 --- a/vm-executor/src/instance.rs +++ b/vm-executor/src/instance.rs @@ -1,4 +1,4 @@ -use crate::{BreakpointValueLegacy, ExecutorError, MemLength, MemPtr}; +use crate::{BreakpointValueLegacy, ExecutorError, MemLength, MemPtr, OpcodeCheckUsed}; /// The old instance trait, used both: /// - from the "outside": configuring & calling the instance; @@ -16,6 +16,9 @@ pub trait InstanceLegacy { /// Checks whether SC has an imported function with given name. fn has_imported_function(&self, func_name: &str) -> bool; + /// Checks whether the given opcode is used in the instance. + fn is_opcode_used(&self, opcode: OpcodeCheckUsed) -> bool; + /// Required to be able to extract all SC endpoint names. fn get_exported_function_names(&self) -> Vec; diff --git a/vm-executor/src/lib.rs b/vm-executor/src/lib.rs index fe7afdb..e3a3f71 100644 --- a/vm-executor/src/lib.rs +++ b/vm-executor/src/lib.rs @@ -5,6 +5,7 @@ mod instance; mod missing_wasm; mod new_traits; mod opcode_cost; +mod opcode_check_used; mod service_error; mod service_trait; mod vm_hooks; @@ -16,6 +17,7 @@ pub use instance::InstanceLegacy; pub use missing_wasm::{check_missing_wasm, MissingWasmError}; pub use new_traits::*; pub use opcode_cost::OpcodeCost; +pub use opcode_check_used::OpcodeCheckUsed; pub use service_error::ServiceError; pub use service_trait::*; pub use vm_hooks::{VMHooksLegacy, VMHooksLegacyDefault}; diff --git a/vm-executor/src/opcode_check_used.rs b/vm-executor/src/opcode_check_used.rs new file mode 100644 index 0000000..df857fd --- /dev/null +++ b/vm-executor/src/opcode_check_used.rs @@ -0,0 +1,22 @@ +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum OpcodeCheckUsed { + MemoryCopy, + MemoryFill, +} + +impl OpcodeCheckUsed { + pub fn from_value(value: u32) -> Option { + match value { + 0 => Some(Self::MemoryCopy), + 1 => Some(Self::MemoryFill), + _ => None, + } + } + + pub fn as_u32(self) -> u32 { + match self { + Self::MemoryCopy => 0, + Self::MemoryFill => 1, + } + } +} \ No newline at end of file From 642fa74808d8461f65a04899efe696612fc2be0c Mon Sep 17 00:00:00 2001 From: Laurentiu Ciobanu Date: Wed, 20 Aug 2025 14:51:56 +0300 Subject: [PATCH 04/35] fix mem_copy usage detection --- vm-executor-wasmer/src/wasmer_opcode_control.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm-executor-wasmer/src/wasmer_opcode_control.rs b/vm-executor-wasmer/src/wasmer_opcode_control.rs index f2dc7b1..2490a38 100644 --- a/vm-executor-wasmer/src/wasmer_opcode_control.rs +++ b/vm-executor-wasmer/src/wasmer_opcode_control.rs @@ -207,7 +207,7 @@ impl FunctionMiddleware for FunctionOpcodeControl { state: &mut MiddlewareReaderState<'b>, ) -> Result<(), MiddlewareError> { let used_opcode = match operator { - Operator::MemoryGrow { .. } => Some(OpcodeCheckUsed::MemoryCopy), + Operator::MemoryCopy { .. } => Some(OpcodeCheckUsed::MemoryCopy), Operator::MemoryFill { .. } => Some(OpcodeCheckUsed::MemoryFill), _ => None, }; From 5292b717fdf2886179d11711f3d910b458dc8f21 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Thu, 21 Aug 2025 13:41:38 +0300 Subject: [PATCH 05/35] ZK crypto hooks --- c-api/src/capi_vm_hook_pointers.rs | 7 ++++ c-api/src/capi_vm_hooks.rs | 28 +++++++++++++ vm-executor-experimental/src/we_imports.rs | 42 +++++++++++++++++++ vm-executor-wasmer/src/wasmer_imports.rs | 42 +++++++++++++++++++ .../src/new_traits/vm_hooks_legacy_adapter.rs | 28 +++++++++++++ vm-executor/src/new_traits/vm_hooks_new.rs | 42 +++++++++++++++++++ vm-executor/src/vm_hooks.rs | 42 +++++++++++++++++++ 7 files changed, 231 insertions(+) diff --git a/c-api/src/capi_vm_hook_pointers.rs b/c-api/src/capi_vm_hook_pointers.rs index 1200dae..0f423c3 100644 --- a/c-api/src/capi_vm_hook_pointers.rs +++ b/c-api/src/capi_vm_hook_pointers.rs @@ -293,6 +293,13 @@ pub struct vm_exec_vm_hook_c_func_pointers { pub managed_get_num_errors_func_ptr: extern "C" fn(context: *mut c_void) -> i32, pub managed_get_error_with_index_func_ptr: extern "C" fn(context: *mut c_void, index: i32, error_handle: i32), pub managed_get_last_error_func_ptr: extern "C" fn(context: *mut c_void, error_handle: i32), + pub managed_verify_groth16_func_ptr: extern "C" fn(context: *mut c_void, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32, + pub managed_verify_plonk_func_ptr: extern "C" fn(context: *mut c_void, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32, + pub managed_add_ec_func_ptr: extern "C" fn(context: *mut c_void, curve_id: i32, group_id: i32, point1_handle: i32, point2_handle: i32, result_handle: i32) -> i32, + pub managed_mul_ec_func_ptr: extern "C" fn(context: *mut c_void, curve_id: i32, group_id: i32, point_handle: i32, scalar_handle: i32, result_handle: i32) -> i32, + pub managed_multi_exp_ec_func_ptr: extern "C" fn(context: *mut c_void, curve_id: i32, group_id: i32, points_handle: i32, scalars_handle: i32, result_handle: i32) -> i32, + pub managed_map_to_curve_ec_func_ptr: extern "C" fn(context: *mut c_void, curve_id: i32, group_id: i32, element_handle: i32, result_handle: i32) -> i32, + pub managed_pairing_checks_ec_func_ptr: extern "C" fn(context: *mut c_void, curve_id: i32, points_g1_handle: i32, points_g2_handle: i32) -> i32, } impl std::fmt::Debug for vm_exec_vm_hook_c_func_pointers { diff --git a/c-api/src/capi_vm_hooks.rs b/c-api/src/capi_vm_hooks.rs index 5936bd3..6339af6 100644 --- a/c-api/src/capi_vm_hooks.rs +++ b/c-api/src/capi_vm_hooks.rs @@ -1166,4 +1166,32 @@ impl multiversx_chain_vm_executor::VMHooksLegacy for CapiVMHooks { fn managed_get_last_error(&self, error_handle: i32) { (self.c_func_pointers_ptr.managed_get_last_error_func_ptr)(self.vm_hooks_ptr, error_handle) } + + fn managed_verify_groth16(&self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32 { + (self.c_func_pointers_ptr.managed_verify_groth16_func_ptr)(self.vm_hooks_ptr, curve_id, proof_handle, vk_handle, pub_witness_handle) + } + + fn managed_verify_plonk(&self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32 { + (self.c_func_pointers_ptr.managed_verify_plonk_func_ptr)(self.vm_hooks_ptr, curve_id, proof_handle, vk_handle, pub_witness_handle) + } + + fn managed_add_ec(&self, curve_id: i32, group_id: i32, point1_handle: i32, point2_handle: i32, result_handle: i32) -> i32 { + (self.c_func_pointers_ptr.managed_add_ec_func_ptr)(self.vm_hooks_ptr, curve_id, group_id, point1_handle, point2_handle, result_handle) + } + + fn managed_mul_ec(&self, curve_id: i32, group_id: i32, point_handle: i32, scalar_handle: i32, result_handle: i32) -> i32 { + (self.c_func_pointers_ptr.managed_mul_ec_func_ptr)(self.vm_hooks_ptr, curve_id, group_id, point_handle, scalar_handle, result_handle) + } + + fn managed_multi_exp_ec(&self, curve_id: i32, group_id: i32, points_handle: i32, scalars_handle: i32, result_handle: i32) -> i32 { + (self.c_func_pointers_ptr.managed_multi_exp_ec_func_ptr)(self.vm_hooks_ptr, curve_id, group_id, points_handle, scalars_handle, result_handle) + } + + fn managed_map_to_curve_ec(&self, curve_id: i32, group_id: i32, element_handle: i32, result_handle: i32) -> i32 { + (self.c_func_pointers_ptr.managed_map_to_curve_ec_func_ptr)(self.vm_hooks_ptr, curve_id, group_id, element_handle, result_handle) + } + + fn managed_pairing_checks_ec(&self, curve_id: i32, points_g1_handle: i32, points_g2_handle: i32) -> i32 { + (self.c_func_pointers_ptr.managed_pairing_checks_ec_func_ptr)(self.vm_hooks_ptr, curve_id, points_g1_handle, points_g2_handle) + } } diff --git a/vm-executor-experimental/src/we_imports.rs b/vm-executor-experimental/src/we_imports.rs index 78a843e..f43f4dd 100644 --- a/vm-executor-experimental/src/we_imports.rs +++ b/vm-executor-experimental/src/we_imports.rs @@ -1421,6 +1421,41 @@ fn wasmer_import_managed_get_last_error(env: FunctionEnvMut, err with_vm_hooks(env, |vh| vh.managed_get_last_error(error_handle)) } +#[rustfmt::skip] +fn wasmer_import_managed_verify_groth16(env: FunctionEnvMut, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> Result { + with_vm_hooks(env, |vh| vh.managed_verify_groth16(curve_id, proof_handle, vk_handle, pub_witness_handle)) +} + +#[rustfmt::skip] +fn wasmer_import_managed_verify_plonk(env: FunctionEnvMut, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> Result { + with_vm_hooks(env, |vh| vh.managed_verify_plonk(curve_id, proof_handle, vk_handle, pub_witness_handle)) +} + +#[rustfmt::skip] +fn wasmer_import_managed_add_ec(env: FunctionEnvMut, curve_id: i32, group_id: i32, point1_handle: i32, point2_handle: i32, result_handle: i32) -> Result { + with_vm_hooks(env, |vh| vh.managed_add_ec(curve_id, group_id, point1_handle, point2_handle, result_handle)) +} + +#[rustfmt::skip] +fn wasmer_import_managed_mul_ec(env: FunctionEnvMut, curve_id: i32, group_id: i32, point_handle: i32, scalar_handle: i32, result_handle: i32) -> Result { + with_vm_hooks(env, |vh| vh.managed_mul_ec(curve_id, group_id, point_handle, scalar_handle, result_handle)) +} + +#[rustfmt::skip] +fn wasmer_import_managed_multi_exp_ec(env: FunctionEnvMut, curve_id: i32, group_id: i32, points_handle: i32, scalars_handle: i32, result_handle: i32) -> Result { + with_vm_hooks(env, |vh| vh.managed_multi_exp_ec(curve_id, group_id, points_handle, scalars_handle, result_handle)) +} + +#[rustfmt::skip] +fn wasmer_import_managed_map_to_curve_ec(env: FunctionEnvMut, curve_id: i32, group_id: i32, element_handle: i32, result_handle: i32) -> Result { + with_vm_hooks(env, |vh| vh.managed_map_to_curve_ec(curve_id, group_id, element_handle, result_handle)) +} + +#[rustfmt::skip] +fn wasmer_import_managed_pairing_checks_ec(env: FunctionEnvMut, curve_id: i32, points_g1_handle: i32, points_g2_handle: i32) -> Result { + with_vm_hooks(env, |vh| vh.managed_pairing_checks_ec(curve_id, points_g1_handle, points_g2_handle)) +} + pub fn generate_import_object(store: &mut Store, vh_wrapper: VMHooksWrapper) -> Imports { let function_env = FunctionEnv::new(store, vh_wrapper); @@ -1708,6 +1743,13 @@ pub fn generate_import_object(store: &mut Store, vh_wrapper: VMHooksWrapper) -> "managedGetNumErrors" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_get_num_errors), "managedGetErrorWithIndex" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_get_error_with_index), "managedGetLastError" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_get_last_error), + "managedVerifyGroth16" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_verify_groth16), + "managedVerifyPlonk" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_verify_plonk), + "managedAddEC" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_add_ec), + "managedMulEC" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_mul_ec), + "managedMultiExpEC" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_multi_exp_ec), + "managedMapToCurveEC" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_map_to_curve_ec), + "managedPairingChecksEC" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_pairing_checks_ec), } } diff --git a/vm-executor-wasmer/src/wasmer_imports.rs b/vm-executor-wasmer/src/wasmer_imports.rs index 0a7a6ab..3c03add 100644 --- a/vm-executor-wasmer/src/wasmer_imports.rs +++ b/vm-executor-wasmer/src/wasmer_imports.rs @@ -1420,6 +1420,41 @@ fn wasmer_import_managed_get_last_error(env: &VMHooksWrapper, error_handle: i32) env.vm_hooks.managed_get_last_error(error_handle) } +#[rustfmt::skip] +fn wasmer_import_managed_verify_groth16(env: &VMHooksWrapper, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32 { + env.vm_hooks.managed_verify_groth16(curve_id, proof_handle, vk_handle, pub_witness_handle) +} + +#[rustfmt::skip] +fn wasmer_import_managed_verify_plonk(env: &VMHooksWrapper, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32 { + env.vm_hooks.managed_verify_plonk(curve_id, proof_handle, vk_handle, pub_witness_handle) +} + +#[rustfmt::skip] +fn wasmer_import_managed_add_ec(env: &VMHooksWrapper, curve_id: i32, group_id: i32, point1_handle: i32, point2_handle: i32, result_handle: i32) -> i32 { + env.vm_hooks.managed_add_ec(curve_id, group_id, point1_handle, point2_handle, result_handle) +} + +#[rustfmt::skip] +fn wasmer_import_managed_mul_ec(env: &VMHooksWrapper, curve_id: i32, group_id: i32, point_handle: i32, scalar_handle: i32, result_handle: i32) -> i32 { + env.vm_hooks.managed_mul_ec(curve_id, group_id, point_handle, scalar_handle, result_handle) +} + +#[rustfmt::skip] +fn wasmer_import_managed_multi_exp_ec(env: &VMHooksWrapper, curve_id: i32, group_id: i32, points_handle: i32, scalars_handle: i32, result_handle: i32) -> i32 { + env.vm_hooks.managed_multi_exp_ec(curve_id, group_id, points_handle, scalars_handle, result_handle) +} + +#[rustfmt::skip] +fn wasmer_import_managed_map_to_curve_ec(env: &VMHooksWrapper, curve_id: i32, group_id: i32, element_handle: i32, result_handle: i32) -> i32 { + env.vm_hooks.managed_map_to_curve_ec(curve_id, group_id, element_handle, result_handle) +} + +#[rustfmt::skip] +fn wasmer_import_managed_pairing_checks_ec(env: &VMHooksWrapper, curve_id: i32, points_g1_handle: i32, points_g2_handle: i32) -> i32 { + env.vm_hooks.managed_pairing_checks_ec(curve_id, points_g1_handle, points_g2_handle) +} + pub fn generate_import_object(store: &Store, env: &VMHooksWrapper) -> ImportObject { imports! { "env" => { @@ -1705,6 +1740,13 @@ pub fn generate_import_object(store: &Store, env: &VMHooksWrapper) -> ImportObje "managedGetNumErrors" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_get_num_errors), "managedGetErrorWithIndex" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_get_error_with_index), "managedGetLastError" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_get_last_error), + "managedVerifyGroth16" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_verify_groth16), + "managedVerifyPlonk" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_verify_plonk), + "managedAddEC" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_add_ec), + "managedMulEC" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_mul_ec), + "managedMultiExpEC" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_multi_exp_ec), + "managedMapToCurveEC" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_map_to_curve_ec), + "managedPairingChecksEC" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_pairing_checks_ec), } } diff --git a/vm-executor/src/new_traits/vm_hooks_legacy_adapter.rs b/vm-executor/src/new_traits/vm_hooks_legacy_adapter.rs index c79d9b6..e907046 100644 --- a/vm-executor/src/new_traits/vm_hooks_legacy_adapter.rs +++ b/vm-executor/src/new_traits/vm_hooks_legacy_adapter.rs @@ -1174,4 +1174,32 @@ impl VMHooksLegacy for VMHooksLegacyAdapter { fn managed_get_last_error(&self, error_handle: i32) { self.adapt_vm_hooks(|inner| VMHooks::managed_get_last_error(inner, error_handle)) } + + fn managed_verify_groth16(&self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32 { + self.adapt_vm_hooks(|inner| VMHooks::managed_verify_groth16(inner, curve_id, proof_handle, vk_handle, pub_witness_handle)) + } + + fn managed_verify_plonk(&self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32 { + self.adapt_vm_hooks(|inner| VMHooks::managed_verify_plonk(inner, curve_id, proof_handle, vk_handle, pub_witness_handle)) + } + + fn managed_add_ec(&self, curve_id: i32, group_id: i32, point1_handle: i32, point2_handle: i32, result_handle: i32) -> i32 { + self.adapt_vm_hooks(|inner| VMHooks::managed_add_ec(inner, curve_id, group_id, point1_handle, point2_handle, result_handle)) + } + + fn managed_mul_ec(&self, curve_id: i32, group_id: i32, point_handle: i32, scalar_handle: i32, result_handle: i32) -> i32 { + self.adapt_vm_hooks(|inner| VMHooks::managed_mul_ec(inner, curve_id, group_id, point_handle, scalar_handle, result_handle)) + } + + fn managed_multi_exp_ec(&self, curve_id: i32, group_id: i32, points_handle: i32, scalars_handle: i32, result_handle: i32) -> i32 { + self.adapt_vm_hooks(|inner| VMHooks::managed_multi_exp_ec(inner, curve_id, group_id, points_handle, scalars_handle, result_handle)) + } + + fn managed_map_to_curve_ec(&self, curve_id: i32, group_id: i32, element_handle: i32, result_handle: i32) -> i32 { + self.adapt_vm_hooks(|inner| VMHooks::managed_map_to_curve_ec(inner, curve_id, group_id, element_handle, result_handle)) + } + + fn managed_pairing_checks_ec(&self, curve_id: i32, points_g1_handle: i32, points_g2_handle: i32) -> i32 { + self.adapt_vm_hooks(|inner| VMHooks::managed_pairing_checks_ec(inner, curve_id, points_g1_handle, points_g2_handle)) + } } diff --git a/vm-executor/src/new_traits/vm_hooks_new.rs b/vm-executor/src/new_traits/vm_hooks_new.rs index 26a6aa5..fef9070 100644 --- a/vm-executor/src/new_traits/vm_hooks_new.rs +++ b/vm-executor/src/new_traits/vm_hooks_new.rs @@ -291,6 +291,13 @@ pub trait VMHooks: core::fmt::Debug { fn managed_get_num_errors(&mut self) -> Result; fn managed_get_error_with_index(&mut self, index: i32, error_handle: i32) -> Result<(), VMHooksEarlyExit>; fn managed_get_last_error(&mut self, error_handle: i32) -> Result<(), VMHooksEarlyExit>; + fn managed_verify_groth16(&mut self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> Result; + fn managed_verify_plonk(&mut self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> Result; + fn managed_add_ec(&mut self, curve_id: i32, group_id: i32, point1_handle: i32, point2_handle: i32, result_handle: i32) -> Result; + fn managed_mul_ec(&mut self, curve_id: i32, group_id: i32, point_handle: i32, scalar_handle: i32, result_handle: i32) -> Result; + fn managed_multi_exp_ec(&mut self, curve_id: i32, group_id: i32, points_handle: i32, scalars_handle: i32, result_handle: i32) -> Result; + fn managed_map_to_curve_ec(&mut self, curve_id: i32, group_id: i32, element_handle: i32, result_handle: i32) -> Result; + fn managed_pairing_checks_ec(&mut self, curve_id: i32, points_g1_handle: i32, points_g2_handle: i32) -> Result; } /// Dummy implementation for VMHooks. Can be used as placeholder, or in tests. @@ -1709,4 +1716,39 @@ impl VMHooks for VMHooksDefault { println!("Called: managed_get_last_error"); Ok(()) } + + fn managed_verify_groth16(&mut self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> Result { + println!("Called: managed_verify_groth16"); + Ok(0) + } + + fn managed_verify_plonk(&mut self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> Result { + println!("Called: managed_verify_plonk"); + Ok(0) + } + + fn managed_add_ec(&mut self, curve_id: i32, group_id: i32, point1_handle: i32, point2_handle: i32, result_handle: i32) -> Result { + println!("Called: managed_add_ec"); + Ok(0) + } + + fn managed_mul_ec(&mut self, curve_id: i32, group_id: i32, point_handle: i32, scalar_handle: i32, result_handle: i32) -> Result { + println!("Called: managed_mul_ec"); + Ok(0) + } + + fn managed_multi_exp_ec(&mut self, curve_id: i32, group_id: i32, points_handle: i32, scalars_handle: i32, result_handle: i32) -> Result { + println!("Called: managed_multi_exp_ec"); + Ok(0) + } + + fn managed_map_to_curve_ec(&mut self, curve_id: i32, group_id: i32, element_handle: i32, result_handle: i32) -> Result { + println!("Called: managed_map_to_curve_ec"); + Ok(0) + } + + fn managed_pairing_checks_ec(&mut self, curve_id: i32, points_g1_handle: i32, points_g2_handle: i32) -> Result { + println!("Called: managed_pairing_checks_ec"); + Ok(0) + } } diff --git a/vm-executor/src/vm_hooks.rs b/vm-executor/src/vm_hooks.rs index 07f0dd7..5c742f1 100644 --- a/vm-executor/src/vm_hooks.rs +++ b/vm-executor/src/vm_hooks.rs @@ -295,6 +295,13 @@ pub trait VMHooksLegacy: core::fmt::Debug { fn managed_get_num_errors(&self) -> i32; fn managed_get_error_with_index(&self, index: i32, error_handle: i32); fn managed_get_last_error(&self, error_handle: i32); + fn managed_verify_groth16(&self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32; + fn managed_verify_plonk(&self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32; + fn managed_add_ec(&self, curve_id: i32, group_id: i32, point1_handle: i32, point2_handle: i32, result_handle: i32) -> i32; + fn managed_mul_ec(&self, curve_id: i32, group_id: i32, point_handle: i32, scalar_handle: i32, result_handle: i32) -> i32; + fn managed_multi_exp_ec(&self, curve_id: i32, group_id: i32, points_handle: i32, scalars_handle: i32, result_handle: i32) -> i32; + fn managed_map_to_curve_ec(&self, curve_id: i32, group_id: i32, element_handle: i32, result_handle: i32) -> i32; + fn managed_pairing_checks_ec(&self, curve_id: i32, points_g1_handle: i32, points_g2_handle: i32) -> i32; } /// Dummy implementation for VMHooks. Can be used as placeholder, or in tests. @@ -1611,4 +1618,39 @@ impl VMHooksLegacy for VMHooksLegacyDefault { fn managed_get_last_error(&self, error_handle: i32) { println!("Called: managed_get_last_error"); } + + fn managed_verify_groth16(&self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32 { + println!("Called: managed_verify_groth16"); + 0 + } + + fn managed_verify_plonk(&self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32 { + println!("Called: managed_verify_plonk"); + 0 + } + + fn managed_add_ec(&self, curve_id: i32, group_id: i32, point1_handle: i32, point2_handle: i32, result_handle: i32) -> i32 { + println!("Called: managed_add_ec"); + 0 + } + + fn managed_mul_ec(&self, curve_id: i32, group_id: i32, point_handle: i32, scalar_handle: i32, result_handle: i32) -> i32 { + println!("Called: managed_mul_ec"); + 0 + } + + fn managed_multi_exp_ec(&self, curve_id: i32, group_id: i32, points_handle: i32, scalars_handle: i32, result_handle: i32) -> i32 { + println!("Called: managed_multi_exp_ec"); + 0 + } + + fn managed_map_to_curve_ec(&self, curve_id: i32, group_id: i32, element_handle: i32, result_handle: i32) -> i32 { + println!("Called: managed_map_to_curve_ec"); + 0 + } + + fn managed_pairing_checks_ec(&self, curve_id: i32, points_g1_handle: i32, points_g2_handle: i32) -> i32 { + println!("Called: managed_pairing_checks_ec"); + 0 + } } From 265657f153eb107fbc3bbd9972f9b1f548b2537a Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Wed, 27 Aug 2025 18:11:13 +0300 Subject: [PATCH 06/35] removed get_local_cost, fmt --- c-api/src/capi_instance.rs | 1 - c-api/src/capi_logger.rs | 3 +- .../src/middlewares/we_metering.rs | 5 ++- .../src/middlewares/we_metering_helpers.rs | 4 --- vm-executor-wasmer/src/wasmer_helpers.rs | 5 ++- vm-executor-wasmer/src/wasmer_instance.rs | 19 ++++++++--- vm-executor-wasmer/src/wasmer_metering.rs | 32 ++++++++++++------- .../src/wasmer_metering_helpers.rs | 4 --- .../src/wasmer_opcode_control.rs | 9 ++++-- vm-executor/src/lib.rs | 4 +-- vm-executor/src/opcode_check_used.rs | 2 +- 11 files changed, 49 insertions(+), 39 deletions(-) diff --git a/c-api/src/capi_instance.rs b/c-api/src/capi_instance.rs index 8938213..fadee79 100644 --- a/c-api/src/capi_instance.rs +++ b/c-api/src/capi_instance.rs @@ -186,7 +186,6 @@ pub unsafe extern "C" fn vm_exec_instance_has_imported_function( c_int::from(capi_instance.content.has_imported_function(func_name_r)) } - /// Checks whether the given opcode is used in the wasm module. /// /// # Safety diff --git a/c-api/src/capi_logger.rs b/c-api/src/capi_logger.rs index 0638d29..e516a09 100644 --- a/c-api/src/capi_logger.rs +++ b/c-api/src/capi_logger.rs @@ -5,13 +5,12 @@ use multiversx_chain_vm_executor_wasmer::{set_log_level, u64_to_log_level}; use crate::{basic_types::vm_exec_result_t, service_singleton::with_service}; - static PANIC_HANDLER: Once = Once::new(); pub fn set_panic_handler() { // Initialize the panic handler only once PANIC_HANDLER.call_once(|| { - std::panic::set_hook(Box::new(|_| { })); + std::panic::set_hook(Box::new(|_| {})); }); } diff --git a/vm-executor-experimental/src/middlewares/we_metering.rs b/vm-executor-experimental/src/middlewares/we_metering.rs index 74abe90..4c1184a 100644 --- a/vm-executor-experimental/src/middlewares/we_metering.rs +++ b/vm-executor-experimental/src/middlewares/we_metering.rs @@ -1,8 +1,7 @@ #![allow(unused)] // TODO: until we activate the local count mechanism use super::{ - get_local_cost, get_opcode_cost, Breakpoints, MiddlewareWithProtectedGlobals, - BREAKPOINT_VALUE_OUT_OF_GAS, + get_opcode_cost, Breakpoints, MiddlewareWithProtectedGlobals, BREAKPOINT_VALUE_OUT_OF_GAS, }; use crate::we_helpers::{ create_global_index, get_global_value_u64, is_control_flow_operator, set_global_value_u64, @@ -182,7 +181,7 @@ impl FunctionMiddleware for FunctionMetering { // let unmetered_locals = self.unmetered_locals as u32; // if count > unmetered_locals { // let metered_locals = count - unmetered_locals; - // let local_cost = get_local_cost(&self.opcode_cost.lock().unwrap()); + // let local_cost = self.opcode_cost.lock().unwrap().opcode_localallocate; // let metered_locals_cost = metered_locals * local_cost; // self.accumulated_cost += metered_locals_cost as u64; // } diff --git a/vm-executor-experimental/src/middlewares/we_metering_helpers.rs b/vm-executor-experimental/src/middlewares/we_metering_helpers.rs index f2e895f..05a45fb 100644 --- a/vm-executor-experimental/src/middlewares/we_metering_helpers.rs +++ b/vm-executor-experimental/src/middlewares/we_metering_helpers.rs @@ -7,10 +7,6 @@ use multiversx_chain_vm_executor::OpcodeCost; use wasmer::wasmparser::Operator; -pub fn get_local_cost(opcode_cost: &OpcodeCost) -> u32 { - opcode_cost.opcode_localallocate -} - pub fn get_opcode_cost(op: &Operator, opcode_cost: &OpcodeCost) -> Option { match op { Operator::Block { .. } => Some(opcode_cost.opcode_block), diff --git a/vm-executor-wasmer/src/wasmer_helpers.rs b/vm-executor-wasmer/src/wasmer_helpers.rs index 34ca39a..86a8ef0 100644 --- a/vm-executor-wasmer/src/wasmer_helpers.rs +++ b/vm-executor-wasmer/src/wasmer_helpers.rs @@ -83,10 +83,9 @@ pub(crate) fn is_control_flow_operator(operator: &Operator) -> bool { ) } -pub (crate) fn is_supported_bulk_memory_operator(operator: &Operator) -> bool { +pub(crate) fn is_supported_bulk_memory_operator(operator: &Operator) -> bool { matches!( operator, - Operator::MemoryCopy { src: _, dst: _ } - | Operator::MemoryFill { mem: _ } + Operator::MemoryCopy { src: _, dst: _ } | Operator::MemoryFill { mem: _ } ) } diff --git a/vm-executor-wasmer/src/wasmer_instance.rs b/vm-executor-wasmer/src/wasmer_instance.rs index a2521d1..e0b75de 100644 --- a/vm-executor-wasmer/src/wasmer_instance.rs +++ b/vm-executor-wasmer/src/wasmer_instance.rs @@ -15,8 +15,8 @@ use std::cell::RefCell; use std::collections::HashSet; use std::sync::Mutex; use std::{rc::Rc, sync::Arc}; -use wasmer::{ExternType, Universal}; use wasmer::{CompilerConfig, Extern, Module, Store}; +use wasmer::{ExternType, Universal}; use wasmer::{Pages, Singlepass}; const MAX_MEMORY_PAGES_ALLOWED: Pages = Pages(20); @@ -41,7 +41,12 @@ impl WasmerInstance { let used_opcodes = Arc::new(Mutex::new(HashSet::new())); // Push middlewares - push_middlewares(&mut compiler, compilation_options, opcode_cost, used_opcodes.clone()); + push_middlewares( + &mut compiler, + compilation_options, + opcode_cost, + used_opcodes.clone(), + ); // Create the store let store = Store::new(&Universal::new(compiler).engine()); @@ -90,7 +95,12 @@ impl WasmerInstance { let used_opcodes = Arc::new(Mutex::new(HashSet::new())); // Push middlewares - push_middlewares(&mut compiler, compilation_options, opcode_cost, used_opcodes.clone()); + push_middlewares( + &mut compiler, + compilation_options, + opcode_cost, + used_opcodes.clone(), + ); // Create the store let store = Store::new(&Universal::new(compiler).engine()); @@ -280,7 +290,6 @@ impl InstanceLegacy for WasmerInstance { } fn has_imported_function(&self, func_name: &str) -> bool { - for import in self.wasmer_instance.module().imports() { if let ExternType::Function(_) = import.ty() { if import.name() == func_name { @@ -296,7 +305,7 @@ impl InstanceLegacy for WasmerInstance { let Ok(used_opcodes) = self.used_opcodes.lock() else { return false; }; - + used_opcodes.contains(&opcode) } diff --git a/vm-executor-wasmer/src/wasmer_metering.rs b/vm-executor-wasmer/src/wasmer_metering.rs index 658929c..83f9e79 100644 --- a/vm-executor-wasmer/src/wasmer_metering.rs +++ b/vm-executor-wasmer/src/wasmer_metering.rs @@ -1,9 +1,10 @@ use crate::executor_interface::OpcodeCost; +use crate::get_opcode_cost; use crate::wasmer_breakpoints::{Breakpoints, BREAKPOINT_VALUE_OUT_OF_GAS}; use crate::wasmer_helpers::{ - create_global_index, get_global_value_u64, is_control_flow_operator, is_supported_bulk_memory_operator, set_global_value_u64, MiddlewareWithProtectedGlobals + create_global_index, get_global_value_u64, is_control_flow_operator, + is_supported_bulk_memory_operator, set_global_value_u64, MiddlewareWithProtectedGlobals, }; -use crate::{get_local_cost, get_opcode_cost}; use loupe::{MemoryUsage, MemoryUsageTracker}; use std::mem; use std::sync::{Arc, Mutex}; @@ -129,7 +130,8 @@ impl MiddlewareWithProtectedGlobals for Metering { vec![ self.get_points_limit_global_index().as_u32(), self.get_points_used_global_index().as_u32(), - self.get_bulk_memory_size_operand_backup_global_index().as_u32(), + self.get_bulk_memory_size_operand_backup_global_index() + .as_u32(), ] } } @@ -176,20 +178,25 @@ impl FunctionMetering { fn inject_bulk_memory_cost(&self, state: &mut MiddlewareReaderState, cost_per_byte: u32) { // backup the bulk memory size state.extend(&[Operator::GlobalSet { - global_index: self.global_indexes.bulk_memory_size_operand_backup_global_index.as_u32(), + global_index: self + .global_indexes + .bulk_memory_size_operand_backup_global_index + .as_u32(), }]); // inject bulk memory cost state.extend(&[ // memory size * price Operator::GlobalGet { - global_index: self.global_indexes.bulk_memory_size_operand_backup_global_index.as_u32(), + global_index: self + .global_indexes + .bulk_memory_size_operand_backup_global_index + .as_u32(), }, Operator::I64Const { value: cost_per_byte as i64, }, Operator::I64Mul, - // points user += memory size * price Operator::GlobalGet { global_index: self.global_indexes.points_used_global_index.as_u32(), @@ -202,7 +209,10 @@ impl FunctionMetering { // bring back the bulk memory size state.extend(&[Operator::GlobalGet { - global_index: self.global_indexes.bulk_memory_size_operand_backup_global_index.as_u32(), + global_index: self + .global_indexes + .bulk_memory_size_operand_backup_global_index + .as_u32(), }]); } } @@ -222,10 +232,8 @@ impl FunctionMiddleware for FunctionMetering { self.inject_bulk_memory_cost(state, cost); // immediatly insert out of gas check as this operation might be expensive self.inject_out_of_gas_check(state); - }, - Some(cost) => { - self.accumulated_cost += cost as u64 - }, + } + Some(cost) => self.accumulated_cost += cost as u64, None => { return Err(MiddlewareError::new( "metering_middleware", @@ -252,7 +260,7 @@ impl FunctionMiddleware for FunctionMetering { let unmetered_locals = self.unmetered_locals as u32; if count > unmetered_locals { let metered_locals = count - unmetered_locals; - let local_cost = get_local_cost(&self.opcode_cost.lock().unwrap()); + let local_cost = self.opcode_cost.lock().unwrap().opcode_localallocate; let metered_locals_cost = metered_locals * local_cost; self.accumulated_cost += metered_locals_cost as u64; } diff --git a/vm-executor-wasmer/src/wasmer_metering_helpers.rs b/vm-executor-wasmer/src/wasmer_metering_helpers.rs index 9e7432d..8d0974c 100644 --- a/vm-executor-wasmer/src/wasmer_metering_helpers.rs +++ b/vm-executor-wasmer/src/wasmer_metering_helpers.rs @@ -7,10 +7,6 @@ use crate::executor_interface::OpcodeCost; use wasmer::wasmparser::Operator; -pub fn get_local_cost(opcode_cost: &OpcodeCost) -> u32 { - opcode_cost.opcode_localallocate -} - pub fn get_opcode_cost(op: &Operator, opcode_cost: &OpcodeCost) -> Option { match op { Operator::Block { .. } => Some(opcode_cost.opcode_block), diff --git a/vm-executor-wasmer/src/wasmer_opcode_control.rs b/vm-executor-wasmer/src/wasmer_opcode_control.rs index 2490a38..dec868f 100644 --- a/vm-executor-wasmer/src/wasmer_opcode_control.rs +++ b/vm-executor-wasmer/src/wasmer_opcode_control.rs @@ -1,5 +1,7 @@ use std::{ - collections::HashSet, mem, sync::{Arc, Mutex} + collections::HashSet, + mem, + sync::{Arc, Mutex}, }; use loupe::{MemoryUsage, MemoryUsageTracker}; @@ -213,7 +215,10 @@ impl FunctionMiddleware for FunctionOpcodeControl { }; if let Some(used_opcode) = used_opcode { - let mut used_opcodes = self.used_opcodes.lock().map_err(|_| MiddlewareError::new("UsedOpcodes", "failed to lock used_opcodes"))?; + let mut used_opcodes = self + .used_opcodes + .lock() + .map_err(|_| MiddlewareError::new("UsedOpcodes", "failed to lock used_opcodes"))?; used_opcodes.insert(used_opcode); } diff --git a/vm-executor/src/lib.rs b/vm-executor/src/lib.rs index e3a3f71..fa3b769 100644 --- a/vm-executor/src/lib.rs +++ b/vm-executor/src/lib.rs @@ -4,8 +4,8 @@ mod executor; mod instance; mod missing_wasm; mod new_traits; -mod opcode_cost; mod opcode_check_used; +mod opcode_cost; mod service_error; mod service_trait; mod vm_hooks; @@ -16,8 +16,8 @@ pub use executor::ExecutorLegacy; pub use instance::InstanceLegacy; pub use missing_wasm::{check_missing_wasm, MissingWasmError}; pub use new_traits::*; -pub use opcode_cost::OpcodeCost; pub use opcode_check_used::OpcodeCheckUsed; +pub use opcode_cost::OpcodeCost; pub use service_error::ServiceError; pub use service_trait::*; pub use vm_hooks::{VMHooksLegacy, VMHooksLegacyDefault}; diff --git a/vm-executor/src/opcode_check_used.rs b/vm-executor/src/opcode_check_used.rs index df857fd..a335edb 100644 --- a/vm-executor/src/opcode_check_used.rs +++ b/vm-executor/src/opcode_check_used.rs @@ -19,4 +19,4 @@ impl OpcodeCheckUsed { Self::MemoryFill => 1, } } -} \ No newline at end of file +} From 00162a721b291aadb4ea7d79213f75a59cc79fd8 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Mon, 1 Sep 2025 19:24:50 +0300 Subject: [PATCH 07/35] opcode version, opcode config refactor --- c-api/libvmexeccapi.h | 5 +- c-api/src/capi_metering.rs | 24 ++- .../src/middlewares/we_metering.rs | 14 +- .../src/middlewares/we_metering_helpers.rs | 147 +++++++++++++++++- vm-executor-experimental/src/we_executor.rs | 6 +- vm-executor-experimental/src/we_instance.rs | 10 +- .../tests/common/test_instance.rs | 4 +- .../src/new_traits/wasmer_prod_executor.rs | 6 +- vm-executor-wasmer/src/wasmer_executor.rs | 35 +++-- vm-executor-wasmer/src/wasmer_instance.rs | 16 +- vm-executor-wasmer/src/wasmer_metering.rs | 21 ++- .../src/wasmer_metering_helpers.rs | 145 ++++++++++++++++- vm-executor/src/executor.rs | 6 +- vm-executor/src/lib.rs | 4 + vm-executor/src/opcode_config.rs | 16 ++ vm-executor/src/opcode_version.rs | 15 ++ 16 files changed, 413 insertions(+), 61 deletions(-) create mode 100644 vm-executor/src/opcode_config.rs create mode 100644 vm-executor/src/opcode_version.rs diff --git a/c-api/libvmexeccapi.h b/c-api/libvmexeccapi.h index b93ab76..0756920 100644 --- a/c-api/libvmexeccapi.h +++ b/c-api/libvmexeccapi.h @@ -628,8 +628,9 @@ vm_exec_result_t vm_exec_set_log_level(uint64_t value); * * C API function, works with raw object pointers. */ -vm_exec_result_t vm_exec_set_opcode_costs(vm_exec_executor_t *executor_ptr, - const vm_exec_opcode_cost_t *opcode_cost_ptr); +vm_exec_result_t vm_exec_set_opcode_config(vm_exec_executor_t *executor_ptr, + int32_t opcode_vesion_code, + const vm_exec_opcode_cost_t *opcode_cost_ptr); /** * Returns all SC endpoint names, separated by pipes. diff --git a/c-api/src/capi_metering.rs b/c-api/src/capi_metering.rs index 838cc39..15b9d48 100644 --- a/c-api/src/capi_metering.rs +++ b/c-api/src/capi_metering.rs @@ -3,7 +3,7 @@ use crate::capi_instance::{vm_exec_instance_t, CapiInstance}; use crate::service_singleton::with_service; use crate::vm_exec_result_t; use meta::capi_safe_unwind; -use multiversx_chain_vm_executor::OpcodeCost; +use multiversx_chain_vm_executor::{OpcodeConfig, OpcodeCost, OpcodeVersion}; #[allow(non_camel_case_types)] #[repr(C)] @@ -21,14 +21,30 @@ pub struct vm_exec_opcode_cost_t; #[allow(clippy::cast_ptr_alignment)] #[no_mangle] #[capi_safe_unwind(vm_exec_result_t::VM_EXEC_ERROR)] -pub unsafe extern "C" fn vm_exec_set_opcode_costs( +pub unsafe extern "C" fn vm_exec_set_opcode_config( executor_ptr: *mut vm_exec_executor_t, + opcode_vesion_code: i32, opcode_cost_ptr: *const vm_exec_opcode_cost_t, ) -> vm_exec_result_t { let capi_executor = cast_input_ptr!(executor_ptr, CapiExecutor, "executor ptr is null"); - let opcode_costs: &OpcodeCost = &*(opcode_cost_ptr as *const OpcodeCost); - let result = capi_executor.content.set_opcode_cost(opcode_costs); + let Some(opcode_version) = OpcodeVersion::from_i32(opcode_vesion_code) else { + with_service(|service| { + service.update_last_error_str(format!( + "invalid opcode version code: {}", + opcode_vesion_code + )) + }); + return vm_exec_result_t::VM_EXEC_ERROR; + }; + + let opcode_costs_ref: &OpcodeCost = &*(opcode_cost_ptr as *const OpcodeCost); + let opcode_config = OpcodeConfig { + opcode_version, + opcode_cost: opcode_costs_ref.clone(), + }; + + let result = capi_executor.content.set_opcode_config(opcode_config); match result { Ok(()) => vm_exec_result_t::VM_EXEC_OK, Err(message) => { diff --git a/vm-executor-experimental/src/middlewares/we_metering.rs b/vm-executor-experimental/src/middlewares/we_metering.rs index 4c1184a..900f76d 100644 --- a/vm-executor-experimental/src/middlewares/we_metering.rs +++ b/vm-executor-experimental/src/middlewares/we_metering.rs @@ -6,7 +6,7 @@ use super::{ use crate::we_helpers::{ create_global_index, get_global_value_u64, is_control_flow_operator, set_global_value_u64, }; -use multiversx_chain_vm_executor::{ExecutorError, OpcodeCost}; +use multiversx_chain_vm_executor::{ExecutorError, OpcodeConfig, OpcodeCost}; use std::mem; use std::sync::{Arc, Mutex}; use wasmer::sys::{FunctionMiddleware, MiddlewareReaderState, ModuleMiddleware}; @@ -28,7 +28,7 @@ struct MeteringGlobalIndexes { #[derive(Debug)] pub(crate) struct Metering { unmetered_locals: usize, - opcode_cost: Arc, + opcode_config: Arc, breakpoints_middleware: Arc, global_indexes: Mutex>, } @@ -36,12 +36,12 @@ pub(crate) struct Metering { impl Metering { pub(crate) fn new( unmetered_locals: usize, - opcode_cost: Arc, + opcode_config: Arc, breakpoints_middleware: Arc, ) -> Self { Self { unmetered_locals, - opcode_cost, + opcode_config, breakpoints_middleware, global_indexes: Mutex::new(None), } @@ -77,7 +77,7 @@ impl ModuleMiddleware for Metering { Box::new(FunctionMetering { accumulated_cost: Default::default(), unmetered_locals: self.unmetered_locals, - opcode_cost: self.opcode_cost.clone(), + opcode_config: self.opcode_config.clone(), breakpoints_middleware: self.breakpoints_middleware.clone(), global_indexes: self.global_indexes.lock().unwrap().clone().unwrap(), }) @@ -103,7 +103,7 @@ impl ModuleMiddleware for Metering { struct FunctionMetering { accumulated_cost: u64, unmetered_locals: usize, - opcode_cost: Arc, + opcode_config: Arc, breakpoints_middleware: Arc, global_indexes: MeteringGlobalIndexes, } @@ -148,7 +148,7 @@ impl FunctionMiddleware for FunctionMetering { // Get the cost of the current operator, and add it to the accumulator. // This needs to be done before the metering logic, to prevent operators like `Call` from escaping metering in some // corner cases. - let option = get_opcode_cost(&operator, &self.opcode_cost); + let option = get_opcode_cost(&operator, &self.opcode_config); match option { Some(cost) => self.accumulated_cost += cost as u64, None => { diff --git a/vm-executor-experimental/src/middlewares/we_metering_helpers.rs b/vm-executor-experimental/src/middlewares/we_metering_helpers.rs index 05a45fb..0c9d568 100644 --- a/vm-executor-experimental/src/middlewares/we_metering_helpers.rs +++ b/vm-executor-experimental/src/middlewares/we_metering_helpers.rs @@ -4,10 +4,17 @@ // !!!!!!!!!!!!!!!!!!!!!! AUTO-GENERATED FILE !!!!!!!!!!!!!!!!!!!!!! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -use multiversx_chain_vm_executor::OpcodeCost; +use multiversx_chain_vm_executor::{OpcodeConfig, OpcodeCost, OpcodeVersion}; use wasmer::wasmparser::Operator; -pub fn get_opcode_cost(op: &Operator, opcode_cost: &OpcodeCost) -> Option { +pub fn get_opcode_cost(op: &Operator, opcode_config: &OpcodeConfig) -> Option { + match opcode_config.opcode_version { + OpcodeVersion::V1 => get_opcode_cost_v1(op, &opcode_config.opcode_cost), + OpcodeVersion::V2 => get_opcode_cost_v2(op, &opcode_config.opcode_cost), + } +} + +pub fn get_opcode_cost_v1(op: &Operator, opcode_cost: &OpcodeCost) -> Option { match op { Operator::Block { .. } => Some(opcode_cost.opcode_block), Operator::Br { .. } => Some(opcode_cost.opcode_br), @@ -117,6 +124,8 @@ pub fn get_opcode_cost(op: &Operator, opcode_cost: &OpcodeCost) -> Option { Operator::Loop { .. } => Some(opcode_cost.opcode_loop), Operator::MemoryGrow { .. } => Some(opcode_cost.opcode_memorygrow), Operator::MemorySize { .. } => Some(opcode_cost.opcode_memorysize), + Operator::MemoryCopy { .. } => Some(opcode_cost.opcode_memorycopy), + Operator::MemoryFill { .. } => Some(opcode_cost.opcode_memoryfill), Operator::Nop { .. } => Some(opcode_cost.opcode_nop), Operator::RefFunc { .. } => Some(opcode_cost.opcode_reffunc), Operator::RefIsNull { .. } => Some(opcode_cost.opcode_refisnull), @@ -139,3 +148,137 @@ pub fn get_opcode_cost(op: &Operator, opcode_cost: &OpcodeCost) -> Option { _ => None, } } + +pub fn get_opcode_cost_v2(op: &Operator, opcode_cost: &OpcodeCost) -> Option { + match op { + Operator::Block { .. } => Some(opcode_cost.opcode_block), + Operator::Br { .. } => Some(opcode_cost.opcode_br), + Operator::BrIf { .. } => Some(opcode_cost.opcode_brif), + Operator::BrTable { .. } => Some(opcode_cost.opcode_brtable), + Operator::Call { .. } => Some(opcode_cost.opcode_call), + Operator::CallIndirect { .. } => Some(opcode_cost.opcode_callindirect), + Operator::Catch { .. } => Some(opcode_cost.opcode_catch), + Operator::CatchAll { .. } => Some(opcode_cost.opcode_catchall), + Operator::Delegate { .. } => Some(opcode_cost.opcode_delegate), + Operator::Drop { .. } => Some(opcode_cost.opcode_drop), + Operator::Else { .. } => Some(opcode_cost.opcode_else), + Operator::End { .. } => Some(opcode_cost.opcode_end), + Operator::GlobalGet { .. } => Some(opcode_cost.opcode_globalget), + Operator::GlobalSet { .. } => Some(opcode_cost.opcode_globalset), + Operator::I32Add { .. } => Some(opcode_cost.opcode_i32add), + Operator::I32And { .. } => Some(opcode_cost.opcode_i32and), + Operator::I32Clz { .. } => Some(opcode_cost.opcode_i32clz), + Operator::I32Const { .. } => Some(opcode_cost.opcode_i32const), + Operator::I32Ctz { .. } => Some(opcode_cost.opcode_i32ctz), + Operator::I32DivS { .. } => Some(opcode_cost.opcode_i32divs), + Operator::I32DivU { .. } => Some(opcode_cost.opcode_i32divu), + Operator::I32Eq { .. } => Some(opcode_cost.opcode_i32eq), + Operator::I32Eqz { .. } => Some(opcode_cost.opcode_i32eqz), + Operator::I32Extend16S { .. } => Some(opcode_cost.opcode_i32extend16s), + Operator::I32Extend8S { .. } => Some(opcode_cost.opcode_i32extend8s), + Operator::I32GeS { .. } => Some(opcode_cost.opcode_i32ges), + Operator::I32GeU { .. } => Some(opcode_cost.opcode_i32geu), + Operator::I32GtS { .. } => Some(opcode_cost.opcode_i32gts), + Operator::I32GtU { .. } => Some(opcode_cost.opcode_i32gtu), + Operator::I32LeS { .. } => Some(opcode_cost.opcode_i32les), + Operator::I32LeU { .. } => Some(opcode_cost.opcode_i32leu), + Operator::I32Load { .. } => Some(opcode_cost.opcode_i32load), + Operator::I32Load16S { .. } => Some(opcode_cost.opcode_i32load16s), + Operator::I32Load16U { .. } => Some(opcode_cost.opcode_i32load16u), + Operator::I32Load8S { .. } => Some(opcode_cost.opcode_i32load8s), + Operator::I32Load8U { .. } => Some(opcode_cost.opcode_i32load8u), + Operator::I32LtS { .. } => Some(opcode_cost.opcode_i32lts), + Operator::I32LtU { .. } => Some(opcode_cost.opcode_i32ltu), + Operator::I32Mul { .. } => Some(opcode_cost.opcode_i32mul), + Operator::I32Ne { .. } => Some(opcode_cost.opcode_i32ne), + Operator::I32Or { .. } => Some(opcode_cost.opcode_i32or), + Operator::I32Popcnt { .. } => Some(opcode_cost.opcode_i32popcnt), + Operator::I32RemS { .. } => Some(opcode_cost.opcode_i32rems), + Operator::I32RemU { .. } => Some(opcode_cost.opcode_i32remu), + Operator::I32Rotl { .. } => Some(opcode_cost.opcode_i32rotl), + Operator::I32Rotr { .. } => Some(opcode_cost.opcode_i32rotr), + Operator::I32Shl { .. } => Some(opcode_cost.opcode_i32shl), + Operator::I32ShrS { .. } => Some(opcode_cost.opcode_i32shrs), + Operator::I32ShrU { .. } => Some(opcode_cost.opcode_i32shru), + Operator::I32Store { .. } => Some(opcode_cost.opcode_i32store), + Operator::I32Store16 { .. } => Some(opcode_cost.opcode_i32store16), + Operator::I32Store8 { .. } => Some(opcode_cost.opcode_i32store8), + Operator::I32Sub { .. } => Some(opcode_cost.opcode_i32sub), + Operator::I32WrapI64 { .. } => Some(opcode_cost.opcode_i32wrapi64), + Operator::I32Xor { .. } => Some(opcode_cost.opcode_i32xor), + Operator::I64Add { .. } => Some(opcode_cost.opcode_i64add), + Operator::I64And { .. } => Some(opcode_cost.opcode_i64and), + Operator::I64Clz { .. } => Some(opcode_cost.opcode_i64clz), + Operator::I64Const { .. } => Some(opcode_cost.opcode_i64const), + Operator::I64Ctz { .. } => Some(opcode_cost.opcode_i64ctz), + Operator::I64DivS { .. } => Some(opcode_cost.opcode_i64divs), + Operator::I64DivU { .. } => Some(opcode_cost.opcode_i64divu), + Operator::I64Eq { .. } => Some(opcode_cost.opcode_i64eq), + Operator::I64Eqz { .. } => Some(opcode_cost.opcode_i64eqz), + Operator::I64Extend16S { .. } => Some(opcode_cost.opcode_i64extend16s), + Operator::I64Extend32S { .. } => Some(opcode_cost.opcode_i64extend32s), + Operator::I64Extend8S { .. } => Some(opcode_cost.opcode_i64extend8s), + Operator::I64ExtendI32S { .. } => Some(opcode_cost.opcode_i64extendi32s), + Operator::I64ExtendI32U { .. } => Some(opcode_cost.opcode_i64extendi32u), + Operator::I64GeS { .. } => Some(opcode_cost.opcode_i64ges), + Operator::I64GeU { .. } => Some(opcode_cost.opcode_i64geu), + Operator::I64GtS { .. } => Some(opcode_cost.opcode_i64gts), + Operator::I64GtU { .. } => Some(opcode_cost.opcode_i64gtu), + Operator::I64LeS { .. } => Some(opcode_cost.opcode_i64les), + Operator::I64LeU { .. } => Some(opcode_cost.opcode_i64leu), + Operator::I64Load { .. } => Some(opcode_cost.opcode_i64load), + Operator::I64Load16S { .. } => Some(opcode_cost.opcode_i64load16s), + Operator::I64Load16U { .. } => Some(opcode_cost.opcode_i64load16u), + Operator::I64Load32S { .. } => Some(opcode_cost.opcode_i64load32s), + Operator::I64Load32U { .. } => Some(opcode_cost.opcode_i64load32u), + Operator::I64Load8S { .. } => Some(opcode_cost.opcode_i64load8s), + Operator::I64Load8U { .. } => Some(opcode_cost.opcode_i64load8u), + Operator::I64LtS { .. } => Some(opcode_cost.opcode_i64lts), + Operator::I64LtU { .. } => Some(opcode_cost.opcode_i64ltu), + Operator::I64Mul { .. } => Some(opcode_cost.opcode_i64mul), + Operator::I64Ne { .. } => Some(opcode_cost.opcode_i64ne), + Operator::I64Or { .. } => Some(opcode_cost.opcode_i64or), + Operator::I64Popcnt { .. } => Some(opcode_cost.opcode_i64popcnt), + Operator::I64RemS { .. } => Some(opcode_cost.opcode_i64rems), + Operator::I64RemU { .. } => Some(opcode_cost.opcode_i64remu), + Operator::I64Rotl { .. } => Some(opcode_cost.opcode_i64rotl), + Operator::I64Rotr { .. } => Some(opcode_cost.opcode_i64rotr), + Operator::I64Shl { .. } => Some(opcode_cost.opcode_i64shl), + Operator::I64ShrS { .. } => Some(opcode_cost.opcode_i64shrs), + Operator::I64ShrU { .. } => Some(opcode_cost.opcode_i64shru), + Operator::I64Store { .. } => Some(opcode_cost.opcode_i64store), + Operator::I64Store16 { .. } => Some(opcode_cost.opcode_i64store16), + Operator::I64Store32 { .. } => Some(opcode_cost.opcode_i64store32), + Operator::I64Store8 { .. } => Some(opcode_cost.opcode_i64store8), + Operator::I64Sub { .. } => Some(opcode_cost.opcode_i64sub), + Operator::I64Xor { .. } => Some(opcode_cost.opcode_i64xor), + Operator::If { .. } => Some(opcode_cost.opcode_if), + Operator::LocalGet { .. } => Some(opcode_cost.opcode_localget), + Operator::LocalSet { .. } => Some(opcode_cost.opcode_localset), + Operator::LocalTee { .. } => Some(opcode_cost.opcode_localtee), + Operator::Loop { .. } => Some(opcode_cost.opcode_loop), + Operator::MemoryGrow { .. } => Some(opcode_cost.opcode_memorygrow), + Operator::MemorySize { .. } => Some(opcode_cost.opcode_memorysize), + Operator::Nop { .. } => Some(opcode_cost.opcode_nop), + Operator::RefFunc { .. } => Some(opcode_cost.opcode_reffunc), + Operator::RefIsNull { .. } => Some(opcode_cost.opcode_refisnull), + Operator::RefNull { .. } => Some(opcode_cost.opcode_refnull), + Operator::Rethrow { .. } => Some(opcode_cost.opcode_rethrow), + Operator::Return { .. } => Some(opcode_cost.opcode_return), + Operator::ReturnCall { .. } => Some(opcode_cost.opcode_returncall), + Operator::ReturnCallIndirect { .. } => Some(opcode_cost.opcode_returncallindirect), + Operator::Select { .. } => Some(opcode_cost.opcode_select), + Operator::TableGet { .. } => Some(opcode_cost.opcode_tableget), + Operator::TableGrow { .. } => Some(opcode_cost.opcode_tablegrow), + Operator::TableInit { .. } => Some(opcode_cost.opcode_tableinit), + Operator::TableSet { .. } => Some(opcode_cost.opcode_tableset), + Operator::TableSize { .. } => Some(opcode_cost.opcode_tablesize), + Operator::Throw { .. } => Some(opcode_cost.opcode_throw), + Operator::Try { .. } => Some(opcode_cost.opcode_try), + Operator::TypedSelect { .. } => Some(opcode_cost.opcode_typedselect), + Operator::Unreachable { .. } => Some(opcode_cost.opcode_unreachable), + Operator::MemoryCopy { .. } => Some(opcode_cost.opcode_memorycopy), + Operator::MemoryFill { .. } => Some(opcode_cost.opcode_memoryfill), + _ => None, + } +} diff --git a/vm-executor-experimental/src/we_executor.rs b/vm-executor-experimental/src/we_executor.rs index 1cec15d..f193af9 100644 --- a/vm-executor-experimental/src/we_executor.rs +++ b/vm-executor-experimental/src/we_executor.rs @@ -1,13 +1,13 @@ use crate::{ExperimentalInstance, ExperimentalVMHooksBuilder}; use multiversx_chain_vm_executor::{ - check_missing_wasm, CompilationOptions, Executor, ExecutorError, Instance, OpcodeCost, + check_missing_wasm, CompilationOptions, Executor, ExecutorError, Instance, OpcodeConfig, }; use std::{fmt, sync::Arc}; pub trait ExperimentalExecutorRuntimeRef: Send + Sync { fn vm_hooks_builder(&self) -> Box; - fn opcode_cost(&self) -> Arc; + fn opcode_config(&self) -> Arc; } /// Executor implementation that produces wasmer instances with correctly injected VM hooks from runtime. @@ -34,7 +34,7 @@ impl ExperimentalExecutor { Box::new( ExperimentalInstance::try_new_instance( self.runtime_ref.vm_hooks_builder(), - self.runtime_ref.opcode_cost(), + self.runtime_ref.opcode_config(), wasm_bytes, compilation_options, ) diff --git a/vm-executor-experimental/src/we_instance.rs b/vm-executor-experimental/src/we_instance.rs index 30f9e0e..a399c06 100644 --- a/vm-executor-experimental/src/we_instance.rs +++ b/vm-executor-experimental/src/we_instance.rs @@ -6,7 +6,7 @@ use crate::{we_imports::generate_import_object, we_vm_hooks::VMHooksWrapper}; use crate::{ExperimentalError, ExperimentalVMHooksBuilder}; use log::trace; use multiversx_chain_vm_executor::{ - BreakpointValue, CompilationOptions, ExecutorError, Instance, InstanceCallResult, OpcodeCost, + BreakpointValue, CompilationOptions, ExecutorError, Instance, InstanceCallResult, OpcodeConfig, ServiceError, VMHooksEarlyExit, }; use rc_new_cyclic_fallible::rc_new_cyclic_fallible; @@ -74,7 +74,7 @@ fn prepare_wasmer_instance_inner( impl ExperimentalInstance { pub fn try_new_instance( vm_hooks_builder: Box, - opcode_cost: Arc, + opcode_config: Arc, wasm_bytes: &[u8], compilation_options: &CompilationOptions, ) -> Result { @@ -82,7 +82,7 @@ impl ExperimentalInstance { let mut compiler = Singlepass::default(); // Push middlewares - push_middlewares(&mut compiler, compilation_options, opcode_cost); + push_middlewares(&mut compiler, compilation_options, opcode_config); // Create the store let mut store: Store = Store::new(compiler); @@ -153,7 +153,7 @@ fn validate_memory(memory: &wasmer::Memory, store: &wasmer::Store) -> Result<(), fn push_middlewares( compiler: &mut Singlepass, compilation_options: &CompilationOptions, - opcode_cost: Arc, + opcode_config: Arc, ) { // Create breakpoints middleware let breakpoints_middleware = Arc::new(Breakpoints::new()); @@ -169,7 +169,7 @@ fn push_middlewares( // Create metering middleware let metering_middleware = Arc::new(Metering::new( compilation_options.unmetered_locals, - opcode_cost, + opcode_config, breakpoints_middleware.clone(), )); diff --git a/vm-executor-experimental/tests/common/test_instance.rs b/vm-executor-experimental/tests/common/test_instance.rs index b85d306..559c2fa 100644 --- a/vm-executor-experimental/tests/common/test_instance.rs +++ b/vm-executor-experimental/tests/common/test_instance.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use multiversx_chain_vm_executor::{CompilationOptions, Instance, OpcodeCost}; +use multiversx_chain_vm_executor::{CompilationOptions, Instance, OpcodeConfig}; use multiversx_chain_vm_executor_wasmer_experimental::{ ExperimentalInstance, ExperimentalVMHooksBuilderDefault, }; @@ -19,7 +19,7 @@ pub fn test_instance(wat: &str) -> Box { Box::new( ExperimentalInstance::try_new_instance( Box::new(ExperimentalVMHooksBuilderDefault), - Arc::new(OpcodeCost::default()), + Arc::new(OpcodeConfig::default()), &wasm_bytes, &DUMMY_COMPILATION_OPTIONS, ) diff --git a/vm-executor-wasmer/src/new_traits/wasmer_prod_executor.rs b/vm-executor-wasmer/src/new_traits/wasmer_prod_executor.rs index 1806312..41e26d5 100644 --- a/vm-executor-wasmer/src/new_traits/wasmer_prod_executor.rs +++ b/vm-executor-wasmer/src/new_traits/wasmer_prod_executor.rs @@ -1,5 +1,5 @@ use crate::executor_interface::{ - check_missing_wasm, CompilationOptions, Executor, ExecutorError, Instance, OpcodeCost, + check_missing_wasm, CompilationOptions, Executor, ExecutorError, Instance, OpcodeConfig, VMHooksLegacy, }; use crate::WasmerInstance; @@ -14,7 +14,7 @@ use super::{WasmerProdInstance, WasmerProdInstanceState}; pub trait WasmerProdRuntimeRef: Send + Sync { fn vm_hooks(&self, instance_state: WasmerProdInstanceState) -> Box; - fn opcode_cost(&self) -> Arc>; + fn opcode_config(&self) -> Arc>; } /// Executor implementation that produces wasmer instances with correctly injected VM hooks from runtime. @@ -44,7 +44,7 @@ impl WasmerProdExecutor { WasmerInstance::try_new_instance( Rc::from(vm_hooks), - self.runtime_ref.opcode_cost(), + self.runtime_ref.opcode_config(), wasm_bytes, &compilation_options.to_legacy(), ) diff --git a/vm-executor-wasmer/src/wasmer_executor.rs b/vm-executor-wasmer/src/wasmer_executor.rs index 30f3491..ba7cb8b 100644 --- a/vm-executor-wasmer/src/wasmer_executor.rs +++ b/vm-executor-wasmer/src/wasmer_executor.rs @@ -1,9 +1,10 @@ use crate::executor_interface::{ - CompilationOptionsLegacy, ExecutorError, ExecutorLegacy, InstanceLegacy, OpcodeCost, - ServiceError, VMHooksLegacy, + CompilationOptionsLegacy, ExecutorError, ExecutorLegacy, InstanceLegacy, ServiceError, + VMHooksLegacy, }; use crate::WasmerInstance; use log::trace; +use multiversx_chain_vm_executor::OpcodeConfig; use std::cell::RefCell; use std::ffi::c_void; use std::rc::Rc; @@ -19,14 +20,14 @@ pub fn force_sighandler_reinstall() { pub struct WasmerExecutorData { vm_hooks: Rc, - opcode_cost: Arc>, + opcode_config: Arc>, } impl WasmerExecutorData { pub fn new(vm_hooks: Box) -> Self { Self { vm_hooks: Rc::from(vm_hooks), - opcode_cost: Arc::new(Mutex::new(OpcodeCost::default())), + opcode_config: Arc::new(Mutex::new(OpcodeConfig::default())), } } @@ -41,9 +42,19 @@ impl WasmerExecutorData { } } - pub fn set_opcode_cost(&mut self, opcode_cost: &OpcodeCost) -> Result<(), ExecutorError> { - self.opcode_cost.lock().unwrap().clone_from(opcode_cost); - Ok(()) + pub fn set_opcode_config(&mut self, opcode_config: OpcodeConfig) -> Result<(), ExecutorError> { + match self.opcode_config.lock() { + Ok(mut opcode_config_ref) => { + *opcode_config_ref = opcode_config; + Ok(()) + } + Err(err) => { + trace!("Failed to acquire lock for setting opcode config: {}", err); + Err(Box::new(ServiceError::new( + "Failed to acquire lock for setting opcode config", + ))) + } + } } } @@ -65,9 +76,9 @@ impl ExecutorLegacy for WasmerExecutor { self.data.borrow_mut().set_vm_hooks_ptr(vm_hooks_ptr) } - fn set_opcode_cost(&mut self, opcode_cost: &OpcodeCost) -> Result<(), ExecutorError> { - trace!("Setting opcode cost..."); - self.data.borrow_mut().set_opcode_cost(opcode_cost) + fn set_opcode_config(&mut self, opcode_config: OpcodeConfig) -> Result<(), ExecutorError> { + trace!("Setting opcode config..."); + self.data.borrow_mut().set_opcode_config(opcode_config) } fn new_instance( @@ -78,7 +89,7 @@ impl ExecutorLegacy for WasmerExecutor { let data = self.data.borrow(); let instance = WasmerInstance::try_new_instance( data.vm_hooks.clone(), - data.opcode_cost.clone(), + data.opcode_config.clone(), wasm_bytes, compilation_options, )?; @@ -93,7 +104,7 @@ impl ExecutorLegacy for WasmerExecutor { let data = self.data.borrow(); let instance = WasmerInstance::try_new_instance_from_cache( data.vm_hooks.clone(), - data.opcode_cost.clone(), + data.opcode_config.clone(), cache_bytes, compilation_options, )?; diff --git a/vm-executor-wasmer/src/wasmer_instance.rs b/vm-executor-wasmer/src/wasmer_instance.rs index e0b75de..c36c275 100644 --- a/vm-executor-wasmer/src/wasmer_instance.rs +++ b/vm-executor-wasmer/src/wasmer_instance.rs @@ -1,6 +1,6 @@ use crate::executor_interface::{ BreakpointValueLegacy, CompilationOptionsLegacy, ExecutorError, InstanceLegacy, MemLength, - MemPtr, OpcodeCost, ServiceError, VMHooksEarlyExit, VMHooksLegacy, + MemPtr, ServiceError, VMHooksEarlyExit, VMHooksLegacy, }; use crate::wasmer_opcode_trace::OpcodeTracer; use crate::wasmer_protected_globals::ProtectedGlobals; @@ -9,7 +9,7 @@ use crate::{ wasmer_opcode_control::OpcodeControl, wasmer_vm_hooks::VMHooksWrapper, }; use log::trace; -use multiversx_chain_vm_executor::OpcodeCheckUsed; +use multiversx_chain_vm_executor::{OpcodeCheckUsed, OpcodeConfig}; use std::cell::RefCell; use std::collections::HashSet; @@ -31,7 +31,7 @@ pub struct WasmerInstance { impl WasmerInstance { pub fn try_new_instance( vm_hooks: Rc, - opcode_cost: Arc>, + opcode_config: Arc>, wasm_bytes: &[u8], compilation_options: &CompilationOptionsLegacy, ) -> Result { @@ -44,7 +44,7 @@ impl WasmerInstance { push_middlewares( &mut compiler, compilation_options, - opcode_cost, + opcode_config, used_opcodes.clone(), ); @@ -85,7 +85,7 @@ impl WasmerInstance { pub fn try_new_instance_from_cache( vm_hooks: Rc, - opcode_cost: Arc>, + opcode_config: Arc>, cache_bytes: &[u8], compilation_options: &CompilationOptionsLegacy, ) -> Result { @@ -98,7 +98,7 @@ impl WasmerInstance { push_middlewares( &mut compiler, compilation_options, - opcode_cost, + opcode_config, used_opcodes.clone(), ); @@ -202,7 +202,7 @@ fn validate_memory(memory: &wasmer::Memory) -> Result<(), ExecutorError> { fn push_middlewares( compiler: &mut Singlepass, compilation_options: &CompilationOptionsLegacy, - opcode_cost: Arc>, + opcode_config: Arc>, used_opcodes: Arc>>, ) { // Create breakpoints middleware @@ -221,7 +221,7 @@ fn push_middlewares( let metering_middleware = Arc::new(Metering::new( compilation_options.gas_limit, compilation_options.unmetered_locals, - opcode_cost, + opcode_config, breakpoints_middleware.clone(), )); diff --git a/vm-executor-wasmer/src/wasmer_metering.rs b/vm-executor-wasmer/src/wasmer_metering.rs index 83f9e79..9e4601a 100644 --- a/vm-executor-wasmer/src/wasmer_metering.rs +++ b/vm-executor-wasmer/src/wasmer_metering.rs @@ -1,4 +1,3 @@ -use crate::executor_interface::OpcodeCost; use crate::get_opcode_cost; use crate::wasmer_breakpoints::{Breakpoints, BREAKPOINT_VALUE_OUT_OF_GAS}; use crate::wasmer_helpers::{ @@ -6,6 +5,7 @@ use crate::wasmer_helpers::{ is_supported_bulk_memory_operator, set_global_value_u64, MiddlewareWithProtectedGlobals, }; use loupe::{MemoryUsage, MemoryUsageTracker}; +use multiversx_chain_vm_executor::OpcodeConfig; use std::mem; use std::sync::{Arc, Mutex}; use wasmer::wasmparser::Operator; @@ -31,7 +31,7 @@ struct MeteringGlobalIndexes { pub(crate) struct Metering { points_limit: u64, unmetered_locals: usize, - opcode_cost: Arc>, + opcode_config: Arc>, breakpoints_middleware: Arc, global_indexes: Mutex>, } @@ -40,13 +40,13 @@ impl Metering { pub(crate) fn new( points_limit: u64, unmetered_locals: usize, - opcode_cost: Arc>, + opcode_config: Arc>, breakpoints_middleware: Arc, ) -> Self { Self { points_limit, unmetered_locals, - opcode_cost, + opcode_config, breakpoints_middleware, global_indexes: Mutex::new(None), } @@ -98,7 +98,7 @@ impl ModuleMiddleware for Metering { Box::new(FunctionMetering { accumulated_cost: Default::default(), unmetered_locals: self.unmetered_locals, - opcode_cost: self.opcode_cost.clone(), + opcode_config: self.opcode_config.clone(), breakpoints_middleware: self.breakpoints_middleware.clone(), global_indexes: self.global_indexes.lock().unwrap().clone().unwrap(), }) @@ -140,7 +140,7 @@ impl MiddlewareWithProtectedGlobals for Metering { struct FunctionMetering { accumulated_cost: u64, unmetered_locals: usize, - opcode_cost: Arc>, + opcode_config: Arc>, breakpoints_middleware: Arc, global_indexes: MeteringGlobalIndexes, } @@ -226,7 +226,7 @@ impl FunctionMiddleware for FunctionMetering { // Get the cost of the current operator, and add it to the accumulator. // This needs to be done before the metering logic, to prevent operators like `Call` from escaping metering in some // corner cases. - let option = get_opcode_cost(&operator, &self.opcode_cost.lock().unwrap()); + let option = get_opcode_cost(&operator, &self.opcode_config.lock().unwrap()); match option { Some(cost) if is_supported_bulk_memory_operator(&operator) => { self.inject_bulk_memory_cost(state, cost); @@ -260,7 +260,12 @@ impl FunctionMiddleware for FunctionMetering { let unmetered_locals = self.unmetered_locals as u32; if count > unmetered_locals { let metered_locals = count - unmetered_locals; - let local_cost = self.opcode_cost.lock().unwrap().opcode_localallocate; + let local_cost = self + .opcode_config + .lock() + .unwrap() + .opcode_cost + .opcode_localallocate; let metered_locals_cost = metered_locals * local_cost; self.accumulated_cost += metered_locals_cost as u64; } diff --git a/vm-executor-wasmer/src/wasmer_metering_helpers.rs b/vm-executor-wasmer/src/wasmer_metering_helpers.rs index 8d0974c..bff46b5 100644 --- a/vm-executor-wasmer/src/wasmer_metering_helpers.rs +++ b/vm-executor-wasmer/src/wasmer_metering_helpers.rs @@ -4,10 +4,17 @@ // !!!!!!!!!!!!!!!!!!!!!! AUTO-GENERATED FILE !!!!!!!!!!!!!!!!!!!!!! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -use crate::executor_interface::OpcodeCost; +use multiversx_chain_vm_executor::{OpcodeConfig, OpcodeCost, OpcodeVersion}; use wasmer::wasmparser::Operator; -pub fn get_opcode_cost(op: &Operator, opcode_cost: &OpcodeCost) -> Option { +pub fn get_opcode_cost(op: &Operator, opcode_config: &OpcodeConfig) -> Option { + match opcode_config.opcode_version { + OpcodeVersion::V1 => get_opcode_cost_v1(op, &opcode_config.opcode_cost), + OpcodeVersion::V2 => get_opcode_cost_v2(op, &opcode_config.opcode_cost), + } +} + +pub fn get_opcode_cost_v1(op: &Operator, opcode_cost: &OpcodeCost) -> Option { match op { Operator::Block { .. } => Some(opcode_cost.opcode_block), Operator::Br { .. } => Some(opcode_cost.opcode_br), @@ -141,3 +148,137 @@ pub fn get_opcode_cost(op: &Operator, opcode_cost: &OpcodeCost) -> Option { _ => None, } } + +pub fn get_opcode_cost_v2(op: &Operator, opcode_cost: &OpcodeCost) -> Option { + match op { + Operator::Block { .. } => Some(opcode_cost.opcode_block), + Operator::Br { .. } => Some(opcode_cost.opcode_br), + Operator::BrIf { .. } => Some(opcode_cost.opcode_brif), + Operator::BrTable { .. } => Some(opcode_cost.opcode_brtable), + Operator::Call { .. } => Some(opcode_cost.opcode_call), + Operator::CallIndirect { .. } => Some(opcode_cost.opcode_callindirect), + Operator::Catch { .. } => Some(opcode_cost.opcode_catch), + Operator::CatchAll { .. } => Some(opcode_cost.opcode_catchall), + Operator::Delegate { .. } => Some(opcode_cost.opcode_delegate), + Operator::Drop { .. } => Some(opcode_cost.opcode_drop), + Operator::Else { .. } => Some(opcode_cost.opcode_else), + Operator::End { .. } => Some(opcode_cost.opcode_end), + Operator::GlobalGet { .. } => Some(opcode_cost.opcode_globalget), + Operator::GlobalSet { .. } => Some(opcode_cost.opcode_globalset), + Operator::I32Add { .. } => Some(opcode_cost.opcode_i32add), + Operator::I32And { .. } => Some(opcode_cost.opcode_i32and), + Operator::I32Clz { .. } => Some(opcode_cost.opcode_i32clz), + Operator::I32Const { .. } => Some(opcode_cost.opcode_i32const), + Operator::I32Ctz { .. } => Some(opcode_cost.opcode_i32ctz), + Operator::I32DivS { .. } => Some(opcode_cost.opcode_i32divs), + Operator::I32DivU { .. } => Some(opcode_cost.opcode_i32divu), + Operator::I32Eq { .. } => Some(opcode_cost.opcode_i32eq), + Operator::I32Eqz { .. } => Some(opcode_cost.opcode_i32eqz), + Operator::I32Extend16S { .. } => Some(opcode_cost.opcode_i32extend16s), + Operator::I32Extend8S { .. } => Some(opcode_cost.opcode_i32extend8s), + Operator::I32GeS { .. } => Some(opcode_cost.opcode_i32ges), + Operator::I32GeU { .. } => Some(opcode_cost.opcode_i32geu), + Operator::I32GtS { .. } => Some(opcode_cost.opcode_i32gts), + Operator::I32GtU { .. } => Some(opcode_cost.opcode_i32gtu), + Operator::I32LeS { .. } => Some(opcode_cost.opcode_i32les), + Operator::I32LeU { .. } => Some(opcode_cost.opcode_i32leu), + Operator::I32Load { .. } => Some(opcode_cost.opcode_i32load), + Operator::I32Load16S { .. } => Some(opcode_cost.opcode_i32load16s), + Operator::I32Load16U { .. } => Some(opcode_cost.opcode_i32load16u), + Operator::I32Load8S { .. } => Some(opcode_cost.opcode_i32load8s), + Operator::I32Load8U { .. } => Some(opcode_cost.opcode_i32load8u), + Operator::I32LtS { .. } => Some(opcode_cost.opcode_i32lts), + Operator::I32LtU { .. } => Some(opcode_cost.opcode_i32ltu), + Operator::I32Mul { .. } => Some(opcode_cost.opcode_i32mul), + Operator::I32Ne { .. } => Some(opcode_cost.opcode_i32ne), + Operator::I32Or { .. } => Some(opcode_cost.opcode_i32or), + Operator::I32Popcnt { .. } => Some(opcode_cost.opcode_i32popcnt), + Operator::I32RemS { .. } => Some(opcode_cost.opcode_i32rems), + Operator::I32RemU { .. } => Some(opcode_cost.opcode_i32remu), + Operator::I32Rotl { .. } => Some(opcode_cost.opcode_i32rotl), + Operator::I32Rotr { .. } => Some(opcode_cost.opcode_i32rotr), + Operator::I32Shl { .. } => Some(opcode_cost.opcode_i32shl), + Operator::I32ShrS { .. } => Some(opcode_cost.opcode_i32shrs), + Operator::I32ShrU { .. } => Some(opcode_cost.opcode_i32shru), + Operator::I32Store { .. } => Some(opcode_cost.opcode_i32store), + Operator::I32Store16 { .. } => Some(opcode_cost.opcode_i32store16), + Operator::I32Store8 { .. } => Some(opcode_cost.opcode_i32store8), + Operator::I32Sub { .. } => Some(opcode_cost.opcode_i32sub), + Operator::I32WrapI64 { .. } => Some(opcode_cost.opcode_i32wrapi64), + Operator::I32Xor { .. } => Some(opcode_cost.opcode_i32xor), + Operator::I64Add { .. } => Some(opcode_cost.opcode_i64add), + Operator::I64And { .. } => Some(opcode_cost.opcode_i64and), + Operator::I64Clz { .. } => Some(opcode_cost.opcode_i64clz), + Operator::I64Const { .. } => Some(opcode_cost.opcode_i64const), + Operator::I64Ctz { .. } => Some(opcode_cost.opcode_i64ctz), + Operator::I64DivS { .. } => Some(opcode_cost.opcode_i64divs), + Operator::I64DivU { .. } => Some(opcode_cost.opcode_i64divu), + Operator::I64Eq { .. } => Some(opcode_cost.opcode_i64eq), + Operator::I64Eqz { .. } => Some(opcode_cost.opcode_i64eqz), + Operator::I64Extend16S { .. } => Some(opcode_cost.opcode_i64extend16s), + Operator::I64Extend32S { .. } => Some(opcode_cost.opcode_i64extend32s), + Operator::I64Extend8S { .. } => Some(opcode_cost.opcode_i64extend8s), + Operator::I64ExtendI32S { .. } => Some(opcode_cost.opcode_i64extendi32s), + Operator::I64ExtendI32U { .. } => Some(opcode_cost.opcode_i64extendi32u), + Operator::I64GeS { .. } => Some(opcode_cost.opcode_i64ges), + Operator::I64GeU { .. } => Some(opcode_cost.opcode_i64geu), + Operator::I64GtS { .. } => Some(opcode_cost.opcode_i64gts), + Operator::I64GtU { .. } => Some(opcode_cost.opcode_i64gtu), + Operator::I64LeS { .. } => Some(opcode_cost.opcode_i64les), + Operator::I64LeU { .. } => Some(opcode_cost.opcode_i64leu), + Operator::I64Load { .. } => Some(opcode_cost.opcode_i64load), + Operator::I64Load16S { .. } => Some(opcode_cost.opcode_i64load16s), + Operator::I64Load16U { .. } => Some(opcode_cost.opcode_i64load16u), + Operator::I64Load32S { .. } => Some(opcode_cost.opcode_i64load32s), + Operator::I64Load32U { .. } => Some(opcode_cost.opcode_i64load32u), + Operator::I64Load8S { .. } => Some(opcode_cost.opcode_i64load8s), + Operator::I64Load8U { .. } => Some(opcode_cost.opcode_i64load8u), + Operator::I64LtS { .. } => Some(opcode_cost.opcode_i64lts), + Operator::I64LtU { .. } => Some(opcode_cost.opcode_i64ltu), + Operator::I64Mul { .. } => Some(opcode_cost.opcode_i64mul), + Operator::I64Ne { .. } => Some(opcode_cost.opcode_i64ne), + Operator::I64Or { .. } => Some(opcode_cost.opcode_i64or), + Operator::I64Popcnt { .. } => Some(opcode_cost.opcode_i64popcnt), + Operator::I64RemS { .. } => Some(opcode_cost.opcode_i64rems), + Operator::I64RemU { .. } => Some(opcode_cost.opcode_i64remu), + Operator::I64Rotl { .. } => Some(opcode_cost.opcode_i64rotl), + Operator::I64Rotr { .. } => Some(opcode_cost.opcode_i64rotr), + Operator::I64Shl { .. } => Some(opcode_cost.opcode_i64shl), + Operator::I64ShrS { .. } => Some(opcode_cost.opcode_i64shrs), + Operator::I64ShrU { .. } => Some(opcode_cost.opcode_i64shru), + Operator::I64Store { .. } => Some(opcode_cost.opcode_i64store), + Operator::I64Store16 { .. } => Some(opcode_cost.opcode_i64store16), + Operator::I64Store32 { .. } => Some(opcode_cost.opcode_i64store32), + Operator::I64Store8 { .. } => Some(opcode_cost.opcode_i64store8), + Operator::I64Sub { .. } => Some(opcode_cost.opcode_i64sub), + Operator::I64Xor { .. } => Some(opcode_cost.opcode_i64xor), + Operator::If { .. } => Some(opcode_cost.opcode_if), + Operator::LocalGet { .. } => Some(opcode_cost.opcode_localget), + Operator::LocalSet { .. } => Some(opcode_cost.opcode_localset), + Operator::LocalTee { .. } => Some(opcode_cost.opcode_localtee), + Operator::Loop { .. } => Some(opcode_cost.opcode_loop), + Operator::MemoryGrow { .. } => Some(opcode_cost.opcode_memorygrow), + Operator::MemorySize { .. } => Some(opcode_cost.opcode_memorysize), + Operator::Nop { .. } => Some(opcode_cost.opcode_nop), + Operator::RefFunc { .. } => Some(opcode_cost.opcode_reffunc), + Operator::RefIsNull { .. } => Some(opcode_cost.opcode_refisnull), + Operator::RefNull { .. } => Some(opcode_cost.opcode_refnull), + Operator::Rethrow { .. } => Some(opcode_cost.opcode_rethrow), + Operator::Return { .. } => Some(opcode_cost.opcode_return), + Operator::ReturnCall { .. } => Some(opcode_cost.opcode_returncall), + Operator::ReturnCallIndirect { .. } => Some(opcode_cost.opcode_returncallindirect), + Operator::Select { .. } => Some(opcode_cost.opcode_select), + Operator::TableGet { .. } => Some(opcode_cost.opcode_tableget), + Operator::TableGrow { .. } => Some(opcode_cost.opcode_tablegrow), + Operator::TableInit { .. } => Some(opcode_cost.opcode_tableinit), + Operator::TableSet { .. } => Some(opcode_cost.opcode_tableset), + Operator::TableSize { .. } => Some(opcode_cost.opcode_tablesize), + Operator::Throw { .. } => Some(opcode_cost.opcode_throw), + Operator::Try { .. } => Some(opcode_cost.opcode_try), + Operator::TypedSelect { .. } => Some(opcode_cost.opcode_typedselect), + Operator::Unreachable { .. } => Some(opcode_cost.opcode_unreachable), + Operator::MemoryCopy { .. } => Some(opcode_cost.opcode_memorycopy), + Operator::MemoryFill { .. } => Some(opcode_cost.opcode_memoryfill), + _ => None, + } +} diff --git a/vm-executor/src/executor.rs b/vm-executor/src/executor.rs index c2e22f0..0fb094e 100644 --- a/vm-executor/src/executor.rs +++ b/vm-executor/src/executor.rs @@ -1,4 +1,4 @@ -use crate::{CompilationOptionsLegacy, ExecutorError, InstanceLegacy, OpcodeCost}; +use crate::{CompilationOptionsLegacy, ExecutorError, InstanceLegacy, OpcodeConfig}; use std::ffi::c_void; @@ -6,8 +6,8 @@ pub trait ExecutorLegacy { /// Sets the data that can be hold by an instance context. fn set_vm_hooks_ptr(&mut self, vm_hooks_ptr: *mut c_void) -> Result<(), ExecutorError>; - /// Sets the opcode costs for the given executor. - fn set_opcode_cost(&mut self, opcode_cost: &OpcodeCost) -> Result<(), ExecutorError>; + /// Sets the opcode version and costs for the given executor. + fn set_opcode_config(&mut self, opcode_config: OpcodeConfig) -> Result<(), ExecutorError>; /// Creates a new VM executor instance. fn new_instance( diff --git a/vm-executor/src/lib.rs b/vm-executor/src/lib.rs index fa3b769..8588ffd 100644 --- a/vm-executor/src/lib.rs +++ b/vm-executor/src/lib.rs @@ -5,7 +5,9 @@ mod instance; mod missing_wasm; mod new_traits; mod opcode_check_used; +mod opcode_config; mod opcode_cost; +mod opcode_version; mod service_error; mod service_trait; mod vm_hooks; @@ -17,7 +19,9 @@ pub use instance::InstanceLegacy; pub use missing_wasm::{check_missing_wasm, MissingWasmError}; pub use new_traits::*; pub use opcode_check_used::OpcodeCheckUsed; +pub use opcode_config::OpcodeConfig; pub use opcode_cost::OpcodeCost; +pub use opcode_version::OpcodeVersion; pub use service_error::ServiceError; pub use service_trait::*; pub use vm_hooks::{VMHooksLegacy, VMHooksLegacyDefault}; diff --git a/vm-executor/src/opcode_config.rs b/vm-executor/src/opcode_config.rs new file mode 100644 index 0000000..c899741 --- /dev/null +++ b/vm-executor/src/opcode_config.rs @@ -0,0 +1,16 @@ +use crate::{OpcodeCost, OpcodeVersion}; + +#[derive(Debug, Clone)] +pub struct OpcodeConfig { + pub opcode_version: OpcodeVersion, + pub opcode_cost: OpcodeCost, +} + +impl Default for OpcodeConfig { + fn default() -> Self { + Self { + opcode_version: OpcodeVersion::V1, + opcode_cost: OpcodeCost::default(), + } + } +} diff --git a/vm-executor/src/opcode_version.rs b/vm-executor/src/opcode_version.rs new file mode 100644 index 0000000..30febbe --- /dev/null +++ b/vm-executor/src/opcode_version.rs @@ -0,0 +1,15 @@ +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum OpcodeVersion { + V1, + V2, +} + +impl OpcodeVersion { + pub fn from_i32(value: i32) -> Option { + match value { + 0 => Some(OpcodeVersion::V1), + 1 => Some(OpcodeVersion::V2), + _ => None, + } + } +} From 876a457e124cfbf9d355a0b7d28f44814ba68633 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Tue, 2 Sep 2025 15:17:08 +0300 Subject: [PATCH 08/35] removed used opcode mechanism --- c-api/libvmexeccapi.h | 9 ----- c-api/src/capi_instance.rs | 24 +------------ vm-executor-wasmer/src/wasmer_instance.rs | 34 ++----------------- .../src/wasmer_opcode_control.rs | 21 ------------ vm-executor/src/instance.rs | 5 +-- vm-executor/src/lib.rs | 2 -- vm-executor/src/opcode_check_used.rs | 22 ------------ 7 files changed, 5 insertions(+), 112 deletions(-) delete mode 100644 vm-executor/src/opcode_check_used.rs diff --git a/c-api/libvmexeccapi.h b/c-api/libvmexeccapi.h index 0756920..de840f1 100644 --- a/c-api/libvmexeccapi.h +++ b/c-api/libvmexeccapi.h @@ -456,15 +456,6 @@ int vm_exec_instance_has_function(vm_exec_instance_t *instance_ptr, const char * int vm_exec_instance_has_imported_function(vm_exec_instance_t *instance_ptr, const char *func_name_ptr); -/** - * Checks whether the given opcode is used in the wasm module. - * - * # Safety - * - * C API function, works with raw object pointers. - */ -int vm_exec_instance_is_opcode_used(vm_exec_instance_t *instance_ptr, uint32_t opcode_value); - /** * Gets a pointer to the beginning of the contiguous memory data * bytes. diff --git a/c-api/src/capi_instance.rs b/c-api/src/capi_instance.rs index fadee79..732bba0 100644 --- a/c-api/src/capi_instance.rs +++ b/c-api/src/capi_instance.rs @@ -7,7 +7,7 @@ use crate::{ }; use libc::{c_char, c_int}; use meta::capi_safe_unwind; -use multiversx_chain_vm_executor::{CompilationOptionsLegacy, InstanceLegacy, OpcodeCheckUsed}; +use multiversx_chain_vm_executor::{CompilationOptionsLegacy, InstanceLegacy}; use std::{ffi::CStr, slice}; /// Opaque pointer to a `wasmer_runtime::Instance` value in Rust. @@ -186,28 +186,6 @@ pub unsafe extern "C" fn vm_exec_instance_has_imported_function( c_int::from(capi_instance.content.has_imported_function(func_name_r)) } -/// Checks whether the given opcode is used in the wasm module. -/// -/// # Safety -/// -/// C API function, works with raw object pointers. -#[allow(clippy::cast_ptr_alignment)] -#[no_mangle] -#[capi_safe_unwind(-1)] -pub unsafe extern "C" fn vm_exec_instance_is_opcode_used( - instance_ptr: *mut vm_exec_instance_t, - opcode_value: u32, -) -> c_int { - let capi_instance = cast_input_ptr!(instance_ptr, CapiInstance, "instance ptr is null", -1); - - let Some(opcode) = OpcodeCheckUsed::from_value(opcode_value) else { - with_service(|service| service.update_last_error_str("invalid opcode value".to_string())); - return -1; - }; - - c_int::from(capi_instance.content.is_opcode_used(opcode)) -} - /// Required to be able to extract all SC endpoint names. See `vm_exported_function_names`. /// /// # Safety diff --git a/vm-executor-wasmer/src/wasmer_instance.rs b/vm-executor-wasmer/src/wasmer_instance.rs index c36c275..b30ed24 100644 --- a/vm-executor-wasmer/src/wasmer_instance.rs +++ b/vm-executor-wasmer/src/wasmer_instance.rs @@ -9,10 +9,9 @@ use crate::{ wasmer_opcode_control::OpcodeControl, wasmer_vm_hooks::VMHooksWrapper, }; use log::trace; -use multiversx_chain_vm_executor::{OpcodeCheckUsed, OpcodeConfig}; +use multiversx_chain_vm_executor::OpcodeConfig; use std::cell::RefCell; -use std::collections::HashSet; use std::sync::Mutex; use std::{rc::Rc, sync::Arc}; use wasmer::{CompilerConfig, Extern, Module, Store}; @@ -25,7 +24,6 @@ pub struct WasmerInstance { pub(crate) wasmer_instance: wasmer::Instance, memory_name: String, early_exit_cell: RefCell>, - used_opcodes: Arc>>, } impl WasmerInstance { @@ -38,15 +36,8 @@ impl WasmerInstance { // Use Singlepass compiler with the default settings let mut compiler = Singlepass::default(); - let used_opcodes = Arc::new(Mutex::new(HashSet::new())); - // Push middlewares - push_middlewares( - &mut compiler, - compilation_options, - opcode_config, - used_opcodes.clone(), - ); + push_middlewares(&mut compiler, compilation_options, opcode_config); // Create the store let store = Store::new(&Universal::new(compiler).engine()); @@ -79,7 +70,6 @@ impl WasmerInstance { wasmer_instance, memory_name, early_exit_cell: RefCell::new(None), - used_opcodes, }) } @@ -92,15 +82,8 @@ impl WasmerInstance { // Use Singlepass compiler with the default settings let mut compiler = Singlepass::default(); - let used_opcodes = Arc::new(Mutex::new(HashSet::new())); - // Push middlewares - push_middlewares( - &mut compiler, - compilation_options, - opcode_config, - used_opcodes.clone(), - ); + push_middlewares(&mut compiler, compilation_options, opcode_config); // Create the store let store = Store::new(&Universal::new(compiler).engine()); @@ -136,7 +119,6 @@ impl WasmerInstance { wasmer_instance, memory_name, early_exit_cell: RefCell::new(None), - used_opcodes, }) } @@ -203,7 +185,6 @@ fn push_middlewares( compiler: &mut Singlepass, compilation_options: &CompilationOptionsLegacy, opcode_config: Arc>, - used_opcodes: Arc>>, ) { // Create breakpoints middleware let breakpoints_middleware = Arc::new(Breakpoints::new()); @@ -214,7 +195,6 @@ fn push_middlewares( compilation_options.max_memory_grow, compilation_options.max_memory_grow_delta, breakpoints_middleware.clone(), - used_opcodes, )); // Create metering middleware @@ -301,14 +281,6 @@ impl InstanceLegacy for WasmerInstance { false } - fn is_opcode_used(&self, opcode: OpcodeCheckUsed) -> bool { - let Ok(used_opcodes) = self.used_opcodes.lock() else { - return false; - }; - - used_opcodes.contains(&opcode) - } - fn get_exported_function_names(&self) -> Vec { self.wasmer_instance .exports diff --git a/vm-executor-wasmer/src/wasmer_opcode_control.rs b/vm-executor-wasmer/src/wasmer_opcode_control.rs index dec868f..631e163 100644 --- a/vm-executor-wasmer/src/wasmer_opcode_control.rs +++ b/vm-executor-wasmer/src/wasmer_opcode_control.rs @@ -1,11 +1,9 @@ use std::{ - collections::HashSet, mem, sync::{Arc, Mutex}, }; use loupe::{MemoryUsage, MemoryUsageTracker}; -use multiversx_chain_vm_executor::OpcodeCheckUsed; use wasmer::{ wasmparser::Operator, FunctionMiddleware, LocalFunctionIndex, MiddlewareError, MiddlewareReaderState, ModuleMiddleware, @@ -34,7 +32,6 @@ pub(crate) struct OpcodeControl { max_memory_grow_delta: usize, breakpoints_middleware: Arc, global_indexes: Mutex>, - used_opcodes: Arc>>, } impl OpcodeControl { @@ -43,7 +40,6 @@ impl OpcodeControl { max_memory_grow: usize, max_memory_grow_delta: usize, breakpoints_middleware: Arc, - used_opcodes: Arc>>, ) -> Self { Self { total_memory_grow_count: Arc::new(Mutex::new(0)), @@ -52,7 +48,6 @@ impl OpcodeControl { max_memory_grow_delta, breakpoints_middleware, global_indexes: Mutex::new(None), - used_opcodes, } } @@ -97,7 +92,6 @@ impl ModuleMiddleware for OpcodeControl { max_memory_grow_delta: self.max_memory_grow_delta, breakpoints_middleware: self.breakpoints_middleware.clone(), global_indexes: self.global_indexes.lock().unwrap().clone().unwrap(), - used_opcodes: self.used_opcodes.clone(), }) } @@ -136,7 +130,6 @@ struct FunctionOpcodeControl { max_memory_grow_delta: usize, breakpoints_middleware: Arc, global_indexes: OpcodeControlGlobalIndexes, - used_opcodes: Arc>>, } impl FunctionOpcodeControl { @@ -208,20 +201,6 @@ impl FunctionMiddleware for FunctionOpcodeControl { operator: Operator<'b>, state: &mut MiddlewareReaderState<'b>, ) -> Result<(), MiddlewareError> { - let used_opcode = match operator { - Operator::MemoryCopy { .. } => Some(OpcodeCheckUsed::MemoryCopy), - Operator::MemoryFill { .. } => Some(OpcodeCheckUsed::MemoryFill), - _ => None, - }; - - if let Some(used_opcode) = used_opcode { - let mut used_opcodes = self - .used_opcodes - .lock() - .map_err(|_| MiddlewareError::new("UsedOpcodes", "failed to lock used_opcodes"))?; - used_opcodes.insert(used_opcode); - } - if matches!(operator, Operator::MemoryGrow { .. }) { let mut grow_count = self .total_memory_grow_count diff --git a/vm-executor/src/instance.rs b/vm-executor/src/instance.rs index d9b2347..aec8d07 100644 --- a/vm-executor/src/instance.rs +++ b/vm-executor/src/instance.rs @@ -1,4 +1,4 @@ -use crate::{BreakpointValueLegacy, ExecutorError, MemLength, MemPtr, OpcodeCheckUsed}; +use crate::{BreakpointValueLegacy, ExecutorError, MemLength, MemPtr}; /// The old instance trait, used both: /// - from the "outside": configuring & calling the instance; @@ -16,9 +16,6 @@ pub trait InstanceLegacy { /// Checks whether SC has an imported function with given name. fn has_imported_function(&self, func_name: &str) -> bool; - /// Checks whether the given opcode is used in the instance. - fn is_opcode_used(&self, opcode: OpcodeCheckUsed) -> bool; - /// Required to be able to extract all SC endpoint names. fn get_exported_function_names(&self) -> Vec; diff --git a/vm-executor/src/lib.rs b/vm-executor/src/lib.rs index 8588ffd..dd06692 100644 --- a/vm-executor/src/lib.rs +++ b/vm-executor/src/lib.rs @@ -4,7 +4,6 @@ mod executor; mod instance; mod missing_wasm; mod new_traits; -mod opcode_check_used; mod opcode_config; mod opcode_cost; mod opcode_version; @@ -18,7 +17,6 @@ pub use executor::ExecutorLegacy; pub use instance::InstanceLegacy; pub use missing_wasm::{check_missing_wasm, MissingWasmError}; pub use new_traits::*; -pub use opcode_check_used::OpcodeCheckUsed; pub use opcode_config::OpcodeConfig; pub use opcode_cost::OpcodeCost; pub use opcode_version::OpcodeVersion; diff --git a/vm-executor/src/opcode_check_used.rs b/vm-executor/src/opcode_check_used.rs deleted file mode 100644 index a335edb..0000000 --- a/vm-executor/src/opcode_check_used.rs +++ /dev/null @@ -1,22 +0,0 @@ -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum OpcodeCheckUsed { - MemoryCopy, - MemoryFill, -} - -impl OpcodeCheckUsed { - pub fn from_value(value: u32) -> Option { - match value { - 0 => Some(Self::MemoryCopy), - 1 => Some(Self::MemoryFill), - _ => None, - } - } - - pub fn as_u32(self) -> u32 { - match self { - Self::MemoryCopy => 0, - Self::MemoryFill => 1, - } - } -} From d434536daaf2aac42eb1a9e48c15ac7bd3fe767f Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Tue, 2 Sep 2025 17:17:33 +0300 Subject: [PATCH 09/35] imports fix --- vm-executor-wasmer/src/wasmer_instance.rs | 3 +-- vm-executor-wasmer/src/wasmer_metering.rs | 2 +- vm-executor-wasmer/src/wasmer_metering_helpers.rs | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/vm-executor-wasmer/src/wasmer_instance.rs b/vm-executor-wasmer/src/wasmer_instance.rs index b30ed24..1601e93 100644 --- a/vm-executor-wasmer/src/wasmer_instance.rs +++ b/vm-executor-wasmer/src/wasmer_instance.rs @@ -1,6 +1,6 @@ use crate::executor_interface::{ BreakpointValueLegacy, CompilationOptionsLegacy, ExecutorError, InstanceLegacy, MemLength, - MemPtr, ServiceError, VMHooksEarlyExit, VMHooksLegacy, + MemPtr, OpcodeConfig, ServiceError, VMHooksEarlyExit, VMHooksLegacy, }; use crate::wasmer_opcode_trace::OpcodeTracer; use crate::wasmer_protected_globals::ProtectedGlobals; @@ -9,7 +9,6 @@ use crate::{ wasmer_opcode_control::OpcodeControl, wasmer_vm_hooks::VMHooksWrapper, }; use log::trace; -use multiversx_chain_vm_executor::OpcodeConfig; use std::cell::RefCell; use std::sync::Mutex; diff --git a/vm-executor-wasmer/src/wasmer_metering.rs b/vm-executor-wasmer/src/wasmer_metering.rs index 9e4601a..d408afd 100644 --- a/vm-executor-wasmer/src/wasmer_metering.rs +++ b/vm-executor-wasmer/src/wasmer_metering.rs @@ -1,3 +1,4 @@ +use crate::executor_interface::OpcodeConfig; use crate::get_opcode_cost; use crate::wasmer_breakpoints::{Breakpoints, BREAKPOINT_VALUE_OUT_OF_GAS}; use crate::wasmer_helpers::{ @@ -5,7 +6,6 @@ use crate::wasmer_helpers::{ is_supported_bulk_memory_operator, set_global_value_u64, MiddlewareWithProtectedGlobals, }; use loupe::{MemoryUsage, MemoryUsageTracker}; -use multiversx_chain_vm_executor::OpcodeConfig; use std::mem; use std::sync::{Arc, Mutex}; use wasmer::wasmparser::Operator; diff --git a/vm-executor-wasmer/src/wasmer_metering_helpers.rs b/vm-executor-wasmer/src/wasmer_metering_helpers.rs index bff46b5..f3ffbbc 100644 --- a/vm-executor-wasmer/src/wasmer_metering_helpers.rs +++ b/vm-executor-wasmer/src/wasmer_metering_helpers.rs @@ -4,7 +4,7 @@ // !!!!!!!!!!!!!!!!!!!!!! AUTO-GENERATED FILE !!!!!!!!!!!!!!!!!!!!!! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -use multiversx_chain_vm_executor::{OpcodeConfig, OpcodeCost, OpcodeVersion}; +use crate::executor_interface::{OpcodeConfig, OpcodeCost, OpcodeVersion}; use wasmer::wasmparser::Operator; pub fn get_opcode_cost(op: &Operator, opcode_config: &OpcodeConfig) -> Option { From 6aa525e147e1e695e1e2be938aa876317ab4197f Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Tue, 2 Sep 2025 17:47:20 +0300 Subject: [PATCH 10/35] import fix --- vm-executor-wasmer/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm-executor-wasmer/Cargo.toml b/vm-executor-wasmer/Cargo.toml index 134a5d4..487246a 100644 --- a/vm-executor-wasmer/Cargo.toml +++ b/vm-executor-wasmer/Cargo.toml @@ -43,6 +43,6 @@ wasmer-vm = { git = "https://github.com/multiversx/wasmer", rev = "090ad17927fd1 wasmer-types = { git = "https://github.com/multiversx/wasmer", rev = "090ad17927fd1cbecb253a7b123d21e453fa13df" } chrono = "0.4.23" -log = "0.4.17" +log = { version = "0.4.17", features = ["std"] } loupe = "0.1.3" thiserror = "2.0" From d655288687842572380e2665449c2ab9b4cdccbf Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Wed, 3 Sep 2025 13:26:27 +0300 Subject: [PATCH 11/35] get_opcode_cost fix --- vm-executor-wasmer/src/wasmer_executor.rs | 5 ++--- vm-executor-wasmer/src/wasmer_metering_helpers.rs | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/vm-executor-wasmer/src/wasmer_executor.rs b/vm-executor-wasmer/src/wasmer_executor.rs index ba7cb8b..f8087fc 100644 --- a/vm-executor-wasmer/src/wasmer_executor.rs +++ b/vm-executor-wasmer/src/wasmer_executor.rs @@ -1,10 +1,9 @@ use crate::executor_interface::{ - CompilationOptionsLegacy, ExecutorError, ExecutorLegacy, InstanceLegacy, ServiceError, - VMHooksLegacy, + CompilationOptionsLegacy, ExecutorError, ExecutorLegacy, InstanceLegacy, OpcodeConfig, + ServiceError, VMHooksLegacy, }; use crate::WasmerInstance; use log::trace; -use multiversx_chain_vm_executor::OpcodeConfig; use std::cell::RefCell; use std::ffi::c_void; use std::rc::Rc; diff --git a/vm-executor-wasmer/src/wasmer_metering_helpers.rs b/vm-executor-wasmer/src/wasmer_metering_helpers.rs index f3ffbbc..a90d6a5 100644 --- a/vm-executor-wasmer/src/wasmer_metering_helpers.rs +++ b/vm-executor-wasmer/src/wasmer_metering_helpers.rs @@ -124,8 +124,6 @@ pub fn get_opcode_cost_v1(op: &Operator, opcode_cost: &OpcodeCost) -> Option Some(opcode_cost.opcode_loop), Operator::MemoryGrow { .. } => Some(opcode_cost.opcode_memorygrow), Operator::MemorySize { .. } => Some(opcode_cost.opcode_memorysize), - Operator::MemoryCopy { .. } => Some(opcode_cost.opcode_memorycopy), - Operator::MemoryFill { .. } => Some(opcode_cost.opcode_memoryfill), Operator::Nop { .. } => Some(opcode_cost.opcode_nop), Operator::RefFunc { .. } => Some(opcode_cost.opcode_reffunc), Operator::RefIsNull { .. } => Some(opcode_cost.opcode_refisnull), From e0fbc4e9d2bb9aec999b382dc0ea5eacf7848f06 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Wed, 3 Sep 2025 13:26:52 +0300 Subject: [PATCH 12/35] opcode version test --- vm-executor-wasmer/tests/memory-copy.wat | 18 ++++++++++ .../tests/opcode_version_test.rs | 34 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 vm-executor-wasmer/tests/memory-copy.wat create mode 100644 vm-executor-wasmer/tests/opcode_version_test.rs diff --git a/vm-executor-wasmer/tests/memory-copy.wat b/vm-executor-wasmer/tests/memory-copy.wat new file mode 100644 index 0000000..917b4ac --- /dev/null +++ b/vm-executor-wasmer/tests/memory-copy.wat @@ -0,0 +1,18 @@ +(module + (type $void (func)) + (type $finish(func (param i64))) + (import "env" "int64finish" (func $int64finish (type $finish))) + (func $main (type $void) + (memory.copy + (i32.const 42) ;; destination address + (i32.const 1024) ;; source address + (i32.const 2) ;; size of memory region in bytes + ) + (i64.const 0) + (call $int64finish) + ) + (memory $mem 1) + (export "memory" (memory $mem)) + (export "main" (func $main)) + (data (i32.const 1024) "ok") +) diff --git a/vm-executor-wasmer/tests/opcode_version_test.rs b/vm-executor-wasmer/tests/opcode_version_test.rs new file mode 100644 index 0000000..c9b453e --- /dev/null +++ b/vm-executor-wasmer/tests/opcode_version_test.rs @@ -0,0 +1,34 @@ +use multiversx_chain_vm_executor::{ + CompilationOptions, ExecutorLegacy, OpcodeConfig, OpcodeCost, OpcodeVersion, + VMHooksLegacyDefault, +}; +use multiversx_chain_vm_executor_wasmer::WasmerExecutor; +use wasmer::wat2wasm; + +const MEMORY_COPY_WAT: &[u8] = include_bytes!("memory-copy.wat"); + +const DUMMY_COMPILATION_OPTIONS: CompilationOptions = CompilationOptions { + unmetered_locals: 0, + max_memory_grow: 0, + max_memory_grow_delta: 0, + opcode_trace: false, +}; + +#[test] +fn opcode_version_test() { + let wasm_bytes = wat2wasm(MEMORY_COPY_WAT).unwrap(); + + let mut executor = WasmerExecutor::new(Box::new(VMHooksLegacyDefault)); + let result = executor.new_instance(&wasm_bytes, &DUMMY_COMPILATION_OPTIONS.to_legacy()); + assert!(result.is_err()); + + executor + .set_opcode_config(OpcodeConfig { + opcode_version: OpcodeVersion::V2, + opcode_cost: OpcodeCost::default(), + }) + .unwrap(); + + let result = executor.new_instance(&wasm_bytes, &DUMMY_COMPILATION_OPTIONS.to_legacy()); + assert!(result.is_ok()); +} From 3b1185f81e2e0ee627913dd02ad329dd692a3658 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Thu, 4 Sep 2025 02:56:40 +0300 Subject: [PATCH 13/35] wasmer opcode cost file rename --- vm-executor-experimental/src/middlewares.rs | 4 ++-- .../middlewares/{we_metering_helpers.rs => we_opcode_cost.rs} | 0 vm-executor-wasmer/src/lib.rs | 4 ++-- .../src/{wasmer_metering_helpers.rs => wasmer_opcode_cost.rs} | 0 4 files changed, 4 insertions(+), 4 deletions(-) rename vm-executor-experimental/src/middlewares/{we_metering_helpers.rs => we_opcode_cost.rs} (100%) rename vm-executor-wasmer/src/{wasmer_metering_helpers.rs => wasmer_opcode_cost.rs} (100%) diff --git a/vm-executor-experimental/src/middlewares.rs b/vm-executor-experimental/src/middlewares.rs index 3d872da..92e6aa6 100644 --- a/vm-executor-experimental/src/middlewares.rs +++ b/vm-executor-experimental/src/middlewares.rs @@ -1,15 +1,15 @@ mod we_breakpoints; mod we_metering; -mod we_metering_helpers; mod we_opcode_control; +mod we_opcode_cost; mod we_opcode_trace; mod we_protected_globals; mod we_protected_globals_trait; pub(crate) use we_breakpoints::*; pub(crate) use we_metering::*; -pub use we_metering_helpers::*; pub use we_opcode_control::OpcodeControl; +pub use we_opcode_cost::*; pub use we_opcode_trace::OpcodeTracer; pub use we_protected_globals::ProtectedGlobals; pub use we_protected_globals_trait::MiddlewareWithProtectedGlobals; diff --git a/vm-executor-experimental/src/middlewares/we_metering_helpers.rs b/vm-executor-experimental/src/middlewares/we_opcode_cost.rs similarity index 100% rename from vm-executor-experimental/src/middlewares/we_metering_helpers.rs rename to vm-executor-experimental/src/middlewares/we_opcode_cost.rs diff --git a/vm-executor-wasmer/src/lib.rs b/vm-executor-wasmer/src/lib.rs index e7c6da5..031e36d 100644 --- a/vm-executor-wasmer/src/lib.rs +++ b/vm-executor-wasmer/src/lib.rs @@ -6,8 +6,8 @@ mod wasmer_imports; mod wasmer_instance; mod wasmer_logger; mod wasmer_metering; -mod wasmer_metering_helpers; mod wasmer_opcode_control; +mod wasmer_opcode_cost; mod wasmer_opcode_trace; mod wasmer_protected_globals; mod wasmer_service; @@ -16,7 +16,7 @@ mod wasmer_vm_hooks; pub use wasmer_executor::*; pub use wasmer_instance::*; pub use wasmer_logger::*; -pub use wasmer_metering_helpers::*; +pub use wasmer_opcode_cost::*; pub use wasmer_service::*; #[cfg(feature = "multiversx-chain-vm-executor")] diff --git a/vm-executor-wasmer/src/wasmer_metering_helpers.rs b/vm-executor-wasmer/src/wasmer_opcode_cost.rs similarity index 100% rename from vm-executor-wasmer/src/wasmer_metering_helpers.rs rename to vm-executor-wasmer/src/wasmer_opcode_cost.rs From ed0ff7d510b122dcd39d75438833de97f29b719e Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Thu, 4 Sep 2025 02:58:02 +0300 Subject: [PATCH 14/35] wasmer opcode cost fix --- .../src/middlewares/we_opcode_cost.rs | 8 +++----- vm-executor-wasmer/src/wasmer_opcode_cost.rs | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/vm-executor-experimental/src/middlewares/we_opcode_cost.rs b/vm-executor-experimental/src/middlewares/we_opcode_cost.rs index 0c9d568..6711ab8 100644 --- a/vm-executor-experimental/src/middlewares/we_opcode_cost.rs +++ b/vm-executor-experimental/src/middlewares/we_opcode_cost.rs @@ -14,7 +14,7 @@ pub fn get_opcode_cost(op: &Operator, opcode_config: &OpcodeConfig) -> Option Option { +fn get_opcode_cost_v1(op: &Operator, opcode_cost: &OpcodeCost) -> Option { match op { Operator::Block { .. } => Some(opcode_cost.opcode_block), Operator::Br { .. } => Some(opcode_cost.opcode_br), @@ -124,8 +124,6 @@ pub fn get_opcode_cost_v1(op: &Operator, opcode_cost: &OpcodeCost) -> Option Some(opcode_cost.opcode_loop), Operator::MemoryGrow { .. } => Some(opcode_cost.opcode_memorygrow), Operator::MemorySize { .. } => Some(opcode_cost.opcode_memorysize), - Operator::MemoryCopy { .. } => Some(opcode_cost.opcode_memorycopy), - Operator::MemoryFill { .. } => Some(opcode_cost.opcode_memoryfill), Operator::Nop { .. } => Some(opcode_cost.opcode_nop), Operator::RefFunc { .. } => Some(opcode_cost.opcode_reffunc), Operator::RefIsNull { .. } => Some(opcode_cost.opcode_refisnull), @@ -144,12 +142,12 @@ pub fn get_opcode_cost_v1(op: &Operator, opcode_cost: &OpcodeCost) -> Option Some(opcode_cost.opcode_try), Operator::TypedSelect { .. } => Some(opcode_cost.opcode_typedselect), Operator::Unreachable { .. } => Some(opcode_cost.opcode_unreachable), - // Operator::Unwind { .. } => Some(opcode_cost.opcode_unwind), + // Operator::Unwind { .. } => Some(opcode_cost.opcode_unwind), // unwind no longer available in Wasmer 6 _ => None, } } -pub fn get_opcode_cost_v2(op: &Operator, opcode_cost: &OpcodeCost) -> Option { +fn get_opcode_cost_v2(op: &Operator, opcode_cost: &OpcodeCost) -> Option { match op { Operator::Block { .. } => Some(opcode_cost.opcode_block), Operator::Br { .. } => Some(opcode_cost.opcode_br), diff --git a/vm-executor-wasmer/src/wasmer_opcode_cost.rs b/vm-executor-wasmer/src/wasmer_opcode_cost.rs index a90d6a5..3b005c7 100644 --- a/vm-executor-wasmer/src/wasmer_opcode_cost.rs +++ b/vm-executor-wasmer/src/wasmer_opcode_cost.rs @@ -14,7 +14,7 @@ pub fn get_opcode_cost(op: &Operator, opcode_config: &OpcodeConfig) -> Option Option { +fn get_opcode_cost_v1(op: &Operator, opcode_cost: &OpcodeCost) -> Option { match op { Operator::Block { .. } => Some(opcode_cost.opcode_block), Operator::Br { .. } => Some(opcode_cost.opcode_br), @@ -147,7 +147,7 @@ pub fn get_opcode_cost_v1(op: &Operator, opcode_cost: &OpcodeCost) -> Option Option { +fn get_opcode_cost_v2(op: &Operator, opcode_cost: &OpcodeCost) -> Option { match op { Operator::Block { .. } => Some(opcode_cost.opcode_block), Operator::Br { .. } => Some(opcode_cost.opcode_br), From a5c00c1dc9a4d4b608a60b5e4dfc580a1067a213 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Tue, 8 Sep 2026 16:09:45 +0300 Subject: [PATCH 15/35] fix after review --- vm-executor-wasmer/src/wasmer_helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm-executor-wasmer/src/wasmer_helpers.rs b/vm-executor-wasmer/src/wasmer_helpers.rs index dea0201..37fab87 100644 --- a/vm-executor-wasmer/src/wasmer_helpers.rs +++ b/vm-executor-wasmer/src/wasmer_helpers.rs @@ -86,6 +86,6 @@ pub(crate) fn is_control_flow_operator(operator: &Operator) -> bool { pub(crate) fn is_supported_bulk_memory_operator(operator: &Operator) -> bool { matches!( operator, - Operator::MemoryCopy { src: _, dst: _ } | Operator::MemoryFill { mem: _ } + Operator::MemoryCopy { .. } | Operator::MemoryFill { .. } ) } From 66f6a4c762bbf7f9939f5ab1b9bfb711a9cc4693 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Tue, 8 Sep 2026 16:14:12 +0300 Subject: [PATCH 16/35] docs --- vm-executor-wasmer/src/wasmer_helpers.rs | 38 ++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/vm-executor-wasmer/src/wasmer_helpers.rs b/vm-executor-wasmer/src/wasmer_helpers.rs index 37fab87..71032ce 100644 --- a/vm-executor-wasmer/src/wasmer_helpers.rs +++ b/vm-executor-wasmer/src/wasmer_helpers.rs @@ -3,7 +3,10 @@ use wasmer::{ }; use wasmer_types::{GlobalIndex, ModuleInfo}; +/// Middleware that marks some globals as protected and therefore not subject to +/// normal runtime mutation. pub trait MiddlewareWithProtectedGlobals { + /// Returns the indices of globals that must remain protected. fn protected_globals(&self) -> Vec; } @@ -13,6 +16,15 @@ impl std::fmt::Debug for dyn MiddlewareWithProtectedGlobals { } } +/// Creates and exports a fresh i64 global in the module and initializes it. +/// +/// # Parameters +/// - `module_info`: the module metadata to update +/// - `key`: the exported name for the global +/// - `init`: the initial value assigned to the global +/// +/// # Returns +/// The index of the newly created global in the module. pub(crate) fn create_global_index( module_info: &mut ModuleInfo, key: &str, @@ -33,6 +45,15 @@ pub(crate) fn create_global_index( global_index } +/// Sets the value of a u64 export global on a Wasmer instance. +/// +/// # Parameters +/// - `instance`: the instance that owns the exported global +/// - `global_name`: the name of the exported global +/// - `points`: the new value to assign to the global +/// +/// # Returns +/// `Ok(())` if the update succeeded, otherwise a formatted error message. pub(crate) fn set_global_value_u64( instance: &Instance, global_name: &str, @@ -51,6 +72,15 @@ pub(crate) fn set_global_value_u64( } } +/// Reads the value of a u64 export global from a Wasmer instance. +/// +/// # Parameters +/// - `instance`: the instance that owns the exported global +/// - `global_name`: the name of the exported global +/// +/// # Returns +/// The current value of the global as a `u64`, or an error message if lookup +/// or conversion fails. pub(crate) fn get_global_value_u64(instance: &Instance, global_name: &str) -> Result { let result = instance.exports.get_global(global_name); match result { @@ -65,6 +95,10 @@ pub(crate) fn get_global_value_u64(instance: &Instance, global_name: &str) -> Re } } +/// Returns `true` when the given WebAssembly operator changes control flow. +/// +/// This is used to recognize branching and call-like operations that affect block +/// execution flow and must be treated specially by middleware logic. pub(crate) fn is_control_flow_operator(operator: &Operator) -> bool { matches!( operator, @@ -83,6 +117,10 @@ pub(crate) fn is_control_flow_operator(operator: &Operator) -> bool { ) } +/// Returns `true` for the bulk-memory operators supported by this helper. +/// +/// These are the memory-copy and memory-fill instructions that need explicit +/// validation or handling in Wasmer middleware. pub(crate) fn is_supported_bulk_memory_operator(operator: &Operator) -> bool { matches!( operator, From 965eb2841db1bf1e44e4f73aa90621d1042a6dd0 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Tue, 8 Sep 2026 16:14:23 +0300 Subject: [PATCH 17/35] gitignore fix --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 6d4d737..39e2174 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,7 @@ Cargo.lock # Personal scripts my-* + +# Other +.vscode +**/.DS_Store From f7f3d24c2241a02bcd212f23e2fe57a8a94e8da7 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Tue, 8 Sep 2026 16:17:51 +0300 Subject: [PATCH 18/35] typos --- _typos.toml | 2 ++ c-api/libvmexeccapi.h | 2 +- c-api/src/capi_metering.rs | 6 +++--- vm-executor-wasmer/src/wasmer_metering.rs | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 _typos.toml diff --git a/_typos.toml b/_typos.toml new file mode 100644 index 0000000..ef06468 --- /dev/null +++ b/_typos.toml @@ -0,0 +1,2 @@ +[default.extend-words] +groth = "groth" #groth16 crypto function diff --git a/c-api/libvmexeccapi.h b/c-api/libvmexeccapi.h index 32b971d..b703a8f 100644 --- a/c-api/libvmexeccapi.h +++ b/c-api/libvmexeccapi.h @@ -1261,7 +1261,7 @@ enum vm_exec_result_t vm_exec_instance_memory_grow(struct vm_exec_instance_t *in * C API function, works with raw object pointers. */ enum vm_exec_result_t vm_exec_set_opcode_config(struct vm_exec_executor_t *executor_ptr, - int32_t opcode_vesion_code, + int32_t opcode_version_code, const struct vm_exec_opcode_cost_t *opcode_cost_ptr); /** diff --git a/c-api/src/capi_metering.rs b/c-api/src/capi_metering.rs index e5b1ba7..6b455c9 100644 --- a/c-api/src/capi_metering.rs +++ b/c-api/src/capi_metering.rs @@ -23,16 +23,16 @@ pub struct vm_exec_opcode_cost_t; #[capi_safe_unwind(vm_exec_result_t::VM_EXEC_ERROR)] pub unsafe extern "C" fn vm_exec_set_opcode_config( executor_ptr: *mut vm_exec_executor_t, - opcode_vesion_code: i32, + opcode_version_code: i32, opcode_cost_ptr: *const vm_exec_opcode_cost_t, ) -> vm_exec_result_t { let capi_executor = cast_input_ptr!(executor_ptr, CapiExecutor, "executor ptr is null"); - let Some(opcode_version) = OpcodeVersion::from_i32(opcode_vesion_code) else { + let Some(opcode_version) = OpcodeVersion::from_i32(opcode_version_code) else { with_service(|service| { service.update_last_error_str(format!( "invalid opcode version code: {}", - opcode_vesion_code + opcode_version_code )) }); return vm_exec_result_t::VM_EXEC_ERROR; diff --git a/vm-executor-wasmer/src/wasmer_metering.rs b/vm-executor-wasmer/src/wasmer_metering.rs index 0640eb2..6426500 100644 --- a/vm-executor-wasmer/src/wasmer_metering.rs +++ b/vm-executor-wasmer/src/wasmer_metering.rs @@ -230,7 +230,7 @@ impl FunctionMiddleware for FunctionMetering { match option { Some(cost) if is_supported_bulk_memory_operator(&operator) => { self.inject_bulk_memory_cost(state, cost); - // immediatly insert out of gas check as this operation might be expensive + // immediately insert out of gas check as this operation might be expensive self.inject_out_of_gas_check(state); } Some(cost) => self.accumulated_cost += cost as u64, From ab7d4088f185f4ed7e8bc7b69fec8416a873346a Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Tue, 8 Sep 2026 16:22:39 +0300 Subject: [PATCH 19/35] docs --- vm-executor/src/opcode_version.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/vm-executor/src/opcode_version.rs b/vm-executor/src/opcode_version.rs index 30febbe..29def6e 100644 --- a/vm-executor/src/opcode_version.rs +++ b/vm-executor/src/opcode_version.rs @@ -1,10 +1,32 @@ +/// Specifies which set of opcodes should be used by the VM. +/// +/// `V1` is the legacy opcode set that does **not** include support for bulk +/// memory operations. `V2` extends `V1` by adding bulk memory instructions, +/// such as `MemoryCopy` and `MemoryFill`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum OpcodeVersion { + /// Legacy opcode set without bulk memory support. + /// + /// Use this for modules or environments that were compiled or designed + /// before bulk memory operations were introduced, or when compatibility + /// with older tooling is required. V1, + /// Opcode set with bulk memory support. + /// + /// Use this for modules that rely on bulk memory operations like + /// `MemoryCopy` and `MemoryFill`, or when targeting newer runtimes that + /// support these instructions. V2, } - impl OpcodeVersion { + /// Converts a numeric opcode version identifier into an `OpcodeVersion`. + /// + /// * `0` maps to [`OpcodeVersion::V1`] (legacy, no bulk memory support). + /// * `1` maps to [`OpcodeVersion::V2`] (with bulk memory operations). + /// + /// Any other value returns `None`. This is typically used when decoding + /// opcode version information from serialized formats or external + /// configuration that represent the version as an integer. pub fn from_i32(value: i32) -> Option { match value { 0 => Some(OpcodeVersion::V1), From 3196e7a3ee509931b031188cce479917a549b81c Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Wed, 9 Sep 2026 03:47:53 +0300 Subject: [PATCH 20/35] docs (bulk memory cost) --- vm-executor-wasmer/src/wasmer_metering.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/vm-executor-wasmer/src/wasmer_metering.rs b/vm-executor-wasmer/src/wasmer_metering.rs index 6426500..84b9535 100644 --- a/vm-executor-wasmer/src/wasmer_metering.rs +++ b/vm-executor-wasmer/src/wasmer_metering.rs @@ -175,6 +175,21 @@ impl FunctionMetering { .inject_breakpoint_condition(state, BREAKPOINT_VALUE_OUT_OF_GAS); } + /// Injects `points_used += size * cost_per_byte` ahead of a `memory.copy`/`memory.fill`, + /// using `size` as it appears on the stack (the raw, attacker-controlled operand), before + /// the real bulk-memory instruction validates it against the actual memory bounds. + /// + /// The multiplication is plain wrapping `i64` arithmetic (wasm has no trapping or + /// saturating integer multiply, and Wasmer doesn't offer one either), so it can in theory + /// wrap around for a large enough `size`. This is not exploitable under the current setup: + /// - `MAX_MEMORY_PAGES_ALLOWED` (in `wasmer_instance.rs`) caps declared memory at 20 pages + /// (1.25 MiB), enforced at instantiation. + /// - any `size` large enough to matter for overflow (`size * cost_per_byte` approaching + /// `i64::MAX`) necessarily exceeds that 1.25 MiB bound, so the real `memory.copy`/ + /// `memory.fill` that follows this injected code traps on out-of-bounds access and aborts + /// the call immediately — regardless of what `points_used` ended up holding. + /// - a `size` that keeps the copy in-bounds is capped at 1,310,720 bytes, so + /// `size * cost_per_byte` tops out around `5.6e15` for a `u32` cost, far below `i64::MAX`. fn inject_bulk_memory_cost(&self, state: &mut MiddlewareReaderState, cost_per_byte: u32) { // backup the bulk memory size state.extend(&[Operator::GlobalSet { From 2782518ede5d2493074ae83b13e7769170502d54 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Wed, 9 Sep 2026 12:34:19 +0300 Subject: [PATCH 21/35] docs --- vm-executor/src/opcode_version.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vm-executor/src/opcode_version.rs b/vm-executor/src/opcode_version.rs index 29def6e..1c1dead 100644 --- a/vm-executor/src/opcode_version.rs +++ b/vm-executor/src/opcode_version.rs @@ -16,6 +16,8 @@ pub enum OpcodeVersion { /// Use this for modules that rely on bulk memory operations like /// `MemoryCopy` and `MemoryFill`, or when targeting newer runtimes that /// support these instructions. + /// + /// Note: `V2` does **not** add support for `memory.init` and `data.drop`. V2, } impl OpcodeVersion { From 168370c80baf7232662589d8a1f0679523760c00 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Wed, 23 Sep 2026 11:22:20 +0300 Subject: [PATCH 22/35] re-generated VM hooks --- c-api/libvmexeccapi.h | 37 ---------------- c-api/src/capi_vm_hook_pointers.rs | 7 ---- c-api/src/capi_vm_hooks.rs | 28 ------------- vm-executor-experimental/src/we_imports.rs | 42 ------------------- vm-executor-wasmer/src/wasmer_imports.rs | 42 ------------------- vm-executor/src/breakpoint_value.rs | 3 +- .../src/new_traits/vm_hooks_legacy_adapter.rs | 28 ------------- vm-executor/src/new_traits/vm_hooks_new.rs | 42 ------------------- vm-executor/src/vm_hooks.rs | 42 ------------------- 9 files changed, 1 insertion(+), 270 deletions(-) diff --git a/c-api/libvmexeccapi.h b/c-api/libvmexeccapi.h index b703a8f..bd04054 100644 --- a/c-api/libvmexeccapi.h +++ b/c-api/libvmexeccapi.h @@ -915,43 +915,6 @@ typedef struct vm_exec_vm_hook_c_func_pointers { int32_t (*managed_get_num_errors_func_ptr)(void *context); void (*managed_get_error_with_index_func_ptr)(void *context, int32_t index, int32_t error_handle); void (*managed_get_last_error_func_ptr)(void *context, int32_t error_handle); - int32_t (*managed_verify_groth16_func_ptr)(void *context, - int32_t curve_id, - int32_t proof_handle, - int32_t vk_handle, - int32_t pub_witness_handle); - int32_t (*managed_verify_plonk_func_ptr)(void *context, - int32_t curve_id, - int32_t proof_handle, - int32_t vk_handle, - int32_t pub_witness_handle); - int32_t (*managed_add_ec_func_ptr)(void *context, - int32_t curve_id, - int32_t group_id, - int32_t point1_handle, - int32_t point2_handle, - int32_t result_handle); - int32_t (*managed_mul_ec_func_ptr)(void *context, - int32_t curve_id, - int32_t group_id, - int32_t point_handle, - int32_t scalar_handle, - int32_t result_handle); - int32_t (*managed_multi_exp_ec_func_ptr)(void *context, - int32_t curve_id, - int32_t group_id, - int32_t points_handle, - int32_t scalars_handle, - int32_t result_handle); - int32_t (*managed_map_to_curve_ec_func_ptr)(void *context, - int32_t curve_id, - int32_t group_id, - int32_t element_handle, - int32_t result_handle); - int32_t (*managed_pairing_checks_ec_func_ptr)(void *context, - int32_t curve_id, - int32_t points_g1_handle, - int32_t points_g2_handle); } vm_exec_vm_hook_c_func_pointers; typedef struct vm_exec_compilation_options_t { diff --git a/c-api/src/capi_vm_hook_pointers.rs b/c-api/src/capi_vm_hook_pointers.rs index 0f423c3..1200dae 100644 --- a/c-api/src/capi_vm_hook_pointers.rs +++ b/c-api/src/capi_vm_hook_pointers.rs @@ -293,13 +293,6 @@ pub struct vm_exec_vm_hook_c_func_pointers { pub managed_get_num_errors_func_ptr: extern "C" fn(context: *mut c_void) -> i32, pub managed_get_error_with_index_func_ptr: extern "C" fn(context: *mut c_void, index: i32, error_handle: i32), pub managed_get_last_error_func_ptr: extern "C" fn(context: *mut c_void, error_handle: i32), - pub managed_verify_groth16_func_ptr: extern "C" fn(context: *mut c_void, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32, - pub managed_verify_plonk_func_ptr: extern "C" fn(context: *mut c_void, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32, - pub managed_add_ec_func_ptr: extern "C" fn(context: *mut c_void, curve_id: i32, group_id: i32, point1_handle: i32, point2_handle: i32, result_handle: i32) -> i32, - pub managed_mul_ec_func_ptr: extern "C" fn(context: *mut c_void, curve_id: i32, group_id: i32, point_handle: i32, scalar_handle: i32, result_handle: i32) -> i32, - pub managed_multi_exp_ec_func_ptr: extern "C" fn(context: *mut c_void, curve_id: i32, group_id: i32, points_handle: i32, scalars_handle: i32, result_handle: i32) -> i32, - pub managed_map_to_curve_ec_func_ptr: extern "C" fn(context: *mut c_void, curve_id: i32, group_id: i32, element_handle: i32, result_handle: i32) -> i32, - pub managed_pairing_checks_ec_func_ptr: extern "C" fn(context: *mut c_void, curve_id: i32, points_g1_handle: i32, points_g2_handle: i32) -> i32, } impl std::fmt::Debug for vm_exec_vm_hook_c_func_pointers { diff --git a/c-api/src/capi_vm_hooks.rs b/c-api/src/capi_vm_hooks.rs index 6339af6..5936bd3 100644 --- a/c-api/src/capi_vm_hooks.rs +++ b/c-api/src/capi_vm_hooks.rs @@ -1166,32 +1166,4 @@ impl multiversx_chain_vm_executor::VMHooksLegacy for CapiVMHooks { fn managed_get_last_error(&self, error_handle: i32) { (self.c_func_pointers_ptr.managed_get_last_error_func_ptr)(self.vm_hooks_ptr, error_handle) } - - fn managed_verify_groth16(&self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32 { - (self.c_func_pointers_ptr.managed_verify_groth16_func_ptr)(self.vm_hooks_ptr, curve_id, proof_handle, vk_handle, pub_witness_handle) - } - - fn managed_verify_plonk(&self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32 { - (self.c_func_pointers_ptr.managed_verify_plonk_func_ptr)(self.vm_hooks_ptr, curve_id, proof_handle, vk_handle, pub_witness_handle) - } - - fn managed_add_ec(&self, curve_id: i32, group_id: i32, point1_handle: i32, point2_handle: i32, result_handle: i32) -> i32 { - (self.c_func_pointers_ptr.managed_add_ec_func_ptr)(self.vm_hooks_ptr, curve_id, group_id, point1_handle, point2_handle, result_handle) - } - - fn managed_mul_ec(&self, curve_id: i32, group_id: i32, point_handle: i32, scalar_handle: i32, result_handle: i32) -> i32 { - (self.c_func_pointers_ptr.managed_mul_ec_func_ptr)(self.vm_hooks_ptr, curve_id, group_id, point_handle, scalar_handle, result_handle) - } - - fn managed_multi_exp_ec(&self, curve_id: i32, group_id: i32, points_handle: i32, scalars_handle: i32, result_handle: i32) -> i32 { - (self.c_func_pointers_ptr.managed_multi_exp_ec_func_ptr)(self.vm_hooks_ptr, curve_id, group_id, points_handle, scalars_handle, result_handle) - } - - fn managed_map_to_curve_ec(&self, curve_id: i32, group_id: i32, element_handle: i32, result_handle: i32) -> i32 { - (self.c_func_pointers_ptr.managed_map_to_curve_ec_func_ptr)(self.vm_hooks_ptr, curve_id, group_id, element_handle, result_handle) - } - - fn managed_pairing_checks_ec(&self, curve_id: i32, points_g1_handle: i32, points_g2_handle: i32) -> i32 { - (self.c_func_pointers_ptr.managed_pairing_checks_ec_func_ptr)(self.vm_hooks_ptr, curve_id, points_g1_handle, points_g2_handle) - } } diff --git a/vm-executor-experimental/src/we_imports.rs b/vm-executor-experimental/src/we_imports.rs index f8732b0..554a7c0 100644 --- a/vm-executor-experimental/src/we_imports.rs +++ b/vm-executor-experimental/src/we_imports.rs @@ -1421,41 +1421,6 @@ fn wasmer_import_managed_get_last_error(env: FunctionEnvMut, err with_vm_hooks(env, |vh| vh.managed_get_last_error(error_handle)) } -#[rustfmt::skip] -fn wasmer_import_managed_verify_groth16(env: FunctionEnvMut, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> Result { - with_vm_hooks(env, |vh| vh.managed_verify_groth16(curve_id, proof_handle, vk_handle, pub_witness_handle)) -} - -#[rustfmt::skip] -fn wasmer_import_managed_verify_plonk(env: FunctionEnvMut, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> Result { - with_vm_hooks(env, |vh| vh.managed_verify_plonk(curve_id, proof_handle, vk_handle, pub_witness_handle)) -} - -#[rustfmt::skip] -fn wasmer_import_managed_add_ec(env: FunctionEnvMut, curve_id: i32, group_id: i32, point1_handle: i32, point2_handle: i32, result_handle: i32) -> Result { - with_vm_hooks(env, |vh| vh.managed_add_ec(curve_id, group_id, point1_handle, point2_handle, result_handle)) -} - -#[rustfmt::skip] -fn wasmer_import_managed_mul_ec(env: FunctionEnvMut, curve_id: i32, group_id: i32, point_handle: i32, scalar_handle: i32, result_handle: i32) -> Result { - with_vm_hooks(env, |vh| vh.managed_mul_ec(curve_id, group_id, point_handle, scalar_handle, result_handle)) -} - -#[rustfmt::skip] -fn wasmer_import_managed_multi_exp_ec(env: FunctionEnvMut, curve_id: i32, group_id: i32, points_handle: i32, scalars_handle: i32, result_handle: i32) -> Result { - with_vm_hooks(env, |vh| vh.managed_multi_exp_ec(curve_id, group_id, points_handle, scalars_handle, result_handle)) -} - -#[rustfmt::skip] -fn wasmer_import_managed_map_to_curve_ec(env: FunctionEnvMut, curve_id: i32, group_id: i32, element_handle: i32, result_handle: i32) -> Result { - with_vm_hooks(env, |vh| vh.managed_map_to_curve_ec(curve_id, group_id, element_handle, result_handle)) -} - -#[rustfmt::skip] -fn wasmer_import_managed_pairing_checks_ec(env: FunctionEnvMut, curve_id: i32, points_g1_handle: i32, points_g2_handle: i32) -> Result { - with_vm_hooks(env, |vh| vh.managed_pairing_checks_ec(curve_id, points_g1_handle, points_g2_handle)) -} - pub fn generate_import_object(store: &mut Store, vh_wrapper: VMHooksWrapper) -> Imports { let function_env = FunctionEnv::new(store, vh_wrapper); @@ -1743,13 +1708,6 @@ pub fn generate_import_object(store: &mut Store, vh_wrapper: VMHooksWrapper) -> "managedGetNumErrors" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_get_num_errors), "managedGetErrorWithIndex" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_get_error_with_index), "managedGetLastError" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_get_last_error), - "managedVerifyGroth16" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_verify_groth16), - "managedVerifyPlonk" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_verify_plonk), - "managedAddEC" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_add_ec), - "managedMulEC" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_mul_ec), - "managedMultiExpEC" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_multi_exp_ec), - "managedMapToCurveEC" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_map_to_curve_ec), - "managedPairingChecksEC" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_pairing_checks_ec), } } diff --git a/vm-executor-wasmer/src/wasmer_imports.rs b/vm-executor-wasmer/src/wasmer_imports.rs index 5baf3ed..6a87c76 100644 --- a/vm-executor-wasmer/src/wasmer_imports.rs +++ b/vm-executor-wasmer/src/wasmer_imports.rs @@ -1420,41 +1420,6 @@ fn wasmer_import_managed_get_last_error(env: &VMHooksWrapper, error_handle: i32) env.vm_hooks.managed_get_last_error(error_handle) } -#[rustfmt::skip] -fn wasmer_import_managed_verify_groth16(env: &VMHooksWrapper, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32 { - env.vm_hooks.managed_verify_groth16(curve_id, proof_handle, vk_handle, pub_witness_handle) -} - -#[rustfmt::skip] -fn wasmer_import_managed_verify_plonk(env: &VMHooksWrapper, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32 { - env.vm_hooks.managed_verify_plonk(curve_id, proof_handle, vk_handle, pub_witness_handle) -} - -#[rustfmt::skip] -fn wasmer_import_managed_add_ec(env: &VMHooksWrapper, curve_id: i32, group_id: i32, point1_handle: i32, point2_handle: i32, result_handle: i32) -> i32 { - env.vm_hooks.managed_add_ec(curve_id, group_id, point1_handle, point2_handle, result_handle) -} - -#[rustfmt::skip] -fn wasmer_import_managed_mul_ec(env: &VMHooksWrapper, curve_id: i32, group_id: i32, point_handle: i32, scalar_handle: i32, result_handle: i32) -> i32 { - env.vm_hooks.managed_mul_ec(curve_id, group_id, point_handle, scalar_handle, result_handle) -} - -#[rustfmt::skip] -fn wasmer_import_managed_multi_exp_ec(env: &VMHooksWrapper, curve_id: i32, group_id: i32, points_handle: i32, scalars_handle: i32, result_handle: i32) -> i32 { - env.vm_hooks.managed_multi_exp_ec(curve_id, group_id, points_handle, scalars_handle, result_handle) -} - -#[rustfmt::skip] -fn wasmer_import_managed_map_to_curve_ec(env: &VMHooksWrapper, curve_id: i32, group_id: i32, element_handle: i32, result_handle: i32) -> i32 { - env.vm_hooks.managed_map_to_curve_ec(curve_id, group_id, element_handle, result_handle) -} - -#[rustfmt::skip] -fn wasmer_import_managed_pairing_checks_ec(env: &VMHooksWrapper, curve_id: i32, points_g1_handle: i32, points_g2_handle: i32) -> i32 { - env.vm_hooks.managed_pairing_checks_ec(curve_id, points_g1_handle, points_g2_handle) -} - pub fn generate_import_object(store: &Store, env: &VMHooksWrapper) -> ImportObject { imports! { "env" => { @@ -1740,13 +1705,6 @@ pub fn generate_import_object(store: &Store, env: &VMHooksWrapper) -> ImportObje "managedGetNumErrors" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_get_num_errors), "managedGetErrorWithIndex" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_get_error_with_index), "managedGetLastError" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_get_last_error), - "managedVerifyGroth16" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_verify_groth16), - "managedVerifyPlonk" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_verify_plonk), - "managedAddEC" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_add_ec), - "managedMulEC" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_mul_ec), - "managedMultiExpEC" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_multi_exp_ec), - "managedMapToCurveEC" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_map_to_curve_ec), - "managedPairingChecksEC" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_pairing_checks_ec), } } diff --git a/vm-executor/src/breakpoint_value.rs b/vm-executor/src/breakpoint_value.rs index 58af35f..4dcfa4c 100644 --- a/vm-executor/src/breakpoint_value.rs +++ b/vm-executor/src/breakpoint_value.rs @@ -1,9 +1,8 @@ - /// Represents the reason why execution of a WASM instance was interrupted. /// /// Used by the legacy executor interface to communicate breakpoint causes /// between the WASM runtime and the high-level VM. -/// +/// /// TODO: move to wasmer-prod, and hide it from the VM implementation. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BreakpointValueLegacy { diff --git a/vm-executor/src/new_traits/vm_hooks_legacy_adapter.rs b/vm-executor/src/new_traits/vm_hooks_legacy_adapter.rs index e907046..c79d9b6 100644 --- a/vm-executor/src/new_traits/vm_hooks_legacy_adapter.rs +++ b/vm-executor/src/new_traits/vm_hooks_legacy_adapter.rs @@ -1174,32 +1174,4 @@ impl VMHooksLegacy for VMHooksLegacyAdapter { fn managed_get_last_error(&self, error_handle: i32) { self.adapt_vm_hooks(|inner| VMHooks::managed_get_last_error(inner, error_handle)) } - - fn managed_verify_groth16(&self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32 { - self.adapt_vm_hooks(|inner| VMHooks::managed_verify_groth16(inner, curve_id, proof_handle, vk_handle, pub_witness_handle)) - } - - fn managed_verify_plonk(&self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32 { - self.adapt_vm_hooks(|inner| VMHooks::managed_verify_plonk(inner, curve_id, proof_handle, vk_handle, pub_witness_handle)) - } - - fn managed_add_ec(&self, curve_id: i32, group_id: i32, point1_handle: i32, point2_handle: i32, result_handle: i32) -> i32 { - self.adapt_vm_hooks(|inner| VMHooks::managed_add_ec(inner, curve_id, group_id, point1_handle, point2_handle, result_handle)) - } - - fn managed_mul_ec(&self, curve_id: i32, group_id: i32, point_handle: i32, scalar_handle: i32, result_handle: i32) -> i32 { - self.adapt_vm_hooks(|inner| VMHooks::managed_mul_ec(inner, curve_id, group_id, point_handle, scalar_handle, result_handle)) - } - - fn managed_multi_exp_ec(&self, curve_id: i32, group_id: i32, points_handle: i32, scalars_handle: i32, result_handle: i32) -> i32 { - self.adapt_vm_hooks(|inner| VMHooks::managed_multi_exp_ec(inner, curve_id, group_id, points_handle, scalars_handle, result_handle)) - } - - fn managed_map_to_curve_ec(&self, curve_id: i32, group_id: i32, element_handle: i32, result_handle: i32) -> i32 { - self.adapt_vm_hooks(|inner| VMHooks::managed_map_to_curve_ec(inner, curve_id, group_id, element_handle, result_handle)) - } - - fn managed_pairing_checks_ec(&self, curve_id: i32, points_g1_handle: i32, points_g2_handle: i32) -> i32 { - self.adapt_vm_hooks(|inner| VMHooks::managed_pairing_checks_ec(inner, curve_id, points_g1_handle, points_g2_handle)) - } } diff --git a/vm-executor/src/new_traits/vm_hooks_new.rs b/vm-executor/src/new_traits/vm_hooks_new.rs index fef9070..26a6aa5 100644 --- a/vm-executor/src/new_traits/vm_hooks_new.rs +++ b/vm-executor/src/new_traits/vm_hooks_new.rs @@ -291,13 +291,6 @@ pub trait VMHooks: core::fmt::Debug { fn managed_get_num_errors(&mut self) -> Result; fn managed_get_error_with_index(&mut self, index: i32, error_handle: i32) -> Result<(), VMHooksEarlyExit>; fn managed_get_last_error(&mut self, error_handle: i32) -> Result<(), VMHooksEarlyExit>; - fn managed_verify_groth16(&mut self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> Result; - fn managed_verify_plonk(&mut self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> Result; - fn managed_add_ec(&mut self, curve_id: i32, group_id: i32, point1_handle: i32, point2_handle: i32, result_handle: i32) -> Result; - fn managed_mul_ec(&mut self, curve_id: i32, group_id: i32, point_handle: i32, scalar_handle: i32, result_handle: i32) -> Result; - fn managed_multi_exp_ec(&mut self, curve_id: i32, group_id: i32, points_handle: i32, scalars_handle: i32, result_handle: i32) -> Result; - fn managed_map_to_curve_ec(&mut self, curve_id: i32, group_id: i32, element_handle: i32, result_handle: i32) -> Result; - fn managed_pairing_checks_ec(&mut self, curve_id: i32, points_g1_handle: i32, points_g2_handle: i32) -> Result; } /// Dummy implementation for VMHooks. Can be used as placeholder, or in tests. @@ -1716,39 +1709,4 @@ impl VMHooks for VMHooksDefault { println!("Called: managed_get_last_error"); Ok(()) } - - fn managed_verify_groth16(&mut self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> Result { - println!("Called: managed_verify_groth16"); - Ok(0) - } - - fn managed_verify_plonk(&mut self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> Result { - println!("Called: managed_verify_plonk"); - Ok(0) - } - - fn managed_add_ec(&mut self, curve_id: i32, group_id: i32, point1_handle: i32, point2_handle: i32, result_handle: i32) -> Result { - println!("Called: managed_add_ec"); - Ok(0) - } - - fn managed_mul_ec(&mut self, curve_id: i32, group_id: i32, point_handle: i32, scalar_handle: i32, result_handle: i32) -> Result { - println!("Called: managed_mul_ec"); - Ok(0) - } - - fn managed_multi_exp_ec(&mut self, curve_id: i32, group_id: i32, points_handle: i32, scalars_handle: i32, result_handle: i32) -> Result { - println!("Called: managed_multi_exp_ec"); - Ok(0) - } - - fn managed_map_to_curve_ec(&mut self, curve_id: i32, group_id: i32, element_handle: i32, result_handle: i32) -> Result { - println!("Called: managed_map_to_curve_ec"); - Ok(0) - } - - fn managed_pairing_checks_ec(&mut self, curve_id: i32, points_g1_handle: i32, points_g2_handle: i32) -> Result { - println!("Called: managed_pairing_checks_ec"); - Ok(0) - } } diff --git a/vm-executor/src/vm_hooks.rs b/vm-executor/src/vm_hooks.rs index 5c742f1..07f0dd7 100644 --- a/vm-executor/src/vm_hooks.rs +++ b/vm-executor/src/vm_hooks.rs @@ -295,13 +295,6 @@ pub trait VMHooksLegacy: core::fmt::Debug { fn managed_get_num_errors(&self) -> i32; fn managed_get_error_with_index(&self, index: i32, error_handle: i32); fn managed_get_last_error(&self, error_handle: i32); - fn managed_verify_groth16(&self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32; - fn managed_verify_plonk(&self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32; - fn managed_add_ec(&self, curve_id: i32, group_id: i32, point1_handle: i32, point2_handle: i32, result_handle: i32) -> i32; - fn managed_mul_ec(&self, curve_id: i32, group_id: i32, point_handle: i32, scalar_handle: i32, result_handle: i32) -> i32; - fn managed_multi_exp_ec(&self, curve_id: i32, group_id: i32, points_handle: i32, scalars_handle: i32, result_handle: i32) -> i32; - fn managed_map_to_curve_ec(&self, curve_id: i32, group_id: i32, element_handle: i32, result_handle: i32) -> i32; - fn managed_pairing_checks_ec(&self, curve_id: i32, points_g1_handle: i32, points_g2_handle: i32) -> i32; } /// Dummy implementation for VMHooks. Can be used as placeholder, or in tests. @@ -1618,39 +1611,4 @@ impl VMHooksLegacy for VMHooksLegacyDefault { fn managed_get_last_error(&self, error_handle: i32) { println!("Called: managed_get_last_error"); } - - fn managed_verify_groth16(&self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32 { - println!("Called: managed_verify_groth16"); - 0 - } - - fn managed_verify_plonk(&self, curve_id: i32, proof_handle: i32, vk_handle: i32, pub_witness_handle: i32) -> i32 { - println!("Called: managed_verify_plonk"); - 0 - } - - fn managed_add_ec(&self, curve_id: i32, group_id: i32, point1_handle: i32, point2_handle: i32, result_handle: i32) -> i32 { - println!("Called: managed_add_ec"); - 0 - } - - fn managed_mul_ec(&self, curve_id: i32, group_id: i32, point_handle: i32, scalar_handle: i32, result_handle: i32) -> i32 { - println!("Called: managed_mul_ec"); - 0 - } - - fn managed_multi_exp_ec(&self, curve_id: i32, group_id: i32, points_handle: i32, scalars_handle: i32, result_handle: i32) -> i32 { - println!("Called: managed_multi_exp_ec"); - 0 - } - - fn managed_map_to_curve_ec(&self, curve_id: i32, group_id: i32, element_handle: i32, result_handle: i32) -> i32 { - println!("Called: managed_map_to_curve_ec"); - 0 - } - - fn managed_pairing_checks_ec(&self, curve_id: i32, points_g1_handle: i32, points_g2_handle: i32) -> i32 { - println!("Called: managed_pairing_checks_ec"); - 0 - } } From ca4b9f32aa18a6b0cf2ba430ac6ea87c6818c828 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Wed, 23 Sep 2026 11:22:28 +0300 Subject: [PATCH 23/35] gitignore tweak --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 39e2174..725e250 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ my-* # Other .vscode **/.DS_Store +.claude From be5e6f30e514b4f84a2011b26a1443629abc5788 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Wed, 23 Sep 2026 14:25:18 +0300 Subject: [PATCH 24/35] bulk memory base cost, opcode cost refactor --- vm-executor-experimental/src/middlewares.rs | 2 + .../src/middlewares/we_metering.rs | 14 +- .../src/middlewares/we_opcode_cost.rs | 523 +++++++++--------- .../src/middlewares/we_opcode_cost_type.rs | 20 + vm-executor-wasmer/src/lib.rs | 2 + vm-executor-wasmer/src/wasmer_helpers.rs | 11 - vm-executor-wasmer/src/wasmer_metering.rs | 32 +- vm-executor-wasmer/src/wasmer_opcode_cost.rs | 523 +++++++++--------- .../src/wasmer_opcode_cost_type.rs | 20 + vm-executor-wasmer/tests/bulk-memory.wat | 37 ++ .../tests/bulk_memory_metering_test.rs | 81 +++ vm-executor/src/opcode_cost.rs | 4 + 12 files changed, 723 insertions(+), 546 deletions(-) create mode 100644 vm-executor-experimental/src/middlewares/we_opcode_cost_type.rs create mode 100644 vm-executor-wasmer/src/wasmer_opcode_cost_type.rs create mode 100644 vm-executor-wasmer/tests/bulk-memory.wat create mode 100644 vm-executor-wasmer/tests/bulk_memory_metering_test.rs diff --git a/vm-executor-experimental/src/middlewares.rs b/vm-executor-experimental/src/middlewares.rs index 92e6aa6..3b6ae11 100644 --- a/vm-executor-experimental/src/middlewares.rs +++ b/vm-executor-experimental/src/middlewares.rs @@ -2,6 +2,7 @@ mod we_breakpoints; mod we_metering; mod we_opcode_control; mod we_opcode_cost; +mod we_opcode_cost_type; mod we_opcode_trace; mod we_protected_globals; mod we_protected_globals_trait; @@ -10,6 +11,7 @@ pub(crate) use we_breakpoints::*; pub(crate) use we_metering::*; pub use we_opcode_control::OpcodeControl; pub use we_opcode_cost::*; +pub use we_opcode_cost_type::Cost; pub use we_opcode_trace::OpcodeTracer; pub use we_protected_globals::ProtectedGlobals; pub use we_protected_globals_trait::MiddlewareWithProtectedGlobals; diff --git a/vm-executor-experimental/src/middlewares/we_metering.rs b/vm-executor-experimental/src/middlewares/we_metering.rs index 606bd90..c52c578 100644 --- a/vm-executor-experimental/src/middlewares/we_metering.rs +++ b/vm-executor-experimental/src/middlewares/we_metering.rs @@ -1,7 +1,7 @@ #![allow(unused)] // TODO: until we activate the local count mechanism use super::{ - BREAKPOINT_VALUE_OUT_OF_GAS, Breakpoints, MiddlewareWithProtectedGlobals, get_opcode_cost, + BREAKPOINT_VALUE_OUT_OF_GAS, Breakpoints, Cost, MiddlewareWithProtectedGlobals, get_opcode_cost, }; use crate::we_helpers::{ create_global_index, get_global_value_u64, is_control_flow_operator, set_global_value_u64, @@ -148,15 +148,19 @@ impl FunctionMiddleware for FunctionMetering { // Get the cost of the current operator, and add it to the accumulator. // This needs to be done before the metering logic, to prevent operators like `Call` from escaping metering in some // corner cases. - let option = get_opcode_cost(&operator, &self.opcode_config); - match option { - Some(cost) => self.accumulated_cost += cost as u64, - None => { + let op_exec_cost = get_opcode_cost(&operator, &self.opcode_config); + match op_exec_cost { + Cost::Illegal => { return Err(MiddlewareError::new( "metering_middleware", format!("Unsupported operator: {operator:?}"), )); } + // TODO: the `per_byte` cost is ignored here, the bulk memory operators are not yet + // metered per byte in this executor, unlike in the production one + Cost::Base(base) | Cost::BulkMemory { base, .. } => { + self.accumulated_cost += base as u64 + } } if is_control_flow_operator(&operator) { diff --git a/vm-executor-experimental/src/middlewares/we_opcode_cost.rs b/vm-executor-experimental/src/middlewares/we_opcode_cost.rs index b4b5f41..9b46553 100644 --- a/vm-executor-experimental/src/middlewares/we_opcode_cost.rs +++ b/vm-executor-experimental/src/middlewares/we_opcode_cost.rs @@ -4,279 +4,282 @@ // !!!!!!!!!!!!!!!!!!!!!! AUTO-GENERATED FILE !!!!!!!!!!!!!!!!!!!!!! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +use super::Cost; use multiversx_chain_vm_executor::{OpcodeConfig, OpcodeCost, OpcodeVersion}; use wasmer::wasmparser::Operator; -pub fn get_opcode_cost(op: &Operator, opcode_config: &OpcodeConfig) -> Option { +pub fn get_opcode_cost(op: &Operator, opcode_config: &OpcodeConfig) -> Cost { match opcode_config.opcode_version { OpcodeVersion::V1 => get_opcode_cost_v1(op, &opcode_config.opcode_cost), OpcodeVersion::V2 => get_opcode_cost_v2(op, &opcode_config.opcode_cost), } } -fn get_opcode_cost_v1(op: &Operator, opcode_cost: &OpcodeCost) -> Option { +#[rustfmt::skip] +fn get_opcode_cost_v1(op: &Operator, opcode_cost: &OpcodeCost) -> Cost { match op { - Operator::Block { .. } => Some(opcode_cost.opcode_block), - Operator::Br { .. } => Some(opcode_cost.opcode_br), - Operator::BrIf { .. } => Some(opcode_cost.opcode_brif), - Operator::BrTable { .. } => Some(opcode_cost.opcode_brtable), - Operator::Call { .. } => Some(opcode_cost.opcode_call), - Operator::CallIndirect { .. } => Some(opcode_cost.opcode_callindirect), - Operator::Catch { .. } => Some(opcode_cost.opcode_catch), - Operator::CatchAll { .. } => Some(opcode_cost.opcode_catchall), - Operator::Delegate { .. } => Some(opcode_cost.opcode_delegate), - Operator::Drop { .. } => Some(opcode_cost.opcode_drop), - Operator::Else { .. } => Some(opcode_cost.opcode_else), - Operator::End { .. } => Some(opcode_cost.opcode_end), - Operator::GlobalGet { .. } => Some(opcode_cost.opcode_globalget), - Operator::GlobalSet { .. } => Some(opcode_cost.opcode_globalset), - Operator::I32Add { .. } => Some(opcode_cost.opcode_i32add), - Operator::I32And { .. } => Some(opcode_cost.opcode_i32and), - Operator::I32Clz { .. } => Some(opcode_cost.opcode_i32clz), - Operator::I32Const { .. } => Some(opcode_cost.opcode_i32const), - Operator::I32Ctz { .. } => Some(opcode_cost.opcode_i32ctz), - Operator::I32DivS { .. } => Some(opcode_cost.opcode_i32divs), - Operator::I32DivU { .. } => Some(opcode_cost.opcode_i32divu), - Operator::I32Eq { .. } => Some(opcode_cost.opcode_i32eq), - Operator::I32Eqz { .. } => Some(opcode_cost.opcode_i32eqz), - Operator::I32Extend16S { .. } => Some(opcode_cost.opcode_i32extend16s), - Operator::I32Extend8S { .. } => Some(opcode_cost.opcode_i32extend8s), - Operator::I32GeS { .. } => Some(opcode_cost.opcode_i32ges), - Operator::I32GeU { .. } => Some(opcode_cost.opcode_i32geu), - Operator::I32GtS { .. } => Some(opcode_cost.opcode_i32gts), - Operator::I32GtU { .. } => Some(opcode_cost.opcode_i32gtu), - Operator::I32LeS { .. } => Some(opcode_cost.opcode_i32les), - Operator::I32LeU { .. } => Some(opcode_cost.opcode_i32leu), - Operator::I32Load { .. } => Some(opcode_cost.opcode_i32load), - Operator::I32Load16S { .. } => Some(opcode_cost.opcode_i32load16s), - Operator::I32Load16U { .. } => Some(opcode_cost.opcode_i32load16u), - Operator::I32Load8S { .. } => Some(opcode_cost.opcode_i32load8s), - Operator::I32Load8U { .. } => Some(opcode_cost.opcode_i32load8u), - Operator::I32LtS { .. } => Some(opcode_cost.opcode_i32lts), - Operator::I32LtU { .. } => Some(opcode_cost.opcode_i32ltu), - Operator::I32Mul { .. } => Some(opcode_cost.opcode_i32mul), - Operator::I32Ne { .. } => Some(opcode_cost.opcode_i32ne), - Operator::I32Or { .. } => Some(opcode_cost.opcode_i32or), - Operator::I32Popcnt { .. } => Some(opcode_cost.opcode_i32popcnt), - Operator::I32RemS { .. } => Some(opcode_cost.opcode_i32rems), - Operator::I32RemU { .. } => Some(opcode_cost.opcode_i32remu), - Operator::I32Rotl { .. } => Some(opcode_cost.opcode_i32rotl), - Operator::I32Rotr { .. } => Some(opcode_cost.opcode_i32rotr), - Operator::I32Shl { .. } => Some(opcode_cost.opcode_i32shl), - Operator::I32ShrS { .. } => Some(opcode_cost.opcode_i32shrs), - Operator::I32ShrU { .. } => Some(opcode_cost.opcode_i32shru), - Operator::I32Store { .. } => Some(opcode_cost.opcode_i32store), - Operator::I32Store16 { .. } => Some(opcode_cost.opcode_i32store16), - Operator::I32Store8 { .. } => Some(opcode_cost.opcode_i32store8), - Operator::I32Sub { .. } => Some(opcode_cost.opcode_i32sub), - Operator::I32WrapI64 { .. } => Some(opcode_cost.opcode_i32wrapi64), - Operator::I32Xor { .. } => Some(opcode_cost.opcode_i32xor), - Operator::I64Add { .. } => Some(opcode_cost.opcode_i64add), - Operator::I64And { .. } => Some(opcode_cost.opcode_i64and), - Operator::I64Clz { .. } => Some(opcode_cost.opcode_i64clz), - Operator::I64Const { .. } => Some(opcode_cost.opcode_i64const), - Operator::I64Ctz { .. } => Some(opcode_cost.opcode_i64ctz), - Operator::I64DivS { .. } => Some(opcode_cost.opcode_i64divs), - Operator::I64DivU { .. } => Some(opcode_cost.opcode_i64divu), - Operator::I64Eq { .. } => Some(opcode_cost.opcode_i64eq), - Operator::I64Eqz { .. } => Some(opcode_cost.opcode_i64eqz), - Operator::I64Extend16S { .. } => Some(opcode_cost.opcode_i64extend16s), - Operator::I64Extend32S { .. } => Some(opcode_cost.opcode_i64extend32s), - Operator::I64Extend8S { .. } => Some(opcode_cost.opcode_i64extend8s), - Operator::I64ExtendI32S { .. } => Some(opcode_cost.opcode_i64extendi32s), - Operator::I64ExtendI32U { .. } => Some(opcode_cost.opcode_i64extendi32u), - Operator::I64GeS { .. } => Some(opcode_cost.opcode_i64ges), - Operator::I64GeU { .. } => Some(opcode_cost.opcode_i64geu), - Operator::I64GtS { .. } => Some(opcode_cost.opcode_i64gts), - Operator::I64GtU { .. } => Some(opcode_cost.opcode_i64gtu), - Operator::I64LeS { .. } => Some(opcode_cost.opcode_i64les), - Operator::I64LeU { .. } => Some(opcode_cost.opcode_i64leu), - Operator::I64Load { .. } => Some(opcode_cost.opcode_i64load), - Operator::I64Load16S { .. } => Some(opcode_cost.opcode_i64load16s), - Operator::I64Load16U { .. } => Some(opcode_cost.opcode_i64load16u), - Operator::I64Load32S { .. } => Some(opcode_cost.opcode_i64load32s), - Operator::I64Load32U { .. } => Some(opcode_cost.opcode_i64load32u), - Operator::I64Load8S { .. } => Some(opcode_cost.opcode_i64load8s), - Operator::I64Load8U { .. } => Some(opcode_cost.opcode_i64load8u), - Operator::I64LtS { .. } => Some(opcode_cost.opcode_i64lts), - Operator::I64LtU { .. } => Some(opcode_cost.opcode_i64ltu), - Operator::I64Mul { .. } => Some(opcode_cost.opcode_i64mul), - Operator::I64Ne { .. } => Some(opcode_cost.opcode_i64ne), - Operator::I64Or { .. } => Some(opcode_cost.opcode_i64or), - Operator::I64Popcnt { .. } => Some(opcode_cost.opcode_i64popcnt), - Operator::I64RemS { .. } => Some(opcode_cost.opcode_i64rems), - Operator::I64RemU { .. } => Some(opcode_cost.opcode_i64remu), - Operator::I64Rotl { .. } => Some(opcode_cost.opcode_i64rotl), - Operator::I64Rotr { .. } => Some(opcode_cost.opcode_i64rotr), - Operator::I64Shl { .. } => Some(opcode_cost.opcode_i64shl), - Operator::I64ShrS { .. } => Some(opcode_cost.opcode_i64shrs), - Operator::I64ShrU { .. } => Some(opcode_cost.opcode_i64shru), - Operator::I64Store { .. } => Some(opcode_cost.opcode_i64store), - Operator::I64Store16 { .. } => Some(opcode_cost.opcode_i64store16), - Operator::I64Store32 { .. } => Some(opcode_cost.opcode_i64store32), - Operator::I64Store8 { .. } => Some(opcode_cost.opcode_i64store8), - Operator::I64Sub { .. } => Some(opcode_cost.opcode_i64sub), - Operator::I64Xor { .. } => Some(opcode_cost.opcode_i64xor), - Operator::If { .. } => Some(opcode_cost.opcode_if), - Operator::LocalGet { .. } => Some(opcode_cost.opcode_localget), - Operator::LocalSet { .. } => Some(opcode_cost.opcode_localset), - Operator::LocalTee { .. } => Some(opcode_cost.opcode_localtee), - Operator::Loop { .. } => Some(opcode_cost.opcode_loop), - Operator::MemoryGrow { .. } => Some(opcode_cost.opcode_memorygrow), - Operator::MemorySize { .. } => Some(opcode_cost.opcode_memorysize), - Operator::Nop { .. } => Some(opcode_cost.opcode_nop), - Operator::RefFunc { .. } => Some(opcode_cost.opcode_reffunc), - Operator::RefIsNull { .. } => Some(opcode_cost.opcode_refisnull), - Operator::RefNull { .. } => Some(opcode_cost.opcode_refnull), - Operator::Rethrow { .. } => Some(opcode_cost.opcode_rethrow), - Operator::Return { .. } => Some(opcode_cost.opcode_return), - Operator::ReturnCall { .. } => Some(opcode_cost.opcode_returncall), - Operator::ReturnCallIndirect { .. } => Some(opcode_cost.opcode_returncallindirect), - Operator::Select { .. } => Some(opcode_cost.opcode_select), - Operator::TableGet { .. } => Some(opcode_cost.opcode_tableget), - Operator::TableGrow { .. } => Some(opcode_cost.opcode_tablegrow), - Operator::TableInit { .. } => Some(opcode_cost.opcode_tableinit), - Operator::TableSet { .. } => Some(opcode_cost.opcode_tableset), - Operator::TableSize { .. } => Some(opcode_cost.opcode_tablesize), - Operator::Throw { .. } => Some(opcode_cost.opcode_throw), - Operator::Try { .. } => Some(opcode_cost.opcode_try), - Operator::TypedSelect { .. } => Some(opcode_cost.opcode_typedselect), - Operator::Unreachable { .. } => Some(opcode_cost.opcode_unreachable), - // Operator::Unwind { .. } => Some(opcode_cost.opcode_unwind), // unwind no longer available in Wasmer 6 - _ => None, + Operator::Block { .. } => Cost::Base(opcode_cost.opcode_block), + Operator::Br { .. } => Cost::Base(opcode_cost.opcode_br), + Operator::BrIf { .. } => Cost::Base(opcode_cost.opcode_brif), + Operator::BrTable { .. } => Cost::Base(opcode_cost.opcode_brtable), + Operator::Call { .. } => Cost::Base(opcode_cost.opcode_call), + Operator::CallIndirect { .. } => Cost::Base(opcode_cost.opcode_callindirect), + Operator::Catch { .. } => Cost::Base(opcode_cost.opcode_catch), + Operator::CatchAll { .. } => Cost::Base(opcode_cost.opcode_catchall), + Operator::Delegate { .. } => Cost::Base(opcode_cost.opcode_delegate), + Operator::Drop { .. } => Cost::Base(opcode_cost.opcode_drop), + Operator::Else { .. } => Cost::Base(opcode_cost.opcode_else), + Operator::End { .. } => Cost::Base(opcode_cost.opcode_end), + Operator::GlobalGet { .. } => Cost::Base(opcode_cost.opcode_globalget), + Operator::GlobalSet { .. } => Cost::Base(opcode_cost.opcode_globalset), + Operator::I32Add { .. } => Cost::Base(opcode_cost.opcode_i32add), + Operator::I32And { .. } => Cost::Base(opcode_cost.opcode_i32and), + Operator::I32Clz { .. } => Cost::Base(opcode_cost.opcode_i32clz), + Operator::I32Const { .. } => Cost::Base(opcode_cost.opcode_i32const), + Operator::I32Ctz { .. } => Cost::Base(opcode_cost.opcode_i32ctz), + Operator::I32DivS { .. } => Cost::Base(opcode_cost.opcode_i32divs), + Operator::I32DivU { .. } => Cost::Base(opcode_cost.opcode_i32divu), + Operator::I32Eq { .. } => Cost::Base(opcode_cost.opcode_i32eq), + Operator::I32Eqz { .. } => Cost::Base(opcode_cost.opcode_i32eqz), + Operator::I32Extend16S { .. } => Cost::Base(opcode_cost.opcode_i32extend16s), + Operator::I32Extend8S { .. } => Cost::Base(opcode_cost.opcode_i32extend8s), + Operator::I32GeS { .. } => Cost::Base(opcode_cost.opcode_i32ges), + Operator::I32GeU { .. } => Cost::Base(opcode_cost.opcode_i32geu), + Operator::I32GtS { .. } => Cost::Base(opcode_cost.opcode_i32gts), + Operator::I32GtU { .. } => Cost::Base(opcode_cost.opcode_i32gtu), + Operator::I32LeS { .. } => Cost::Base(opcode_cost.opcode_i32les), + Operator::I32LeU { .. } => Cost::Base(opcode_cost.opcode_i32leu), + Operator::I32Load { .. } => Cost::Base(opcode_cost.opcode_i32load), + Operator::I32Load16S { .. } => Cost::Base(opcode_cost.opcode_i32load16s), + Operator::I32Load16U { .. } => Cost::Base(opcode_cost.opcode_i32load16u), + Operator::I32Load8S { .. } => Cost::Base(opcode_cost.opcode_i32load8s), + Operator::I32Load8U { .. } => Cost::Base(opcode_cost.opcode_i32load8u), + Operator::I32LtS { .. } => Cost::Base(opcode_cost.opcode_i32lts), + Operator::I32LtU { .. } => Cost::Base(opcode_cost.opcode_i32ltu), + Operator::I32Mul { .. } => Cost::Base(opcode_cost.opcode_i32mul), + Operator::I32Ne { .. } => Cost::Base(opcode_cost.opcode_i32ne), + Operator::I32Or { .. } => Cost::Base(opcode_cost.opcode_i32or), + Operator::I32Popcnt { .. } => Cost::Base(opcode_cost.opcode_i32popcnt), + Operator::I32RemS { .. } => Cost::Base(opcode_cost.opcode_i32rems), + Operator::I32RemU { .. } => Cost::Base(opcode_cost.opcode_i32remu), + Operator::I32Rotl { .. } => Cost::Base(opcode_cost.opcode_i32rotl), + Operator::I32Rotr { .. } => Cost::Base(opcode_cost.opcode_i32rotr), + Operator::I32Shl { .. } => Cost::Base(opcode_cost.opcode_i32shl), + Operator::I32ShrS { .. } => Cost::Base(opcode_cost.opcode_i32shrs), + Operator::I32ShrU { .. } => Cost::Base(opcode_cost.opcode_i32shru), + Operator::I32Store { .. } => Cost::Base(opcode_cost.opcode_i32store), + Operator::I32Store16 { .. } => Cost::Base(opcode_cost.opcode_i32store16), + Operator::I32Store8 { .. } => Cost::Base(opcode_cost.opcode_i32store8), + Operator::I32Sub { .. } => Cost::Base(opcode_cost.opcode_i32sub), + Operator::I32WrapI64 { .. } => Cost::Base(opcode_cost.opcode_i32wrapi64), + Operator::I32Xor { .. } => Cost::Base(opcode_cost.opcode_i32xor), + Operator::I64Add { .. } => Cost::Base(opcode_cost.opcode_i64add), + Operator::I64And { .. } => Cost::Base(opcode_cost.opcode_i64and), + Operator::I64Clz { .. } => Cost::Base(opcode_cost.opcode_i64clz), + Operator::I64Const { .. } => Cost::Base(opcode_cost.opcode_i64const), + Operator::I64Ctz { .. } => Cost::Base(opcode_cost.opcode_i64ctz), + Operator::I64DivS { .. } => Cost::Base(opcode_cost.opcode_i64divs), + Operator::I64DivU { .. } => Cost::Base(opcode_cost.opcode_i64divu), + Operator::I64Eq { .. } => Cost::Base(opcode_cost.opcode_i64eq), + Operator::I64Eqz { .. } => Cost::Base(opcode_cost.opcode_i64eqz), + Operator::I64Extend16S { .. } => Cost::Base(opcode_cost.opcode_i64extend16s), + Operator::I64Extend32S { .. } => Cost::Base(opcode_cost.opcode_i64extend32s), + Operator::I64Extend8S { .. } => Cost::Base(opcode_cost.opcode_i64extend8s), + Operator::I64ExtendI32S { .. } => Cost::Base(opcode_cost.opcode_i64extendi32s), + Operator::I64ExtendI32U { .. } => Cost::Base(opcode_cost.opcode_i64extendi32u), + Operator::I64GeS { .. } => Cost::Base(opcode_cost.opcode_i64ges), + Operator::I64GeU { .. } => Cost::Base(opcode_cost.opcode_i64geu), + Operator::I64GtS { .. } => Cost::Base(opcode_cost.opcode_i64gts), + Operator::I64GtU { .. } => Cost::Base(opcode_cost.opcode_i64gtu), + Operator::I64LeS { .. } => Cost::Base(opcode_cost.opcode_i64les), + Operator::I64LeU { .. } => Cost::Base(opcode_cost.opcode_i64leu), + Operator::I64Load { .. } => Cost::Base(opcode_cost.opcode_i64load), + Operator::I64Load16S { .. } => Cost::Base(opcode_cost.opcode_i64load16s), + Operator::I64Load16U { .. } => Cost::Base(opcode_cost.opcode_i64load16u), + Operator::I64Load32S { .. } => Cost::Base(opcode_cost.opcode_i64load32s), + Operator::I64Load32U { .. } => Cost::Base(opcode_cost.opcode_i64load32u), + Operator::I64Load8S { .. } => Cost::Base(opcode_cost.opcode_i64load8s), + Operator::I64Load8U { .. } => Cost::Base(opcode_cost.opcode_i64load8u), + Operator::I64LtS { .. } => Cost::Base(opcode_cost.opcode_i64lts), + Operator::I64LtU { .. } => Cost::Base(opcode_cost.opcode_i64ltu), + Operator::I64Mul { .. } => Cost::Base(opcode_cost.opcode_i64mul), + Operator::I64Ne { .. } => Cost::Base(opcode_cost.opcode_i64ne), + Operator::I64Or { .. } => Cost::Base(opcode_cost.opcode_i64or), + Operator::I64Popcnt { .. } => Cost::Base(opcode_cost.opcode_i64popcnt), + Operator::I64RemS { .. } => Cost::Base(opcode_cost.opcode_i64rems), + Operator::I64RemU { .. } => Cost::Base(opcode_cost.opcode_i64remu), + Operator::I64Rotl { .. } => Cost::Base(opcode_cost.opcode_i64rotl), + Operator::I64Rotr { .. } => Cost::Base(opcode_cost.opcode_i64rotr), + Operator::I64Shl { .. } => Cost::Base(opcode_cost.opcode_i64shl), + Operator::I64ShrS { .. } => Cost::Base(opcode_cost.opcode_i64shrs), + Operator::I64ShrU { .. } => Cost::Base(opcode_cost.opcode_i64shru), + Operator::I64Store { .. } => Cost::Base(opcode_cost.opcode_i64store), + Operator::I64Store16 { .. } => Cost::Base(opcode_cost.opcode_i64store16), + Operator::I64Store32 { .. } => Cost::Base(opcode_cost.opcode_i64store32), + Operator::I64Store8 { .. } => Cost::Base(opcode_cost.opcode_i64store8), + Operator::I64Sub { .. } => Cost::Base(opcode_cost.opcode_i64sub), + Operator::I64Xor { .. } => Cost::Base(opcode_cost.opcode_i64xor), + Operator::If { .. } => Cost::Base(opcode_cost.opcode_if), + Operator::LocalGet { .. } => Cost::Base(opcode_cost.opcode_localget), + Operator::LocalSet { .. } => Cost::Base(opcode_cost.opcode_localset), + Operator::LocalTee { .. } => Cost::Base(opcode_cost.opcode_localtee), + Operator::Loop { .. } => Cost::Base(opcode_cost.opcode_loop), + Operator::MemoryGrow { .. } => Cost::Base(opcode_cost.opcode_memorygrow), + Operator::MemorySize { .. } => Cost::Base(opcode_cost.opcode_memorysize), + Operator::Nop { .. } => Cost::Base(opcode_cost.opcode_nop), + Operator::RefFunc { .. } => Cost::Base(opcode_cost.opcode_reffunc), + Operator::RefIsNull { .. } => Cost::Base(opcode_cost.opcode_refisnull), + Operator::RefNull { .. } => Cost::Base(opcode_cost.opcode_refnull), + Operator::Rethrow { .. } => Cost::Base(opcode_cost.opcode_rethrow), + Operator::Return { .. } => Cost::Base(opcode_cost.opcode_return), + Operator::ReturnCall { .. } => Cost::Base(opcode_cost.opcode_returncall), + Operator::ReturnCallIndirect { .. } => Cost::Base(opcode_cost.opcode_returncallindirect), + Operator::Select { .. } => Cost::Base(opcode_cost.opcode_select), + Operator::TableGet { .. } => Cost::Base(opcode_cost.opcode_tableget), + Operator::TableGrow { .. } => Cost::Base(opcode_cost.opcode_tablegrow), + Operator::TableInit { .. } => Cost::Base(opcode_cost.opcode_tableinit), + Operator::TableSet { .. } => Cost::Base(opcode_cost.opcode_tableset), + Operator::TableSize { .. } => Cost::Base(opcode_cost.opcode_tablesize), + Operator::Throw { .. } => Cost::Base(opcode_cost.opcode_throw), + Operator::Try { .. } => Cost::Base(opcode_cost.opcode_try), + Operator::TypedSelect { .. } => Cost::Base(opcode_cost.opcode_typedselect), + Operator::Unreachable { .. } => Cost::Base(opcode_cost.opcode_unreachable), + // Operator::Unwind { .. } => Cost::Base(opcode_cost.opcode_unwind), // unwind no longer available in Wasmer 6 + _ => Cost::Illegal, } } -fn get_opcode_cost_v2(op: &Operator, opcode_cost: &OpcodeCost) -> Option { +#[rustfmt::skip] +fn get_opcode_cost_v2(op: &Operator, opcode_cost: &OpcodeCost) -> Cost { match op { - Operator::Block { .. } => Some(opcode_cost.opcode_block), - Operator::Br { .. } => Some(opcode_cost.opcode_br), - Operator::BrIf { .. } => Some(opcode_cost.opcode_brif), - Operator::BrTable { .. } => Some(opcode_cost.opcode_brtable), - Operator::Call { .. } => Some(opcode_cost.opcode_call), - Operator::CallIndirect { .. } => Some(opcode_cost.opcode_callindirect), - Operator::Catch { .. } => Some(opcode_cost.opcode_catch), - Operator::CatchAll { .. } => Some(opcode_cost.opcode_catchall), - Operator::Delegate { .. } => Some(opcode_cost.opcode_delegate), - Operator::Drop { .. } => Some(opcode_cost.opcode_drop), - Operator::Else { .. } => Some(opcode_cost.opcode_else), - Operator::End { .. } => Some(opcode_cost.opcode_end), - Operator::GlobalGet { .. } => Some(opcode_cost.opcode_globalget), - Operator::GlobalSet { .. } => Some(opcode_cost.opcode_globalset), - Operator::I32Add { .. } => Some(opcode_cost.opcode_i32add), - Operator::I32And { .. } => Some(opcode_cost.opcode_i32and), - Operator::I32Clz { .. } => Some(opcode_cost.opcode_i32clz), - Operator::I32Const { .. } => Some(opcode_cost.opcode_i32const), - Operator::I32Ctz { .. } => Some(opcode_cost.opcode_i32ctz), - Operator::I32DivS { .. } => Some(opcode_cost.opcode_i32divs), - Operator::I32DivU { .. } => Some(opcode_cost.opcode_i32divu), - Operator::I32Eq { .. } => Some(opcode_cost.opcode_i32eq), - Operator::I32Eqz { .. } => Some(opcode_cost.opcode_i32eqz), - Operator::I32Extend16S { .. } => Some(opcode_cost.opcode_i32extend16s), - Operator::I32Extend8S { .. } => Some(opcode_cost.opcode_i32extend8s), - Operator::I32GeS { .. } => Some(opcode_cost.opcode_i32ges), - Operator::I32GeU { .. } => Some(opcode_cost.opcode_i32geu), - Operator::I32GtS { .. } => Some(opcode_cost.opcode_i32gts), - Operator::I32GtU { .. } => Some(opcode_cost.opcode_i32gtu), - Operator::I32LeS { .. } => Some(opcode_cost.opcode_i32les), - Operator::I32LeU { .. } => Some(opcode_cost.opcode_i32leu), - Operator::I32Load { .. } => Some(opcode_cost.opcode_i32load), - Operator::I32Load16S { .. } => Some(opcode_cost.opcode_i32load16s), - Operator::I32Load16U { .. } => Some(opcode_cost.opcode_i32load16u), - Operator::I32Load8S { .. } => Some(opcode_cost.opcode_i32load8s), - Operator::I32Load8U { .. } => Some(opcode_cost.opcode_i32load8u), - Operator::I32LtS { .. } => Some(opcode_cost.opcode_i32lts), - Operator::I32LtU { .. } => Some(opcode_cost.opcode_i32ltu), - Operator::I32Mul { .. } => Some(opcode_cost.opcode_i32mul), - Operator::I32Ne { .. } => Some(opcode_cost.opcode_i32ne), - Operator::I32Or { .. } => Some(opcode_cost.opcode_i32or), - Operator::I32Popcnt { .. } => Some(opcode_cost.opcode_i32popcnt), - Operator::I32RemS { .. } => Some(opcode_cost.opcode_i32rems), - Operator::I32RemU { .. } => Some(opcode_cost.opcode_i32remu), - Operator::I32Rotl { .. } => Some(opcode_cost.opcode_i32rotl), - Operator::I32Rotr { .. } => Some(opcode_cost.opcode_i32rotr), - Operator::I32Shl { .. } => Some(opcode_cost.opcode_i32shl), - Operator::I32ShrS { .. } => Some(opcode_cost.opcode_i32shrs), - Operator::I32ShrU { .. } => Some(opcode_cost.opcode_i32shru), - Operator::I32Store { .. } => Some(opcode_cost.opcode_i32store), - Operator::I32Store16 { .. } => Some(opcode_cost.opcode_i32store16), - Operator::I32Store8 { .. } => Some(opcode_cost.opcode_i32store8), - Operator::I32Sub { .. } => Some(opcode_cost.opcode_i32sub), - Operator::I32WrapI64 { .. } => Some(opcode_cost.opcode_i32wrapi64), - Operator::I32Xor { .. } => Some(opcode_cost.opcode_i32xor), - Operator::I64Add { .. } => Some(opcode_cost.opcode_i64add), - Operator::I64And { .. } => Some(opcode_cost.opcode_i64and), - Operator::I64Clz { .. } => Some(opcode_cost.opcode_i64clz), - Operator::I64Const { .. } => Some(opcode_cost.opcode_i64const), - Operator::I64Ctz { .. } => Some(opcode_cost.opcode_i64ctz), - Operator::I64DivS { .. } => Some(opcode_cost.opcode_i64divs), - Operator::I64DivU { .. } => Some(opcode_cost.opcode_i64divu), - Operator::I64Eq { .. } => Some(opcode_cost.opcode_i64eq), - Operator::I64Eqz { .. } => Some(opcode_cost.opcode_i64eqz), - Operator::I64Extend16S { .. } => Some(opcode_cost.opcode_i64extend16s), - Operator::I64Extend32S { .. } => Some(opcode_cost.opcode_i64extend32s), - Operator::I64Extend8S { .. } => Some(opcode_cost.opcode_i64extend8s), - Operator::I64ExtendI32S { .. } => Some(opcode_cost.opcode_i64extendi32s), - Operator::I64ExtendI32U { .. } => Some(opcode_cost.opcode_i64extendi32u), - Operator::I64GeS { .. } => Some(opcode_cost.opcode_i64ges), - Operator::I64GeU { .. } => Some(opcode_cost.opcode_i64geu), - Operator::I64GtS { .. } => Some(opcode_cost.opcode_i64gts), - Operator::I64GtU { .. } => Some(opcode_cost.opcode_i64gtu), - Operator::I64LeS { .. } => Some(opcode_cost.opcode_i64les), - Operator::I64LeU { .. } => Some(opcode_cost.opcode_i64leu), - Operator::I64Load { .. } => Some(opcode_cost.opcode_i64load), - Operator::I64Load16S { .. } => Some(opcode_cost.opcode_i64load16s), - Operator::I64Load16U { .. } => Some(opcode_cost.opcode_i64load16u), - Operator::I64Load32S { .. } => Some(opcode_cost.opcode_i64load32s), - Operator::I64Load32U { .. } => Some(opcode_cost.opcode_i64load32u), - Operator::I64Load8S { .. } => Some(opcode_cost.opcode_i64load8s), - Operator::I64Load8U { .. } => Some(opcode_cost.opcode_i64load8u), - Operator::I64LtS { .. } => Some(opcode_cost.opcode_i64lts), - Operator::I64LtU { .. } => Some(opcode_cost.opcode_i64ltu), - Operator::I64Mul { .. } => Some(opcode_cost.opcode_i64mul), - Operator::I64Ne { .. } => Some(opcode_cost.opcode_i64ne), - Operator::I64Or { .. } => Some(opcode_cost.opcode_i64or), - Operator::I64Popcnt { .. } => Some(opcode_cost.opcode_i64popcnt), - Operator::I64RemS { .. } => Some(opcode_cost.opcode_i64rems), - Operator::I64RemU { .. } => Some(opcode_cost.opcode_i64remu), - Operator::I64Rotl { .. } => Some(opcode_cost.opcode_i64rotl), - Operator::I64Rotr { .. } => Some(opcode_cost.opcode_i64rotr), - Operator::I64Shl { .. } => Some(opcode_cost.opcode_i64shl), - Operator::I64ShrS { .. } => Some(opcode_cost.opcode_i64shrs), - Operator::I64ShrU { .. } => Some(opcode_cost.opcode_i64shru), - Operator::I64Store { .. } => Some(opcode_cost.opcode_i64store), - Operator::I64Store16 { .. } => Some(opcode_cost.opcode_i64store16), - Operator::I64Store32 { .. } => Some(opcode_cost.opcode_i64store32), - Operator::I64Store8 { .. } => Some(opcode_cost.opcode_i64store8), - Operator::I64Sub { .. } => Some(opcode_cost.opcode_i64sub), - Operator::I64Xor { .. } => Some(opcode_cost.opcode_i64xor), - Operator::If { .. } => Some(opcode_cost.opcode_if), - Operator::LocalGet { .. } => Some(opcode_cost.opcode_localget), - Operator::LocalSet { .. } => Some(opcode_cost.opcode_localset), - Operator::LocalTee { .. } => Some(opcode_cost.opcode_localtee), - Operator::Loop { .. } => Some(opcode_cost.opcode_loop), - Operator::MemoryGrow { .. } => Some(opcode_cost.opcode_memorygrow), - Operator::MemorySize { .. } => Some(opcode_cost.opcode_memorysize), - Operator::Nop { .. } => Some(opcode_cost.opcode_nop), - Operator::RefFunc { .. } => Some(opcode_cost.opcode_reffunc), - Operator::RefIsNull { .. } => Some(opcode_cost.opcode_refisnull), - Operator::RefNull { .. } => Some(opcode_cost.opcode_refnull), - Operator::Rethrow { .. } => Some(opcode_cost.opcode_rethrow), - Operator::Return { .. } => Some(opcode_cost.opcode_return), - Operator::ReturnCall { .. } => Some(opcode_cost.opcode_returncall), - Operator::ReturnCallIndirect { .. } => Some(opcode_cost.opcode_returncallindirect), - Operator::Select { .. } => Some(opcode_cost.opcode_select), - Operator::TableGet { .. } => Some(opcode_cost.opcode_tableget), - Operator::TableGrow { .. } => Some(opcode_cost.opcode_tablegrow), - Operator::TableInit { .. } => Some(opcode_cost.opcode_tableinit), - Operator::TableSet { .. } => Some(opcode_cost.opcode_tableset), - Operator::TableSize { .. } => Some(opcode_cost.opcode_tablesize), - Operator::Throw { .. } => Some(opcode_cost.opcode_throw), - Operator::Try { .. } => Some(opcode_cost.opcode_try), - Operator::TypedSelect { .. } => Some(opcode_cost.opcode_typedselect), - Operator::Unreachable { .. } => Some(opcode_cost.opcode_unreachable), - Operator::MemoryCopy { .. } => Some(opcode_cost.opcode_memorycopy), - Operator::MemoryFill { .. } => Some(opcode_cost.opcode_memoryfill), - _ => None, + Operator::Block { .. } => Cost::Base(opcode_cost.opcode_block), + Operator::Br { .. } => Cost::Base(opcode_cost.opcode_br), + Operator::BrIf { .. } => Cost::Base(opcode_cost.opcode_brif), + Operator::BrTable { .. } => Cost::Base(opcode_cost.opcode_brtable), + Operator::Call { .. } => Cost::Base(opcode_cost.opcode_call), + Operator::CallIndirect { .. } => Cost::Base(opcode_cost.opcode_callindirect), + Operator::Catch { .. } => Cost::Base(opcode_cost.opcode_catch), + Operator::CatchAll { .. } => Cost::Base(opcode_cost.opcode_catchall), + Operator::Delegate { .. } => Cost::Base(opcode_cost.opcode_delegate), + Operator::Drop { .. } => Cost::Base(opcode_cost.opcode_drop), + Operator::Else { .. } => Cost::Base(opcode_cost.opcode_else), + Operator::End { .. } => Cost::Base(opcode_cost.opcode_end), + Operator::GlobalGet { .. } => Cost::Base(opcode_cost.opcode_globalget), + Operator::GlobalSet { .. } => Cost::Base(opcode_cost.opcode_globalset), + Operator::I32Add { .. } => Cost::Base(opcode_cost.opcode_i32add), + Operator::I32And { .. } => Cost::Base(opcode_cost.opcode_i32and), + Operator::I32Clz { .. } => Cost::Base(opcode_cost.opcode_i32clz), + Operator::I32Const { .. } => Cost::Base(opcode_cost.opcode_i32const), + Operator::I32Ctz { .. } => Cost::Base(opcode_cost.opcode_i32ctz), + Operator::I32DivS { .. } => Cost::Base(opcode_cost.opcode_i32divs), + Operator::I32DivU { .. } => Cost::Base(opcode_cost.opcode_i32divu), + Operator::I32Eq { .. } => Cost::Base(opcode_cost.opcode_i32eq), + Operator::I32Eqz { .. } => Cost::Base(opcode_cost.opcode_i32eqz), + Operator::I32Extend16S { .. } => Cost::Base(opcode_cost.opcode_i32extend16s), + Operator::I32Extend8S { .. } => Cost::Base(opcode_cost.opcode_i32extend8s), + Operator::I32GeS { .. } => Cost::Base(opcode_cost.opcode_i32ges), + Operator::I32GeU { .. } => Cost::Base(opcode_cost.opcode_i32geu), + Operator::I32GtS { .. } => Cost::Base(opcode_cost.opcode_i32gts), + Operator::I32GtU { .. } => Cost::Base(opcode_cost.opcode_i32gtu), + Operator::I32LeS { .. } => Cost::Base(opcode_cost.opcode_i32les), + Operator::I32LeU { .. } => Cost::Base(opcode_cost.opcode_i32leu), + Operator::I32Load { .. } => Cost::Base(opcode_cost.opcode_i32load), + Operator::I32Load16S { .. } => Cost::Base(opcode_cost.opcode_i32load16s), + Operator::I32Load16U { .. } => Cost::Base(opcode_cost.opcode_i32load16u), + Operator::I32Load8S { .. } => Cost::Base(opcode_cost.opcode_i32load8s), + Operator::I32Load8U { .. } => Cost::Base(opcode_cost.opcode_i32load8u), + Operator::I32LtS { .. } => Cost::Base(opcode_cost.opcode_i32lts), + Operator::I32LtU { .. } => Cost::Base(opcode_cost.opcode_i32ltu), + Operator::I32Mul { .. } => Cost::Base(opcode_cost.opcode_i32mul), + Operator::I32Ne { .. } => Cost::Base(opcode_cost.opcode_i32ne), + Operator::I32Or { .. } => Cost::Base(opcode_cost.opcode_i32or), + Operator::I32Popcnt { .. } => Cost::Base(opcode_cost.opcode_i32popcnt), + Operator::I32RemS { .. } => Cost::Base(opcode_cost.opcode_i32rems), + Operator::I32RemU { .. } => Cost::Base(opcode_cost.opcode_i32remu), + Operator::I32Rotl { .. } => Cost::Base(opcode_cost.opcode_i32rotl), + Operator::I32Rotr { .. } => Cost::Base(opcode_cost.opcode_i32rotr), + Operator::I32Shl { .. } => Cost::Base(opcode_cost.opcode_i32shl), + Operator::I32ShrS { .. } => Cost::Base(opcode_cost.opcode_i32shrs), + Operator::I32ShrU { .. } => Cost::Base(opcode_cost.opcode_i32shru), + Operator::I32Store { .. } => Cost::Base(opcode_cost.opcode_i32store), + Operator::I32Store16 { .. } => Cost::Base(opcode_cost.opcode_i32store16), + Operator::I32Store8 { .. } => Cost::Base(opcode_cost.opcode_i32store8), + Operator::I32Sub { .. } => Cost::Base(opcode_cost.opcode_i32sub), + Operator::I32WrapI64 { .. } => Cost::Base(opcode_cost.opcode_i32wrapi64), + Operator::I32Xor { .. } => Cost::Base(opcode_cost.opcode_i32xor), + Operator::I64Add { .. } => Cost::Base(opcode_cost.opcode_i64add), + Operator::I64And { .. } => Cost::Base(opcode_cost.opcode_i64and), + Operator::I64Clz { .. } => Cost::Base(opcode_cost.opcode_i64clz), + Operator::I64Const { .. } => Cost::Base(opcode_cost.opcode_i64const), + Operator::I64Ctz { .. } => Cost::Base(opcode_cost.opcode_i64ctz), + Operator::I64DivS { .. } => Cost::Base(opcode_cost.opcode_i64divs), + Operator::I64DivU { .. } => Cost::Base(opcode_cost.opcode_i64divu), + Operator::I64Eq { .. } => Cost::Base(opcode_cost.opcode_i64eq), + Operator::I64Eqz { .. } => Cost::Base(opcode_cost.opcode_i64eqz), + Operator::I64Extend16S { .. } => Cost::Base(opcode_cost.opcode_i64extend16s), + Operator::I64Extend32S { .. } => Cost::Base(opcode_cost.opcode_i64extend32s), + Operator::I64Extend8S { .. } => Cost::Base(opcode_cost.opcode_i64extend8s), + Operator::I64ExtendI32S { .. } => Cost::Base(opcode_cost.opcode_i64extendi32s), + Operator::I64ExtendI32U { .. } => Cost::Base(opcode_cost.opcode_i64extendi32u), + Operator::I64GeS { .. } => Cost::Base(opcode_cost.opcode_i64ges), + Operator::I64GeU { .. } => Cost::Base(opcode_cost.opcode_i64geu), + Operator::I64GtS { .. } => Cost::Base(opcode_cost.opcode_i64gts), + Operator::I64GtU { .. } => Cost::Base(opcode_cost.opcode_i64gtu), + Operator::I64LeS { .. } => Cost::Base(opcode_cost.opcode_i64les), + Operator::I64LeU { .. } => Cost::Base(opcode_cost.opcode_i64leu), + Operator::I64Load { .. } => Cost::Base(opcode_cost.opcode_i64load), + Operator::I64Load16S { .. } => Cost::Base(opcode_cost.opcode_i64load16s), + Operator::I64Load16U { .. } => Cost::Base(opcode_cost.opcode_i64load16u), + Operator::I64Load32S { .. } => Cost::Base(opcode_cost.opcode_i64load32s), + Operator::I64Load32U { .. } => Cost::Base(opcode_cost.opcode_i64load32u), + Operator::I64Load8S { .. } => Cost::Base(opcode_cost.opcode_i64load8s), + Operator::I64Load8U { .. } => Cost::Base(opcode_cost.opcode_i64load8u), + Operator::I64LtS { .. } => Cost::Base(opcode_cost.opcode_i64lts), + Operator::I64LtU { .. } => Cost::Base(opcode_cost.opcode_i64ltu), + Operator::I64Mul { .. } => Cost::Base(opcode_cost.opcode_i64mul), + Operator::I64Ne { .. } => Cost::Base(opcode_cost.opcode_i64ne), + Operator::I64Or { .. } => Cost::Base(opcode_cost.opcode_i64or), + Operator::I64Popcnt { .. } => Cost::Base(opcode_cost.opcode_i64popcnt), + Operator::I64RemS { .. } => Cost::Base(opcode_cost.opcode_i64rems), + Operator::I64RemU { .. } => Cost::Base(opcode_cost.opcode_i64remu), + Operator::I64Rotl { .. } => Cost::Base(opcode_cost.opcode_i64rotl), + Operator::I64Rotr { .. } => Cost::Base(opcode_cost.opcode_i64rotr), + Operator::I64Shl { .. } => Cost::Base(opcode_cost.opcode_i64shl), + Operator::I64ShrS { .. } => Cost::Base(opcode_cost.opcode_i64shrs), + Operator::I64ShrU { .. } => Cost::Base(opcode_cost.opcode_i64shru), + Operator::I64Store { .. } => Cost::Base(opcode_cost.opcode_i64store), + Operator::I64Store16 { .. } => Cost::Base(opcode_cost.opcode_i64store16), + Operator::I64Store32 { .. } => Cost::Base(opcode_cost.opcode_i64store32), + Operator::I64Store8 { .. } => Cost::Base(opcode_cost.opcode_i64store8), + Operator::I64Sub { .. } => Cost::Base(opcode_cost.opcode_i64sub), + Operator::I64Xor { .. } => Cost::Base(opcode_cost.opcode_i64xor), + Operator::If { .. } => Cost::Base(opcode_cost.opcode_if), + Operator::LocalGet { .. } => Cost::Base(opcode_cost.opcode_localget), + Operator::LocalSet { .. } => Cost::Base(opcode_cost.opcode_localset), + Operator::LocalTee { .. } => Cost::Base(opcode_cost.opcode_localtee), + Operator::Loop { .. } => Cost::Base(opcode_cost.opcode_loop), + Operator::MemoryGrow { .. } => Cost::Base(opcode_cost.opcode_memorygrow), + Operator::MemorySize { .. } => Cost::Base(opcode_cost.opcode_memorysize), + Operator::Nop { .. } => Cost::Base(opcode_cost.opcode_nop), + Operator::RefFunc { .. } => Cost::Base(opcode_cost.opcode_reffunc), + Operator::RefIsNull { .. } => Cost::Base(opcode_cost.opcode_refisnull), + Operator::RefNull { .. } => Cost::Base(opcode_cost.opcode_refnull), + Operator::Rethrow { .. } => Cost::Base(opcode_cost.opcode_rethrow), + Operator::Return { .. } => Cost::Base(opcode_cost.opcode_return), + Operator::ReturnCall { .. } => Cost::Base(opcode_cost.opcode_returncall), + Operator::ReturnCallIndirect { .. } => Cost::Base(opcode_cost.opcode_returncallindirect), + Operator::Select { .. } => Cost::Base(opcode_cost.opcode_select), + Operator::TableGet { .. } => Cost::Base(opcode_cost.opcode_tableget), + Operator::TableGrow { .. } => Cost::Base(opcode_cost.opcode_tablegrow), + Operator::TableInit { .. } => Cost::Base(opcode_cost.opcode_tableinit), + Operator::TableSet { .. } => Cost::Base(opcode_cost.opcode_tableset), + Operator::TableSize { .. } => Cost::Base(opcode_cost.opcode_tablesize), + Operator::Throw { .. } => Cost::Base(opcode_cost.opcode_throw), + Operator::Try { .. } => Cost::Base(opcode_cost.opcode_try), + Operator::TypedSelect { .. } => Cost::Base(opcode_cost.opcode_typedselect), + Operator::Unreachable { .. } => Cost::Base(opcode_cost.opcode_unreachable), + Operator::MemoryCopy { .. } => Cost::BulkMemory { base: opcode_cost.opcode_memorycopy, per_byte: opcode_cost.opcode_memorycopyperbyte }, + Operator::MemoryFill { .. } => Cost::BulkMemory { base: opcode_cost.opcode_memoryfill, per_byte: opcode_cost.opcode_memoryfillperbyte }, + _ => Cost::Illegal, } } diff --git a/vm-executor-experimental/src/middlewares/we_opcode_cost_type.rs b/vm-executor-experimental/src/middlewares/we_opcode_cost_type.rs new file mode 100644 index 0000000..124c276 --- /dev/null +++ b/vm-executor-experimental/src/middlewares/we_opcode_cost_type.rs @@ -0,0 +1,20 @@ +/// What executing one WASM operator costs. +/// +/// Not to be confused with `OpcodeCost`, which is the full cost table, as configured by the +/// gas schedule. This is the cost of one occurrence of one operator. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Cost { + /// The operator is not allowed by the configured opcode version, so it has no cost. + /// + /// Modules that contain it are rejected at compile time. + Illegal, + + /// The operator is charged once, no matter what its operands are. + Base(u32), + + /// A bulk memory operator (`memory.copy`, `memory.fill`), charged once for the operation + /// itself, plus once for every byte it copies or fills. + /// + /// The base cost is what keeps processing zero bytes from being free. + BulkMemory { base: u32, per_byte: u32 }, +} diff --git a/vm-executor-wasmer/src/lib.rs b/vm-executor-wasmer/src/lib.rs index 187fe73..3a8b7cf 100644 --- a/vm-executor-wasmer/src/lib.rs +++ b/vm-executor-wasmer/src/lib.rs @@ -7,6 +7,7 @@ mod wasmer_instance; mod wasmer_metering; mod wasmer_opcode_control; mod wasmer_opcode_cost; +mod wasmer_opcode_cost_type; mod wasmer_opcode_trace; mod wasmer_protected_globals; mod wasmer_service; @@ -15,6 +16,7 @@ mod wasmer_vm_hooks; pub use wasmer_executor::*; pub use wasmer_instance::*; pub use wasmer_opcode_cost::*; +pub use wasmer_opcode_cost_type::Cost; pub use wasmer_service::*; pub use multiversx_chain_vm_executor as executor_interface; diff --git a/vm-executor-wasmer/src/wasmer_helpers.rs b/vm-executor-wasmer/src/wasmer_helpers.rs index 71032ce..861b8b4 100644 --- a/vm-executor-wasmer/src/wasmer_helpers.rs +++ b/vm-executor-wasmer/src/wasmer_helpers.rs @@ -116,14 +116,3 @@ pub(crate) fn is_control_flow_operator(operator: &Operator) -> bool { | Operator::Return ) } - -/// Returns `true` for the bulk-memory operators supported by this helper. -/// -/// These are the memory-copy and memory-fill instructions that need explicit -/// validation or handling in Wasmer middleware. -pub(crate) fn is_supported_bulk_memory_operator(operator: &Operator) -> bool { - matches!( - operator, - Operator::MemoryCopy { .. } | Operator::MemoryFill { .. } - ) -} diff --git a/vm-executor-wasmer/src/wasmer_metering.rs b/vm-executor-wasmer/src/wasmer_metering.rs index 84b9535..2621b75 100644 --- a/vm-executor-wasmer/src/wasmer_metering.rs +++ b/vm-executor-wasmer/src/wasmer_metering.rs @@ -3,8 +3,9 @@ use crate::get_opcode_cost; use crate::wasmer_breakpoints::{BREAKPOINT_VALUE_OUT_OF_GAS, Breakpoints}; use crate::wasmer_helpers::{ MiddlewareWithProtectedGlobals, create_global_index, get_global_value_u64, - is_control_flow_operator, is_supported_bulk_memory_operator, set_global_value_u64, + is_control_flow_operator, set_global_value_u64, }; +use crate::wasmer_opcode_cost_type::Cost; use loupe::{MemoryUsage, MemoryUsageTracker}; use std::mem; use std::sync::{Arc, Mutex}; @@ -179,6 +180,9 @@ impl FunctionMetering { /// using `size` as it appears on the stack (the raw, attacker-controlled operand), before /// the real bulk-memory instruction validates it against the actual memory bounds. /// + /// This only covers the cost of the bytes. The flat cost of the instruction itself goes + /// through the regular accumulator, so that a zero-size copy or fill is never free. + /// /// The multiplication is plain wrapping `i64` arithmetic (wasm has no trapping or /// saturating integer multiply, and Wasmer doesn't offer one either), so it can in theory /// wrap around for a large enough `size`. This is not exploitable under the current setup: @@ -241,20 +245,28 @@ impl FunctionMiddleware for FunctionMetering { // Get the cost of the current operator, and add it to the accumulator. // This needs to be done before the metering logic, to prevent operators like `Call` from escaping metering in some // corner cases. - let option = get_opcode_cost(&operator, &self.opcode_config.lock().unwrap()); - match option { - Some(cost) if is_supported_bulk_memory_operator(&operator) => { - self.inject_bulk_memory_cost(state, cost); - // immediately insert out of gas check as this operation might be expensive - self.inject_out_of_gas_check(state); - } - Some(cost) => self.accumulated_cost += cost as u64, - None => { + let op_exec_cost = get_opcode_cost(&operator, &self.opcode_config.lock().unwrap()); + match op_exec_cost { + Cost::Illegal => { return Err(MiddlewareError::new( "metering_middleware", format!("Unsupported operator: {operator:?}"), )); } + Cost::Base(base) => self.accumulated_cost += base as u64, + Cost::BulkMemory { base, per_byte } => { + self.accumulated_cost += base as u64; + + // flush what accumulated so far, including the base cost of this operator, + // so that the out of gas check below takes all of it into account + self.inject_points_used_increment(state); + self.accumulated_cost = 0; + + self.inject_bulk_memory_cost(state, per_byte); + + // immediately insert out of gas check as this operation might be expensive + self.inject_out_of_gas_check(state); + } } if is_control_flow_operator(&operator) { diff --git a/vm-executor-wasmer/src/wasmer_opcode_cost.rs b/vm-executor-wasmer/src/wasmer_opcode_cost.rs index 3b005c7..9829887 100644 --- a/vm-executor-wasmer/src/wasmer_opcode_cost.rs +++ b/vm-executor-wasmer/src/wasmer_opcode_cost.rs @@ -4,279 +4,282 @@ // !!!!!!!!!!!!!!!!!!!!!! AUTO-GENERATED FILE !!!!!!!!!!!!!!!!!!!!!! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +use crate::Cost; use crate::executor_interface::{OpcodeConfig, OpcodeCost, OpcodeVersion}; use wasmer::wasmparser::Operator; -pub fn get_opcode_cost(op: &Operator, opcode_config: &OpcodeConfig) -> Option { +pub fn get_opcode_cost(op: &Operator, opcode_config: &OpcodeConfig) -> Cost { match opcode_config.opcode_version { OpcodeVersion::V1 => get_opcode_cost_v1(op, &opcode_config.opcode_cost), OpcodeVersion::V2 => get_opcode_cost_v2(op, &opcode_config.opcode_cost), } } -fn get_opcode_cost_v1(op: &Operator, opcode_cost: &OpcodeCost) -> Option { +#[rustfmt::skip] +fn get_opcode_cost_v1(op: &Operator, opcode_cost: &OpcodeCost) -> Cost { match op { - Operator::Block { .. } => Some(opcode_cost.opcode_block), - Operator::Br { .. } => Some(opcode_cost.opcode_br), - Operator::BrIf { .. } => Some(opcode_cost.opcode_brif), - Operator::BrTable { .. } => Some(opcode_cost.opcode_brtable), - Operator::Call { .. } => Some(opcode_cost.opcode_call), - Operator::CallIndirect { .. } => Some(opcode_cost.opcode_callindirect), - Operator::Catch { .. } => Some(opcode_cost.opcode_catch), - Operator::CatchAll { .. } => Some(opcode_cost.opcode_catchall), - Operator::Delegate { .. } => Some(opcode_cost.opcode_delegate), - Operator::Drop { .. } => Some(opcode_cost.opcode_drop), - Operator::Else { .. } => Some(opcode_cost.opcode_else), - Operator::End { .. } => Some(opcode_cost.opcode_end), - Operator::GlobalGet { .. } => Some(opcode_cost.opcode_globalget), - Operator::GlobalSet { .. } => Some(opcode_cost.opcode_globalset), - Operator::I32Add { .. } => Some(opcode_cost.opcode_i32add), - Operator::I32And { .. } => Some(opcode_cost.opcode_i32and), - Operator::I32Clz { .. } => Some(opcode_cost.opcode_i32clz), - Operator::I32Const { .. } => Some(opcode_cost.opcode_i32const), - Operator::I32Ctz { .. } => Some(opcode_cost.opcode_i32ctz), - Operator::I32DivS { .. } => Some(opcode_cost.opcode_i32divs), - Operator::I32DivU { .. } => Some(opcode_cost.opcode_i32divu), - Operator::I32Eq { .. } => Some(opcode_cost.opcode_i32eq), - Operator::I32Eqz { .. } => Some(opcode_cost.opcode_i32eqz), - Operator::I32Extend16S { .. } => Some(opcode_cost.opcode_i32extend16s), - Operator::I32Extend8S { .. } => Some(opcode_cost.opcode_i32extend8s), - Operator::I32GeS { .. } => Some(opcode_cost.opcode_i32ges), - Operator::I32GeU { .. } => Some(opcode_cost.opcode_i32geu), - Operator::I32GtS { .. } => Some(opcode_cost.opcode_i32gts), - Operator::I32GtU { .. } => Some(opcode_cost.opcode_i32gtu), - Operator::I32LeS { .. } => Some(opcode_cost.opcode_i32les), - Operator::I32LeU { .. } => Some(opcode_cost.opcode_i32leu), - Operator::I32Load { .. } => Some(opcode_cost.opcode_i32load), - Operator::I32Load16S { .. } => Some(opcode_cost.opcode_i32load16s), - Operator::I32Load16U { .. } => Some(opcode_cost.opcode_i32load16u), - Operator::I32Load8S { .. } => Some(opcode_cost.opcode_i32load8s), - Operator::I32Load8U { .. } => Some(opcode_cost.opcode_i32load8u), - Operator::I32LtS { .. } => Some(opcode_cost.opcode_i32lts), - Operator::I32LtU { .. } => Some(opcode_cost.opcode_i32ltu), - Operator::I32Mul { .. } => Some(opcode_cost.opcode_i32mul), - Operator::I32Ne { .. } => Some(opcode_cost.opcode_i32ne), - Operator::I32Or { .. } => Some(opcode_cost.opcode_i32or), - Operator::I32Popcnt { .. } => Some(opcode_cost.opcode_i32popcnt), - Operator::I32RemS { .. } => Some(opcode_cost.opcode_i32rems), - Operator::I32RemU { .. } => Some(opcode_cost.opcode_i32remu), - Operator::I32Rotl { .. } => Some(opcode_cost.opcode_i32rotl), - Operator::I32Rotr { .. } => Some(opcode_cost.opcode_i32rotr), - Operator::I32Shl { .. } => Some(opcode_cost.opcode_i32shl), - Operator::I32ShrS { .. } => Some(opcode_cost.opcode_i32shrs), - Operator::I32ShrU { .. } => Some(opcode_cost.opcode_i32shru), - Operator::I32Store { .. } => Some(opcode_cost.opcode_i32store), - Operator::I32Store16 { .. } => Some(opcode_cost.opcode_i32store16), - Operator::I32Store8 { .. } => Some(opcode_cost.opcode_i32store8), - Operator::I32Sub { .. } => Some(opcode_cost.opcode_i32sub), - Operator::I32WrapI64 { .. } => Some(opcode_cost.opcode_i32wrapi64), - Operator::I32Xor { .. } => Some(opcode_cost.opcode_i32xor), - Operator::I64Add { .. } => Some(opcode_cost.opcode_i64add), - Operator::I64And { .. } => Some(opcode_cost.opcode_i64and), - Operator::I64Clz { .. } => Some(opcode_cost.opcode_i64clz), - Operator::I64Const { .. } => Some(opcode_cost.opcode_i64const), - Operator::I64Ctz { .. } => Some(opcode_cost.opcode_i64ctz), - Operator::I64DivS { .. } => Some(opcode_cost.opcode_i64divs), - Operator::I64DivU { .. } => Some(opcode_cost.opcode_i64divu), - Operator::I64Eq { .. } => Some(opcode_cost.opcode_i64eq), - Operator::I64Eqz { .. } => Some(opcode_cost.opcode_i64eqz), - Operator::I64Extend16S { .. } => Some(opcode_cost.opcode_i64extend16s), - Operator::I64Extend32S { .. } => Some(opcode_cost.opcode_i64extend32s), - Operator::I64Extend8S { .. } => Some(opcode_cost.opcode_i64extend8s), - Operator::I64ExtendI32S { .. } => Some(opcode_cost.opcode_i64extendi32s), - Operator::I64ExtendI32U { .. } => Some(opcode_cost.opcode_i64extendi32u), - Operator::I64GeS { .. } => Some(opcode_cost.opcode_i64ges), - Operator::I64GeU { .. } => Some(opcode_cost.opcode_i64geu), - Operator::I64GtS { .. } => Some(opcode_cost.opcode_i64gts), - Operator::I64GtU { .. } => Some(opcode_cost.opcode_i64gtu), - Operator::I64LeS { .. } => Some(opcode_cost.opcode_i64les), - Operator::I64LeU { .. } => Some(opcode_cost.opcode_i64leu), - Operator::I64Load { .. } => Some(opcode_cost.opcode_i64load), - Operator::I64Load16S { .. } => Some(opcode_cost.opcode_i64load16s), - Operator::I64Load16U { .. } => Some(opcode_cost.opcode_i64load16u), - Operator::I64Load32S { .. } => Some(opcode_cost.opcode_i64load32s), - Operator::I64Load32U { .. } => Some(opcode_cost.opcode_i64load32u), - Operator::I64Load8S { .. } => Some(opcode_cost.opcode_i64load8s), - Operator::I64Load8U { .. } => Some(opcode_cost.opcode_i64load8u), - Operator::I64LtS { .. } => Some(opcode_cost.opcode_i64lts), - Operator::I64LtU { .. } => Some(opcode_cost.opcode_i64ltu), - Operator::I64Mul { .. } => Some(opcode_cost.opcode_i64mul), - Operator::I64Ne { .. } => Some(opcode_cost.opcode_i64ne), - Operator::I64Or { .. } => Some(opcode_cost.opcode_i64or), - Operator::I64Popcnt { .. } => Some(opcode_cost.opcode_i64popcnt), - Operator::I64RemS { .. } => Some(opcode_cost.opcode_i64rems), - Operator::I64RemU { .. } => Some(opcode_cost.opcode_i64remu), - Operator::I64Rotl { .. } => Some(opcode_cost.opcode_i64rotl), - Operator::I64Rotr { .. } => Some(opcode_cost.opcode_i64rotr), - Operator::I64Shl { .. } => Some(opcode_cost.opcode_i64shl), - Operator::I64ShrS { .. } => Some(opcode_cost.opcode_i64shrs), - Operator::I64ShrU { .. } => Some(opcode_cost.opcode_i64shru), - Operator::I64Store { .. } => Some(opcode_cost.opcode_i64store), - Operator::I64Store16 { .. } => Some(opcode_cost.opcode_i64store16), - Operator::I64Store32 { .. } => Some(opcode_cost.opcode_i64store32), - Operator::I64Store8 { .. } => Some(opcode_cost.opcode_i64store8), - Operator::I64Sub { .. } => Some(opcode_cost.opcode_i64sub), - Operator::I64Xor { .. } => Some(opcode_cost.opcode_i64xor), - Operator::If { .. } => Some(opcode_cost.opcode_if), - Operator::LocalGet { .. } => Some(opcode_cost.opcode_localget), - Operator::LocalSet { .. } => Some(opcode_cost.opcode_localset), - Operator::LocalTee { .. } => Some(opcode_cost.opcode_localtee), - Operator::Loop { .. } => Some(opcode_cost.opcode_loop), - Operator::MemoryGrow { .. } => Some(opcode_cost.opcode_memorygrow), - Operator::MemorySize { .. } => Some(opcode_cost.opcode_memorysize), - Operator::Nop { .. } => Some(opcode_cost.opcode_nop), - Operator::RefFunc { .. } => Some(opcode_cost.opcode_reffunc), - Operator::RefIsNull { .. } => Some(opcode_cost.opcode_refisnull), - Operator::RefNull { .. } => Some(opcode_cost.opcode_refnull), - Operator::Rethrow { .. } => Some(opcode_cost.opcode_rethrow), - Operator::Return { .. } => Some(opcode_cost.opcode_return), - Operator::ReturnCall { .. } => Some(opcode_cost.opcode_returncall), - Operator::ReturnCallIndirect { .. } => Some(opcode_cost.opcode_returncallindirect), - Operator::Select { .. } => Some(opcode_cost.opcode_select), - Operator::TableGet { .. } => Some(opcode_cost.opcode_tableget), - Operator::TableGrow { .. } => Some(opcode_cost.opcode_tablegrow), - Operator::TableInit { .. } => Some(opcode_cost.opcode_tableinit), - Operator::TableSet { .. } => Some(opcode_cost.opcode_tableset), - Operator::TableSize { .. } => Some(opcode_cost.opcode_tablesize), - Operator::Throw { .. } => Some(opcode_cost.opcode_throw), - Operator::Try { .. } => Some(opcode_cost.opcode_try), - Operator::TypedSelect { .. } => Some(opcode_cost.opcode_typedselect), - Operator::Unreachable { .. } => Some(opcode_cost.opcode_unreachable), - Operator::Unwind { .. } => Some(opcode_cost.opcode_unwind), - _ => None, + Operator::Block { .. } => Cost::Base(opcode_cost.opcode_block), + Operator::Br { .. } => Cost::Base(opcode_cost.opcode_br), + Operator::BrIf { .. } => Cost::Base(opcode_cost.opcode_brif), + Operator::BrTable { .. } => Cost::Base(opcode_cost.opcode_brtable), + Operator::Call { .. } => Cost::Base(opcode_cost.opcode_call), + Operator::CallIndirect { .. } => Cost::Base(opcode_cost.opcode_callindirect), + Operator::Catch { .. } => Cost::Base(opcode_cost.opcode_catch), + Operator::CatchAll { .. } => Cost::Base(opcode_cost.opcode_catchall), + Operator::Delegate { .. } => Cost::Base(opcode_cost.opcode_delegate), + Operator::Drop { .. } => Cost::Base(opcode_cost.opcode_drop), + Operator::Else { .. } => Cost::Base(opcode_cost.opcode_else), + Operator::End { .. } => Cost::Base(opcode_cost.opcode_end), + Operator::GlobalGet { .. } => Cost::Base(opcode_cost.opcode_globalget), + Operator::GlobalSet { .. } => Cost::Base(opcode_cost.opcode_globalset), + Operator::I32Add { .. } => Cost::Base(opcode_cost.opcode_i32add), + Operator::I32And { .. } => Cost::Base(opcode_cost.opcode_i32and), + Operator::I32Clz { .. } => Cost::Base(opcode_cost.opcode_i32clz), + Operator::I32Const { .. } => Cost::Base(opcode_cost.opcode_i32const), + Operator::I32Ctz { .. } => Cost::Base(opcode_cost.opcode_i32ctz), + Operator::I32DivS { .. } => Cost::Base(opcode_cost.opcode_i32divs), + Operator::I32DivU { .. } => Cost::Base(opcode_cost.opcode_i32divu), + Operator::I32Eq { .. } => Cost::Base(opcode_cost.opcode_i32eq), + Operator::I32Eqz { .. } => Cost::Base(opcode_cost.opcode_i32eqz), + Operator::I32Extend16S { .. } => Cost::Base(opcode_cost.opcode_i32extend16s), + Operator::I32Extend8S { .. } => Cost::Base(opcode_cost.opcode_i32extend8s), + Operator::I32GeS { .. } => Cost::Base(opcode_cost.opcode_i32ges), + Operator::I32GeU { .. } => Cost::Base(opcode_cost.opcode_i32geu), + Operator::I32GtS { .. } => Cost::Base(opcode_cost.opcode_i32gts), + Operator::I32GtU { .. } => Cost::Base(opcode_cost.opcode_i32gtu), + Operator::I32LeS { .. } => Cost::Base(opcode_cost.opcode_i32les), + Operator::I32LeU { .. } => Cost::Base(opcode_cost.opcode_i32leu), + Operator::I32Load { .. } => Cost::Base(opcode_cost.opcode_i32load), + Operator::I32Load16S { .. } => Cost::Base(opcode_cost.opcode_i32load16s), + Operator::I32Load16U { .. } => Cost::Base(opcode_cost.opcode_i32load16u), + Operator::I32Load8S { .. } => Cost::Base(opcode_cost.opcode_i32load8s), + Operator::I32Load8U { .. } => Cost::Base(opcode_cost.opcode_i32load8u), + Operator::I32LtS { .. } => Cost::Base(opcode_cost.opcode_i32lts), + Operator::I32LtU { .. } => Cost::Base(opcode_cost.opcode_i32ltu), + Operator::I32Mul { .. } => Cost::Base(opcode_cost.opcode_i32mul), + Operator::I32Ne { .. } => Cost::Base(opcode_cost.opcode_i32ne), + Operator::I32Or { .. } => Cost::Base(opcode_cost.opcode_i32or), + Operator::I32Popcnt { .. } => Cost::Base(opcode_cost.opcode_i32popcnt), + Operator::I32RemS { .. } => Cost::Base(opcode_cost.opcode_i32rems), + Operator::I32RemU { .. } => Cost::Base(opcode_cost.opcode_i32remu), + Operator::I32Rotl { .. } => Cost::Base(opcode_cost.opcode_i32rotl), + Operator::I32Rotr { .. } => Cost::Base(opcode_cost.opcode_i32rotr), + Operator::I32Shl { .. } => Cost::Base(opcode_cost.opcode_i32shl), + Operator::I32ShrS { .. } => Cost::Base(opcode_cost.opcode_i32shrs), + Operator::I32ShrU { .. } => Cost::Base(opcode_cost.opcode_i32shru), + Operator::I32Store { .. } => Cost::Base(opcode_cost.opcode_i32store), + Operator::I32Store16 { .. } => Cost::Base(opcode_cost.opcode_i32store16), + Operator::I32Store8 { .. } => Cost::Base(opcode_cost.opcode_i32store8), + Operator::I32Sub { .. } => Cost::Base(opcode_cost.opcode_i32sub), + Operator::I32WrapI64 { .. } => Cost::Base(opcode_cost.opcode_i32wrapi64), + Operator::I32Xor { .. } => Cost::Base(opcode_cost.opcode_i32xor), + Operator::I64Add { .. } => Cost::Base(opcode_cost.opcode_i64add), + Operator::I64And { .. } => Cost::Base(opcode_cost.opcode_i64and), + Operator::I64Clz { .. } => Cost::Base(opcode_cost.opcode_i64clz), + Operator::I64Const { .. } => Cost::Base(opcode_cost.opcode_i64const), + Operator::I64Ctz { .. } => Cost::Base(opcode_cost.opcode_i64ctz), + Operator::I64DivS { .. } => Cost::Base(opcode_cost.opcode_i64divs), + Operator::I64DivU { .. } => Cost::Base(opcode_cost.opcode_i64divu), + Operator::I64Eq { .. } => Cost::Base(opcode_cost.opcode_i64eq), + Operator::I64Eqz { .. } => Cost::Base(opcode_cost.opcode_i64eqz), + Operator::I64Extend16S { .. } => Cost::Base(opcode_cost.opcode_i64extend16s), + Operator::I64Extend32S { .. } => Cost::Base(opcode_cost.opcode_i64extend32s), + Operator::I64Extend8S { .. } => Cost::Base(opcode_cost.opcode_i64extend8s), + Operator::I64ExtendI32S { .. } => Cost::Base(opcode_cost.opcode_i64extendi32s), + Operator::I64ExtendI32U { .. } => Cost::Base(opcode_cost.opcode_i64extendi32u), + Operator::I64GeS { .. } => Cost::Base(opcode_cost.opcode_i64ges), + Operator::I64GeU { .. } => Cost::Base(opcode_cost.opcode_i64geu), + Operator::I64GtS { .. } => Cost::Base(opcode_cost.opcode_i64gts), + Operator::I64GtU { .. } => Cost::Base(opcode_cost.opcode_i64gtu), + Operator::I64LeS { .. } => Cost::Base(opcode_cost.opcode_i64les), + Operator::I64LeU { .. } => Cost::Base(opcode_cost.opcode_i64leu), + Operator::I64Load { .. } => Cost::Base(opcode_cost.opcode_i64load), + Operator::I64Load16S { .. } => Cost::Base(opcode_cost.opcode_i64load16s), + Operator::I64Load16U { .. } => Cost::Base(opcode_cost.opcode_i64load16u), + Operator::I64Load32S { .. } => Cost::Base(opcode_cost.opcode_i64load32s), + Operator::I64Load32U { .. } => Cost::Base(opcode_cost.opcode_i64load32u), + Operator::I64Load8S { .. } => Cost::Base(opcode_cost.opcode_i64load8s), + Operator::I64Load8U { .. } => Cost::Base(opcode_cost.opcode_i64load8u), + Operator::I64LtS { .. } => Cost::Base(opcode_cost.opcode_i64lts), + Operator::I64LtU { .. } => Cost::Base(opcode_cost.opcode_i64ltu), + Operator::I64Mul { .. } => Cost::Base(opcode_cost.opcode_i64mul), + Operator::I64Ne { .. } => Cost::Base(opcode_cost.opcode_i64ne), + Operator::I64Or { .. } => Cost::Base(opcode_cost.opcode_i64or), + Operator::I64Popcnt { .. } => Cost::Base(opcode_cost.opcode_i64popcnt), + Operator::I64RemS { .. } => Cost::Base(opcode_cost.opcode_i64rems), + Operator::I64RemU { .. } => Cost::Base(opcode_cost.opcode_i64remu), + Operator::I64Rotl { .. } => Cost::Base(opcode_cost.opcode_i64rotl), + Operator::I64Rotr { .. } => Cost::Base(opcode_cost.opcode_i64rotr), + Operator::I64Shl { .. } => Cost::Base(opcode_cost.opcode_i64shl), + Operator::I64ShrS { .. } => Cost::Base(opcode_cost.opcode_i64shrs), + Operator::I64ShrU { .. } => Cost::Base(opcode_cost.opcode_i64shru), + Operator::I64Store { .. } => Cost::Base(opcode_cost.opcode_i64store), + Operator::I64Store16 { .. } => Cost::Base(opcode_cost.opcode_i64store16), + Operator::I64Store32 { .. } => Cost::Base(opcode_cost.opcode_i64store32), + Operator::I64Store8 { .. } => Cost::Base(opcode_cost.opcode_i64store8), + Operator::I64Sub { .. } => Cost::Base(opcode_cost.opcode_i64sub), + Operator::I64Xor { .. } => Cost::Base(opcode_cost.opcode_i64xor), + Operator::If { .. } => Cost::Base(opcode_cost.opcode_if), + Operator::LocalGet { .. } => Cost::Base(opcode_cost.opcode_localget), + Operator::LocalSet { .. } => Cost::Base(opcode_cost.opcode_localset), + Operator::LocalTee { .. } => Cost::Base(opcode_cost.opcode_localtee), + Operator::Loop { .. } => Cost::Base(opcode_cost.opcode_loop), + Operator::MemoryGrow { .. } => Cost::Base(opcode_cost.opcode_memorygrow), + Operator::MemorySize { .. } => Cost::Base(opcode_cost.opcode_memorysize), + Operator::Nop { .. } => Cost::Base(opcode_cost.opcode_nop), + Operator::RefFunc { .. } => Cost::Base(opcode_cost.opcode_reffunc), + Operator::RefIsNull { .. } => Cost::Base(opcode_cost.opcode_refisnull), + Operator::RefNull { .. } => Cost::Base(opcode_cost.opcode_refnull), + Operator::Rethrow { .. } => Cost::Base(opcode_cost.opcode_rethrow), + Operator::Return { .. } => Cost::Base(opcode_cost.opcode_return), + Operator::ReturnCall { .. } => Cost::Base(opcode_cost.opcode_returncall), + Operator::ReturnCallIndirect { .. } => Cost::Base(opcode_cost.opcode_returncallindirect), + Operator::Select { .. } => Cost::Base(opcode_cost.opcode_select), + Operator::TableGet { .. } => Cost::Base(opcode_cost.opcode_tableget), + Operator::TableGrow { .. } => Cost::Base(opcode_cost.opcode_tablegrow), + Operator::TableInit { .. } => Cost::Base(opcode_cost.opcode_tableinit), + Operator::TableSet { .. } => Cost::Base(opcode_cost.opcode_tableset), + Operator::TableSize { .. } => Cost::Base(opcode_cost.opcode_tablesize), + Operator::Throw { .. } => Cost::Base(opcode_cost.opcode_throw), + Operator::Try { .. } => Cost::Base(opcode_cost.opcode_try), + Operator::TypedSelect { .. } => Cost::Base(opcode_cost.opcode_typedselect), + Operator::Unreachable { .. } => Cost::Base(opcode_cost.opcode_unreachable), + Operator::Unwind { .. } => Cost::Base(opcode_cost.opcode_unwind), + _ => Cost::Illegal, } } -fn get_opcode_cost_v2(op: &Operator, opcode_cost: &OpcodeCost) -> Option { +#[rustfmt::skip] +fn get_opcode_cost_v2(op: &Operator, opcode_cost: &OpcodeCost) -> Cost { match op { - Operator::Block { .. } => Some(opcode_cost.opcode_block), - Operator::Br { .. } => Some(opcode_cost.opcode_br), - Operator::BrIf { .. } => Some(opcode_cost.opcode_brif), - Operator::BrTable { .. } => Some(opcode_cost.opcode_brtable), - Operator::Call { .. } => Some(opcode_cost.opcode_call), - Operator::CallIndirect { .. } => Some(opcode_cost.opcode_callindirect), - Operator::Catch { .. } => Some(opcode_cost.opcode_catch), - Operator::CatchAll { .. } => Some(opcode_cost.opcode_catchall), - Operator::Delegate { .. } => Some(opcode_cost.opcode_delegate), - Operator::Drop { .. } => Some(opcode_cost.opcode_drop), - Operator::Else { .. } => Some(opcode_cost.opcode_else), - Operator::End { .. } => Some(opcode_cost.opcode_end), - Operator::GlobalGet { .. } => Some(opcode_cost.opcode_globalget), - Operator::GlobalSet { .. } => Some(opcode_cost.opcode_globalset), - Operator::I32Add { .. } => Some(opcode_cost.opcode_i32add), - Operator::I32And { .. } => Some(opcode_cost.opcode_i32and), - Operator::I32Clz { .. } => Some(opcode_cost.opcode_i32clz), - Operator::I32Const { .. } => Some(opcode_cost.opcode_i32const), - Operator::I32Ctz { .. } => Some(opcode_cost.opcode_i32ctz), - Operator::I32DivS { .. } => Some(opcode_cost.opcode_i32divs), - Operator::I32DivU { .. } => Some(opcode_cost.opcode_i32divu), - Operator::I32Eq { .. } => Some(opcode_cost.opcode_i32eq), - Operator::I32Eqz { .. } => Some(opcode_cost.opcode_i32eqz), - Operator::I32Extend16S { .. } => Some(opcode_cost.opcode_i32extend16s), - Operator::I32Extend8S { .. } => Some(opcode_cost.opcode_i32extend8s), - Operator::I32GeS { .. } => Some(opcode_cost.opcode_i32ges), - Operator::I32GeU { .. } => Some(opcode_cost.opcode_i32geu), - Operator::I32GtS { .. } => Some(opcode_cost.opcode_i32gts), - Operator::I32GtU { .. } => Some(opcode_cost.opcode_i32gtu), - Operator::I32LeS { .. } => Some(opcode_cost.opcode_i32les), - Operator::I32LeU { .. } => Some(opcode_cost.opcode_i32leu), - Operator::I32Load { .. } => Some(opcode_cost.opcode_i32load), - Operator::I32Load16S { .. } => Some(opcode_cost.opcode_i32load16s), - Operator::I32Load16U { .. } => Some(opcode_cost.opcode_i32load16u), - Operator::I32Load8S { .. } => Some(opcode_cost.opcode_i32load8s), - Operator::I32Load8U { .. } => Some(opcode_cost.opcode_i32load8u), - Operator::I32LtS { .. } => Some(opcode_cost.opcode_i32lts), - Operator::I32LtU { .. } => Some(opcode_cost.opcode_i32ltu), - Operator::I32Mul { .. } => Some(opcode_cost.opcode_i32mul), - Operator::I32Ne { .. } => Some(opcode_cost.opcode_i32ne), - Operator::I32Or { .. } => Some(opcode_cost.opcode_i32or), - Operator::I32Popcnt { .. } => Some(opcode_cost.opcode_i32popcnt), - Operator::I32RemS { .. } => Some(opcode_cost.opcode_i32rems), - Operator::I32RemU { .. } => Some(opcode_cost.opcode_i32remu), - Operator::I32Rotl { .. } => Some(opcode_cost.opcode_i32rotl), - Operator::I32Rotr { .. } => Some(opcode_cost.opcode_i32rotr), - Operator::I32Shl { .. } => Some(opcode_cost.opcode_i32shl), - Operator::I32ShrS { .. } => Some(opcode_cost.opcode_i32shrs), - Operator::I32ShrU { .. } => Some(opcode_cost.opcode_i32shru), - Operator::I32Store { .. } => Some(opcode_cost.opcode_i32store), - Operator::I32Store16 { .. } => Some(opcode_cost.opcode_i32store16), - Operator::I32Store8 { .. } => Some(opcode_cost.opcode_i32store8), - Operator::I32Sub { .. } => Some(opcode_cost.opcode_i32sub), - Operator::I32WrapI64 { .. } => Some(opcode_cost.opcode_i32wrapi64), - Operator::I32Xor { .. } => Some(opcode_cost.opcode_i32xor), - Operator::I64Add { .. } => Some(opcode_cost.opcode_i64add), - Operator::I64And { .. } => Some(opcode_cost.opcode_i64and), - Operator::I64Clz { .. } => Some(opcode_cost.opcode_i64clz), - Operator::I64Const { .. } => Some(opcode_cost.opcode_i64const), - Operator::I64Ctz { .. } => Some(opcode_cost.opcode_i64ctz), - Operator::I64DivS { .. } => Some(opcode_cost.opcode_i64divs), - Operator::I64DivU { .. } => Some(opcode_cost.opcode_i64divu), - Operator::I64Eq { .. } => Some(opcode_cost.opcode_i64eq), - Operator::I64Eqz { .. } => Some(opcode_cost.opcode_i64eqz), - Operator::I64Extend16S { .. } => Some(opcode_cost.opcode_i64extend16s), - Operator::I64Extend32S { .. } => Some(opcode_cost.opcode_i64extend32s), - Operator::I64Extend8S { .. } => Some(opcode_cost.opcode_i64extend8s), - Operator::I64ExtendI32S { .. } => Some(opcode_cost.opcode_i64extendi32s), - Operator::I64ExtendI32U { .. } => Some(opcode_cost.opcode_i64extendi32u), - Operator::I64GeS { .. } => Some(opcode_cost.opcode_i64ges), - Operator::I64GeU { .. } => Some(opcode_cost.opcode_i64geu), - Operator::I64GtS { .. } => Some(opcode_cost.opcode_i64gts), - Operator::I64GtU { .. } => Some(opcode_cost.opcode_i64gtu), - Operator::I64LeS { .. } => Some(opcode_cost.opcode_i64les), - Operator::I64LeU { .. } => Some(opcode_cost.opcode_i64leu), - Operator::I64Load { .. } => Some(opcode_cost.opcode_i64load), - Operator::I64Load16S { .. } => Some(opcode_cost.opcode_i64load16s), - Operator::I64Load16U { .. } => Some(opcode_cost.opcode_i64load16u), - Operator::I64Load32S { .. } => Some(opcode_cost.opcode_i64load32s), - Operator::I64Load32U { .. } => Some(opcode_cost.opcode_i64load32u), - Operator::I64Load8S { .. } => Some(opcode_cost.opcode_i64load8s), - Operator::I64Load8U { .. } => Some(opcode_cost.opcode_i64load8u), - Operator::I64LtS { .. } => Some(opcode_cost.opcode_i64lts), - Operator::I64LtU { .. } => Some(opcode_cost.opcode_i64ltu), - Operator::I64Mul { .. } => Some(opcode_cost.opcode_i64mul), - Operator::I64Ne { .. } => Some(opcode_cost.opcode_i64ne), - Operator::I64Or { .. } => Some(opcode_cost.opcode_i64or), - Operator::I64Popcnt { .. } => Some(opcode_cost.opcode_i64popcnt), - Operator::I64RemS { .. } => Some(opcode_cost.opcode_i64rems), - Operator::I64RemU { .. } => Some(opcode_cost.opcode_i64remu), - Operator::I64Rotl { .. } => Some(opcode_cost.opcode_i64rotl), - Operator::I64Rotr { .. } => Some(opcode_cost.opcode_i64rotr), - Operator::I64Shl { .. } => Some(opcode_cost.opcode_i64shl), - Operator::I64ShrS { .. } => Some(opcode_cost.opcode_i64shrs), - Operator::I64ShrU { .. } => Some(opcode_cost.opcode_i64shru), - Operator::I64Store { .. } => Some(opcode_cost.opcode_i64store), - Operator::I64Store16 { .. } => Some(opcode_cost.opcode_i64store16), - Operator::I64Store32 { .. } => Some(opcode_cost.opcode_i64store32), - Operator::I64Store8 { .. } => Some(opcode_cost.opcode_i64store8), - Operator::I64Sub { .. } => Some(opcode_cost.opcode_i64sub), - Operator::I64Xor { .. } => Some(opcode_cost.opcode_i64xor), - Operator::If { .. } => Some(opcode_cost.opcode_if), - Operator::LocalGet { .. } => Some(opcode_cost.opcode_localget), - Operator::LocalSet { .. } => Some(opcode_cost.opcode_localset), - Operator::LocalTee { .. } => Some(opcode_cost.opcode_localtee), - Operator::Loop { .. } => Some(opcode_cost.opcode_loop), - Operator::MemoryGrow { .. } => Some(opcode_cost.opcode_memorygrow), - Operator::MemorySize { .. } => Some(opcode_cost.opcode_memorysize), - Operator::Nop { .. } => Some(opcode_cost.opcode_nop), - Operator::RefFunc { .. } => Some(opcode_cost.opcode_reffunc), - Operator::RefIsNull { .. } => Some(opcode_cost.opcode_refisnull), - Operator::RefNull { .. } => Some(opcode_cost.opcode_refnull), - Operator::Rethrow { .. } => Some(opcode_cost.opcode_rethrow), - Operator::Return { .. } => Some(opcode_cost.opcode_return), - Operator::ReturnCall { .. } => Some(opcode_cost.opcode_returncall), - Operator::ReturnCallIndirect { .. } => Some(opcode_cost.opcode_returncallindirect), - Operator::Select { .. } => Some(opcode_cost.opcode_select), - Operator::TableGet { .. } => Some(opcode_cost.opcode_tableget), - Operator::TableGrow { .. } => Some(opcode_cost.opcode_tablegrow), - Operator::TableInit { .. } => Some(opcode_cost.opcode_tableinit), - Operator::TableSet { .. } => Some(opcode_cost.opcode_tableset), - Operator::TableSize { .. } => Some(opcode_cost.opcode_tablesize), - Operator::Throw { .. } => Some(opcode_cost.opcode_throw), - Operator::Try { .. } => Some(opcode_cost.opcode_try), - Operator::TypedSelect { .. } => Some(opcode_cost.opcode_typedselect), - Operator::Unreachable { .. } => Some(opcode_cost.opcode_unreachable), - Operator::MemoryCopy { .. } => Some(opcode_cost.opcode_memorycopy), - Operator::MemoryFill { .. } => Some(opcode_cost.opcode_memoryfill), - _ => None, + Operator::Block { .. } => Cost::Base(opcode_cost.opcode_block), + Operator::Br { .. } => Cost::Base(opcode_cost.opcode_br), + Operator::BrIf { .. } => Cost::Base(opcode_cost.opcode_brif), + Operator::BrTable { .. } => Cost::Base(opcode_cost.opcode_brtable), + Operator::Call { .. } => Cost::Base(opcode_cost.opcode_call), + Operator::CallIndirect { .. } => Cost::Base(opcode_cost.opcode_callindirect), + Operator::Catch { .. } => Cost::Base(opcode_cost.opcode_catch), + Operator::CatchAll { .. } => Cost::Base(opcode_cost.opcode_catchall), + Operator::Delegate { .. } => Cost::Base(opcode_cost.opcode_delegate), + Operator::Drop { .. } => Cost::Base(opcode_cost.opcode_drop), + Operator::Else { .. } => Cost::Base(opcode_cost.opcode_else), + Operator::End { .. } => Cost::Base(opcode_cost.opcode_end), + Operator::GlobalGet { .. } => Cost::Base(opcode_cost.opcode_globalget), + Operator::GlobalSet { .. } => Cost::Base(opcode_cost.opcode_globalset), + Operator::I32Add { .. } => Cost::Base(opcode_cost.opcode_i32add), + Operator::I32And { .. } => Cost::Base(opcode_cost.opcode_i32and), + Operator::I32Clz { .. } => Cost::Base(opcode_cost.opcode_i32clz), + Operator::I32Const { .. } => Cost::Base(opcode_cost.opcode_i32const), + Operator::I32Ctz { .. } => Cost::Base(opcode_cost.opcode_i32ctz), + Operator::I32DivS { .. } => Cost::Base(opcode_cost.opcode_i32divs), + Operator::I32DivU { .. } => Cost::Base(opcode_cost.opcode_i32divu), + Operator::I32Eq { .. } => Cost::Base(opcode_cost.opcode_i32eq), + Operator::I32Eqz { .. } => Cost::Base(opcode_cost.opcode_i32eqz), + Operator::I32Extend16S { .. } => Cost::Base(opcode_cost.opcode_i32extend16s), + Operator::I32Extend8S { .. } => Cost::Base(opcode_cost.opcode_i32extend8s), + Operator::I32GeS { .. } => Cost::Base(opcode_cost.opcode_i32ges), + Operator::I32GeU { .. } => Cost::Base(opcode_cost.opcode_i32geu), + Operator::I32GtS { .. } => Cost::Base(opcode_cost.opcode_i32gts), + Operator::I32GtU { .. } => Cost::Base(opcode_cost.opcode_i32gtu), + Operator::I32LeS { .. } => Cost::Base(opcode_cost.opcode_i32les), + Operator::I32LeU { .. } => Cost::Base(opcode_cost.opcode_i32leu), + Operator::I32Load { .. } => Cost::Base(opcode_cost.opcode_i32load), + Operator::I32Load16S { .. } => Cost::Base(opcode_cost.opcode_i32load16s), + Operator::I32Load16U { .. } => Cost::Base(opcode_cost.opcode_i32load16u), + Operator::I32Load8S { .. } => Cost::Base(opcode_cost.opcode_i32load8s), + Operator::I32Load8U { .. } => Cost::Base(opcode_cost.opcode_i32load8u), + Operator::I32LtS { .. } => Cost::Base(opcode_cost.opcode_i32lts), + Operator::I32LtU { .. } => Cost::Base(opcode_cost.opcode_i32ltu), + Operator::I32Mul { .. } => Cost::Base(opcode_cost.opcode_i32mul), + Operator::I32Ne { .. } => Cost::Base(opcode_cost.opcode_i32ne), + Operator::I32Or { .. } => Cost::Base(opcode_cost.opcode_i32or), + Operator::I32Popcnt { .. } => Cost::Base(opcode_cost.opcode_i32popcnt), + Operator::I32RemS { .. } => Cost::Base(opcode_cost.opcode_i32rems), + Operator::I32RemU { .. } => Cost::Base(opcode_cost.opcode_i32remu), + Operator::I32Rotl { .. } => Cost::Base(opcode_cost.opcode_i32rotl), + Operator::I32Rotr { .. } => Cost::Base(opcode_cost.opcode_i32rotr), + Operator::I32Shl { .. } => Cost::Base(opcode_cost.opcode_i32shl), + Operator::I32ShrS { .. } => Cost::Base(opcode_cost.opcode_i32shrs), + Operator::I32ShrU { .. } => Cost::Base(opcode_cost.opcode_i32shru), + Operator::I32Store { .. } => Cost::Base(opcode_cost.opcode_i32store), + Operator::I32Store16 { .. } => Cost::Base(opcode_cost.opcode_i32store16), + Operator::I32Store8 { .. } => Cost::Base(opcode_cost.opcode_i32store8), + Operator::I32Sub { .. } => Cost::Base(opcode_cost.opcode_i32sub), + Operator::I32WrapI64 { .. } => Cost::Base(opcode_cost.opcode_i32wrapi64), + Operator::I32Xor { .. } => Cost::Base(opcode_cost.opcode_i32xor), + Operator::I64Add { .. } => Cost::Base(opcode_cost.opcode_i64add), + Operator::I64And { .. } => Cost::Base(opcode_cost.opcode_i64and), + Operator::I64Clz { .. } => Cost::Base(opcode_cost.opcode_i64clz), + Operator::I64Const { .. } => Cost::Base(opcode_cost.opcode_i64const), + Operator::I64Ctz { .. } => Cost::Base(opcode_cost.opcode_i64ctz), + Operator::I64DivS { .. } => Cost::Base(opcode_cost.opcode_i64divs), + Operator::I64DivU { .. } => Cost::Base(opcode_cost.opcode_i64divu), + Operator::I64Eq { .. } => Cost::Base(opcode_cost.opcode_i64eq), + Operator::I64Eqz { .. } => Cost::Base(opcode_cost.opcode_i64eqz), + Operator::I64Extend16S { .. } => Cost::Base(opcode_cost.opcode_i64extend16s), + Operator::I64Extend32S { .. } => Cost::Base(opcode_cost.opcode_i64extend32s), + Operator::I64Extend8S { .. } => Cost::Base(opcode_cost.opcode_i64extend8s), + Operator::I64ExtendI32S { .. } => Cost::Base(opcode_cost.opcode_i64extendi32s), + Operator::I64ExtendI32U { .. } => Cost::Base(opcode_cost.opcode_i64extendi32u), + Operator::I64GeS { .. } => Cost::Base(opcode_cost.opcode_i64ges), + Operator::I64GeU { .. } => Cost::Base(opcode_cost.opcode_i64geu), + Operator::I64GtS { .. } => Cost::Base(opcode_cost.opcode_i64gts), + Operator::I64GtU { .. } => Cost::Base(opcode_cost.opcode_i64gtu), + Operator::I64LeS { .. } => Cost::Base(opcode_cost.opcode_i64les), + Operator::I64LeU { .. } => Cost::Base(opcode_cost.opcode_i64leu), + Operator::I64Load { .. } => Cost::Base(opcode_cost.opcode_i64load), + Operator::I64Load16S { .. } => Cost::Base(opcode_cost.opcode_i64load16s), + Operator::I64Load16U { .. } => Cost::Base(opcode_cost.opcode_i64load16u), + Operator::I64Load32S { .. } => Cost::Base(opcode_cost.opcode_i64load32s), + Operator::I64Load32U { .. } => Cost::Base(opcode_cost.opcode_i64load32u), + Operator::I64Load8S { .. } => Cost::Base(opcode_cost.opcode_i64load8s), + Operator::I64Load8U { .. } => Cost::Base(opcode_cost.opcode_i64load8u), + Operator::I64LtS { .. } => Cost::Base(opcode_cost.opcode_i64lts), + Operator::I64LtU { .. } => Cost::Base(opcode_cost.opcode_i64ltu), + Operator::I64Mul { .. } => Cost::Base(opcode_cost.opcode_i64mul), + Operator::I64Ne { .. } => Cost::Base(opcode_cost.opcode_i64ne), + Operator::I64Or { .. } => Cost::Base(opcode_cost.opcode_i64or), + Operator::I64Popcnt { .. } => Cost::Base(opcode_cost.opcode_i64popcnt), + Operator::I64RemS { .. } => Cost::Base(opcode_cost.opcode_i64rems), + Operator::I64RemU { .. } => Cost::Base(opcode_cost.opcode_i64remu), + Operator::I64Rotl { .. } => Cost::Base(opcode_cost.opcode_i64rotl), + Operator::I64Rotr { .. } => Cost::Base(opcode_cost.opcode_i64rotr), + Operator::I64Shl { .. } => Cost::Base(opcode_cost.opcode_i64shl), + Operator::I64ShrS { .. } => Cost::Base(opcode_cost.opcode_i64shrs), + Operator::I64ShrU { .. } => Cost::Base(opcode_cost.opcode_i64shru), + Operator::I64Store { .. } => Cost::Base(opcode_cost.opcode_i64store), + Operator::I64Store16 { .. } => Cost::Base(opcode_cost.opcode_i64store16), + Operator::I64Store32 { .. } => Cost::Base(opcode_cost.opcode_i64store32), + Operator::I64Store8 { .. } => Cost::Base(opcode_cost.opcode_i64store8), + Operator::I64Sub { .. } => Cost::Base(opcode_cost.opcode_i64sub), + Operator::I64Xor { .. } => Cost::Base(opcode_cost.opcode_i64xor), + Operator::If { .. } => Cost::Base(opcode_cost.opcode_if), + Operator::LocalGet { .. } => Cost::Base(opcode_cost.opcode_localget), + Operator::LocalSet { .. } => Cost::Base(opcode_cost.opcode_localset), + Operator::LocalTee { .. } => Cost::Base(opcode_cost.opcode_localtee), + Operator::Loop { .. } => Cost::Base(opcode_cost.opcode_loop), + Operator::MemoryGrow { .. } => Cost::Base(opcode_cost.opcode_memorygrow), + Operator::MemorySize { .. } => Cost::Base(opcode_cost.opcode_memorysize), + Operator::Nop { .. } => Cost::Base(opcode_cost.opcode_nop), + Operator::RefFunc { .. } => Cost::Base(opcode_cost.opcode_reffunc), + Operator::RefIsNull { .. } => Cost::Base(opcode_cost.opcode_refisnull), + Operator::RefNull { .. } => Cost::Base(opcode_cost.opcode_refnull), + Operator::Rethrow { .. } => Cost::Base(opcode_cost.opcode_rethrow), + Operator::Return { .. } => Cost::Base(opcode_cost.opcode_return), + Operator::ReturnCall { .. } => Cost::Base(opcode_cost.opcode_returncall), + Operator::ReturnCallIndirect { .. } => Cost::Base(opcode_cost.opcode_returncallindirect), + Operator::Select { .. } => Cost::Base(opcode_cost.opcode_select), + Operator::TableGet { .. } => Cost::Base(opcode_cost.opcode_tableget), + Operator::TableGrow { .. } => Cost::Base(opcode_cost.opcode_tablegrow), + Operator::TableInit { .. } => Cost::Base(opcode_cost.opcode_tableinit), + Operator::TableSet { .. } => Cost::Base(opcode_cost.opcode_tableset), + Operator::TableSize { .. } => Cost::Base(opcode_cost.opcode_tablesize), + Operator::Throw { .. } => Cost::Base(opcode_cost.opcode_throw), + Operator::Try { .. } => Cost::Base(opcode_cost.opcode_try), + Operator::TypedSelect { .. } => Cost::Base(opcode_cost.opcode_typedselect), + Operator::Unreachable { .. } => Cost::Base(opcode_cost.opcode_unreachable), + Operator::MemoryCopy { .. } => Cost::BulkMemory { base: opcode_cost.opcode_memorycopy, per_byte: opcode_cost.opcode_memorycopyperbyte }, + Operator::MemoryFill { .. } => Cost::BulkMemory { base: opcode_cost.opcode_memoryfill, per_byte: opcode_cost.opcode_memoryfillperbyte }, + _ => Cost::Illegal, } } diff --git a/vm-executor-wasmer/src/wasmer_opcode_cost_type.rs b/vm-executor-wasmer/src/wasmer_opcode_cost_type.rs new file mode 100644 index 0000000..124c276 --- /dev/null +++ b/vm-executor-wasmer/src/wasmer_opcode_cost_type.rs @@ -0,0 +1,20 @@ +/// What executing one WASM operator costs. +/// +/// Not to be confused with `OpcodeCost`, which is the full cost table, as configured by the +/// gas schedule. This is the cost of one occurrence of one operator. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Cost { + /// The operator is not allowed by the configured opcode version, so it has no cost. + /// + /// Modules that contain it are rejected at compile time. + Illegal, + + /// The operator is charged once, no matter what its operands are. + Base(u32), + + /// A bulk memory operator (`memory.copy`, `memory.fill`), charged once for the operation + /// itself, plus once for every byte it copies or fills. + /// + /// The base cost is what keeps processing zero bytes from being free. + BulkMemory { base: u32, per_byte: u32 }, +} diff --git a/vm-executor-wasmer/tests/bulk-memory.wat b/vm-executor-wasmer/tests/bulk-memory.wat new file mode 100644 index 0000000..6d19ee5 --- /dev/null +++ b/vm-executor-wasmer/tests/bulk-memory.wat @@ -0,0 +1,37 @@ +(module + (memory $mem 1) + (func $copyZero (type $void) + (memory.copy + (i32.const 0) ;; destination address + (i32.const 64) ;; source address + (i32.const 0) ;; size of memory region in bytes + ) + ) + (func $copyTen (type $void) + (memory.copy + (i32.const 0) ;; destination address + (i32.const 64) ;; source address + (i32.const 10) ;; size of memory region in bytes + ) + ) + (func $fillZero (type $void) + (memory.fill + (i32.const 0) ;; destination address + (i32.const 7) ;; value to fill with + (i32.const 0) ;; size of memory region in bytes + ) + ) + (func $fillTen (type $void) + (memory.fill + (i32.const 0) ;; destination address + (i32.const 7) ;; value to fill with + (i32.const 10) ;; size of memory region in bytes + ) + ) + (type $void (func)) + (export "memory" (memory $mem)) + (export "copyZero" (func $copyZero)) + (export "copyTen" (func $copyTen)) + (export "fillZero" (func $fillZero)) + (export "fillTen" (func $fillTen)) +) diff --git a/vm-executor-wasmer/tests/bulk_memory_metering_test.rs b/vm-executor-wasmer/tests/bulk_memory_metering_test.rs new file mode 100644 index 0000000..66589ff --- /dev/null +++ b/vm-executor-wasmer/tests/bulk_memory_metering_test.rs @@ -0,0 +1,81 @@ +use multiversx_chain_vm_executor::{ + CompilationOptionsLegacy, ExecutorLegacy, InstanceLegacy, OpcodeConfig, OpcodeCost, + OpcodeVersion, VMHooksLegacyDefault, +}; +use multiversx_chain_vm_executor_wasmer::WasmerExecutor; +use wasmer::wat2wasm; + +const BULK_MEMORY_WAT: &[u8] = include_bytes!("bulk-memory.wat"); + +const MEMORY_COPY_COST: u32 = 300; +const MEMORY_COPY_PER_BYTE_COST: u32 = 7; +const MEMORY_FILL_COST: u32 = 400; +const MEMORY_FILL_PER_BYTE_COST: u32 = 11; + +const COMPILATION_OPTIONS: CompilationOptionsLegacy = CompilationOptionsLegacy { + gas_limit: 1_000_000, + unmetered_locals: 0, + max_memory_grow: 0, + max_memory_grow_delta: 0, + opcode_trace: false, + metering: true, + runtime_breakpoints: true, +}; + +/// All opcodes are free, except the bulk memory ones, so that `points_used` after a call +/// is exactly the cost of the single `memory.copy`/`memory.fill` in the called function. +fn bulk_memory_instance() -> Box { + let wasm_bytes = wat2wasm(BULK_MEMORY_WAT).unwrap(); + + let mut executor = WasmerExecutor::new(Box::new(VMHooksLegacyDefault)); + executor + .set_opcode_config(OpcodeConfig { + opcode_version: OpcodeVersion::V2, + opcode_cost: OpcodeCost { + opcode_memorycopy: MEMORY_COPY_COST, + opcode_memorycopyperbyte: MEMORY_COPY_PER_BYTE_COST, + opcode_memoryfill: MEMORY_FILL_COST, + opcode_memoryfillperbyte: MEMORY_FILL_PER_BYTE_COST, + ..Default::default() + }, + }) + .unwrap(); + + executor + .new_instance(&wasm_bytes, &COMPILATION_OPTIONS) + .unwrap() +} + +fn points_used_by(instance: &dyn InstanceLegacy, func_name: &str) -> u64 { + instance.set_points_used(0).unwrap(); + instance.call(func_name).unwrap(); + instance.get_points_used().unwrap() +} + +#[test] +fn bulk_memory_zero_bytes_still_costs_the_base() { + let instance = bulk_memory_instance(); + + assert_eq!( + points_used_by(instance.as_ref(), "copyZero"), + MEMORY_COPY_COST as u64 + ); + assert_eq!( + points_used_by(instance.as_ref(), "fillZero"), + MEMORY_FILL_COST as u64 + ); +} + +#[test] +fn bulk_memory_bytes_cost_on_top_of_the_base() { + let instance = bulk_memory_instance(); + + assert_eq!( + points_used_by(instance.as_ref(), "copyTen"), + (MEMORY_COPY_COST + 10 * MEMORY_COPY_PER_BYTE_COST) as u64 + ); + assert_eq!( + points_used_by(instance.as_ref(), "fillTen"), + (MEMORY_FILL_COST + 10 * MEMORY_FILL_PER_BYTE_COST) as u64 + ); +} diff --git a/vm-executor/src/opcode_cost.rs b/vm-executor/src/opcode_cost.rs index ad2f7f7..85e9617 100644 --- a/vm-executor/src/opcode_cost.rs +++ b/vm-executor/src/opcode_cost.rs @@ -229,8 +229,12 @@ pub struct OpcodeCost { pub opcode_memorysize: u32, #[serde(rename = "MemoryCopy", default)] pub opcode_memorycopy: u32, + #[serde(rename = "MemoryCopyPerByte", default)] + pub opcode_memorycopyperbyte: u32, #[serde(rename = "MemoryFill", default)] pub opcode_memoryfill: u32, + #[serde(rename = "MemoryFillPerByte", default)] + pub opcode_memoryfillperbyte: u32, #[serde(rename = "Nop", default)] pub opcode_nop: u32, #[serde(rename = "RefFunc", default)] From 59ea7f6f217264dc7267c591349e77c6f50f91c4 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Wed, 23 Sep 2026 16:14:48 +0300 Subject: [PATCH 25/35] bulk memory gas for wasmer-experimental --- .../src/middlewares/we_metering.rs | 98 ++++++++++++++++++- .../middlewares/we_protected_globals_trait.rs | 2 + .../tests/bulk-memory.wat | 48 +++++++++ .../tests/bulk_memory_metering_test.rs | 82 ++++++++++++++++ vm-executor-wasmer/tests/bulk-memory.wat | 11 +++ .../tests/bulk_memory_metering_test.rs | 11 +++ 6 files changed, 248 insertions(+), 4 deletions(-) create mode 100644 vm-executor-experimental/tests/bulk-memory.wat create mode 100644 vm-executor-experimental/tests/bulk_memory_metering_test.rs diff --git a/vm-executor-experimental/src/middlewares/we_metering.rs b/vm-executor-experimental/src/middlewares/we_metering.rs index c52c578..4305336 100644 --- a/vm-executor-experimental/src/middlewares/we_metering.rs +++ b/vm-executor-experimental/src/middlewares/we_metering.rs @@ -16,6 +16,7 @@ use wasmer_types::{GlobalIndex, MiddlewareError, ModuleInfo}; const METERING_POINTS_LIMIT: &str = "metering_points_limit"; const METERING_POINTS_USED: &str = "metering_points_used"; +const METERING_BULK_MEMORY_SIZE_OPERAND_BACKUP: &str = "metering_bulk_memory_size_operand_backup"; const MAX_LOCAL_COUNT: u32 = 4000; const POINTS_LIMIT_INIT: i64 = 0; @@ -23,6 +24,7 @@ const POINTS_LIMIT_INIT: i64 = 0; struct MeteringGlobalIndexes { points_limit_global_index: GlobalIndex, points_used_global_index: GlobalIndex, + bulk_memory_size_operand_backup_global_index: GlobalIndex, } #[derive(Debug)] @@ -64,6 +66,15 @@ impl Metering { .unwrap() .points_used_global_index } + + pub fn get_bulk_memory_size_operand_backup_global_index(&self) -> GlobalIndex { + self.global_indexes + .lock() + .unwrap() + .as_ref() + .unwrap() + .bulk_memory_size_operand_backup_global_index + } } unsafe impl Send for Metering {} @@ -93,6 +104,11 @@ impl ModuleMiddleware for Metering { POINTS_LIMIT_INIT, ), points_used_global_index: create_global_index(module_info, METERING_POINTS_USED, 0), + bulk_memory_size_operand_backup_global_index: create_global_index( + module_info, + METERING_BULK_MEMORY_SIZE_OPERAND_BACKUP, + 0, + ), }); Ok(()) @@ -137,6 +153,71 @@ impl FunctionMetering { self.breakpoints_middleware .inject_breakpoint_condition(state, BREAKPOINT_VALUE_OUT_OF_GAS); } + + /// Injects `points_used += size * cost_per_byte` ahead of a `memory.copy`/`memory.fill`, + /// using `size` as it appears on the stack (the raw, attacker-controlled operand), before + /// the real bulk-memory instruction validates it against the actual memory bounds. + /// + /// This only covers the cost of the bytes. The flat cost of the instruction itself goes + /// through the regular accumulator, so that a zero-size copy or fill is never free. + /// + /// The multiplication is plain wrapping `i64` arithmetic (wasm has no trapping or + /// saturating integer multiply, and Wasmer doesn't offer one either), so it can in theory + /// wrap around for a large enough `size`. This is not exploitable under the current setup: + /// - `MAX_MEMORY_PAGES_ALLOWED` (in `we_instance.rs`) caps declared memory at 20 pages + /// (1.25 MiB), enforced at instantiation. + /// - any `size` large enough to matter for overflow (`size * cost_per_byte` approaching + /// `i64::MAX`) necessarily exceeds that 1.25 MiB bound, so the real `memory.copy`/ + /// `memory.fill` that follows this injected code traps on out-of-bounds access and aborts + /// the call immediately — regardless of what `points_used` ended up holding. + /// - a `size` that keeps the copy in-bounds is capped at 1,310,720 bytes, so + /// `size * cost_per_byte` tops out around `5.6e15` for a `u32` cost, far below `i64::MAX`. + fn inject_bulk_memory_cost(&self, state: &mut MiddlewareReaderState, cost_per_byte: u32) { + // backup the bulk memory size + state.extend(&[ + Operator::I64ExtendI32U, + Operator::GlobalSet { + global_index: self + .global_indexes + .bulk_memory_size_operand_backup_global_index + .as_u32(), + }, + ]); + + // inject bulk memory cost + state.extend(&[ + // memory size * price + Operator::GlobalGet { + global_index: self + .global_indexes + .bulk_memory_size_operand_backup_global_index + .as_u32(), + }, + Operator::I64Const { + value: cost_per_byte as i64, + }, + Operator::I64Mul, + // points used += memory size * price + Operator::GlobalGet { + global_index: self.global_indexes.points_used_global_index.as_u32(), + }, + Operator::I64Add, + Operator::GlobalSet { + global_index: self.global_indexes.points_used_global_index.as_u32(), + }, + ]); + + // bring back the bulk memory size + state.extend(&[ + Operator::GlobalGet { + global_index: self + .global_indexes + .bulk_memory_size_operand_backup_global_index + .as_u32(), + }, + Operator::I32WrapI64, + ]); + } } impl FunctionMiddleware for FunctionMetering { @@ -156,10 +237,19 @@ impl FunctionMiddleware for FunctionMetering { format!("Unsupported operator: {operator:?}"), )); } - // TODO: the `per_byte` cost is ignored here, the bulk memory operators are not yet - // metered per byte in this executor, unlike in the production one - Cost::Base(base) | Cost::BulkMemory { base, .. } => { - self.accumulated_cost += base as u64 + Cost::Base(base) => self.accumulated_cost += base as u64, + Cost::BulkMemory { base, per_byte } => { + self.accumulated_cost += base as u64; + + // flush what accumulated so far, including the base cost of this operator, + // so that the out of gas check below takes all of it into account + self.inject_points_used_increment(state); + self.accumulated_cost = 0; + + self.inject_bulk_memory_cost(state, per_byte); + + // immediately insert out of gas check as this operation might be expensive + self.inject_out_of_gas_check(state); } } diff --git a/vm-executor-experimental/src/middlewares/we_protected_globals_trait.rs b/vm-executor-experimental/src/middlewares/we_protected_globals_trait.rs index 482cc93..22ac551 100644 --- a/vm-executor-experimental/src/middlewares/we_protected_globals_trait.rs +++ b/vm-executor-experimental/src/middlewares/we_protected_globals_trait.rs @@ -26,6 +26,8 @@ impl MiddlewareWithProtectedGlobals for Metering { vec![ self.get_points_limit_global_index().as_u32(), self.get_points_used_global_index().as_u32(), + self.get_bulk_memory_size_operand_backup_global_index() + .as_u32(), ] } } diff --git a/vm-executor-experimental/tests/bulk-memory.wat b/vm-executor-experimental/tests/bulk-memory.wat new file mode 100644 index 0000000..ea04c72 --- /dev/null +++ b/vm-executor-experimental/tests/bulk-memory.wat @@ -0,0 +1,48 @@ +(module + (memory $mem 1) + (func $copyZero (type $void) + (memory.copy + (i32.const 0) ;; destination address + (i32.const 64) ;; source address + (i32.const 0) ;; size of memory region in bytes + ) + ) + (func $copyTen (type $void) + (memory.copy + (i32.const 0) ;; destination address + (i32.const 64) ;; source address + (i32.const 10) ;; size of memory region in bytes + ) + ) + (func $fillZero (type $void) + (memory.fill + (i32.const 0) ;; destination address + (i32.const 7) ;; value to fill with + (i32.const 0) ;; size of memory region in bytes + ) + ) + (func $fillTen (type $void) + (memory.fill + (i32.const 0) ;; destination address + (i32.const 7) ;; value to fill with + (i32.const 10) ;; size of memory region in bytes + ) + ) + ;; same as $copyTen, but with a size that the compiler cannot see through, + ;; to check that the size operand survives the metering injection unchanged + (func $copyLocalTen (type $void) (local $size i32) + (local.set $size (i32.const 10)) + (memory.copy + (i32.const 0) ;; destination address + (i32.const 64) ;; source address + (local.get $size) ;; size of memory region in bytes + ) + ) + (type $void (func)) + (export "memory" (memory $mem)) + (export "copyZero" (func $copyZero)) + (export "copyTen" (func $copyTen)) + (export "fillZero" (func $fillZero)) + (export "fillTen" (func $fillTen)) + (export "copyLocalTen" (func $copyLocalTen)) +) diff --git a/vm-executor-experimental/tests/bulk_memory_metering_test.rs b/vm-executor-experimental/tests/bulk_memory_metering_test.rs new file mode 100644 index 0000000..2f78b90 --- /dev/null +++ b/vm-executor-experimental/tests/bulk_memory_metering_test.rs @@ -0,0 +1,82 @@ +use std::sync::Arc; + +use multiversx_chain_vm_executor::{ + CompilationOptions, Instance, InstanceCallResult, OpcodeConfig, OpcodeCost, OpcodeVersion, +}; +use multiversx_chain_vm_executor_wasmer_experimental::{ + ExperimentalInstance, ExperimentalVMHooksBuilderDefault, +}; +use wasmer::wat2wasm; + +const BULK_MEMORY_WAT: &[u8] = include_bytes!("bulk-memory.wat"); + +const POINTS_LIMIT: u64 = 1_000_000; +const MEMORY_COPY_COST: u32 = 300; +const MEMORY_COPY_PER_BYTE_COST: u32 = 7; +const MEMORY_FILL_COST: u32 = 400; +const MEMORY_FILL_PER_BYTE_COST: u32 = 11; + +const COMPILATION_OPTIONS: CompilationOptions = CompilationOptions { + unmetered_locals: 0, + max_memory_grow: 0, + max_memory_grow_delta: 0, + opcode_trace: false, +}; + +/// All opcodes are free, except the bulk memory ones, so that `points_used` after a call +/// is exactly the cost of the single `memory.copy`/`memory.fill` in the called function. +/// +/// A fresh instance per call, since `points_used` only starts at zero. +fn points_used_by(func_name: &str) -> u64 { + let wasm_bytes = wat2wasm(BULK_MEMORY_WAT).unwrap(); + + let opcode_config = OpcodeConfig { + opcode_version: OpcodeVersion::V2, + opcode_cost: OpcodeCost { + opcode_memorycopy: MEMORY_COPY_COST, + opcode_memorycopyperbyte: MEMORY_COPY_PER_BYTE_COST, + opcode_memoryfill: MEMORY_FILL_COST, + opcode_memoryfillperbyte: MEMORY_FILL_PER_BYTE_COST, + ..Default::default() + }, + }; + + let mut instance = ExperimentalInstance::try_new_instance( + Box::new(ExperimentalVMHooksBuilderDefault), + Arc::new(opcode_config), + &wasm_bytes, + &COMPILATION_OPTIONS, + ) + .unwrap(); + + assert!(matches!( + instance.call(func_name, POINTS_LIMIT), + InstanceCallResult::Ok + )); + + instance.get_points_used().unwrap() +} + +#[test] +fn bulk_memory_zero_bytes_still_costs_the_base() { + assert_eq!(points_used_by("copyZero"), MEMORY_COPY_COST as u64); + assert_eq!(points_used_by("fillZero"), MEMORY_FILL_COST as u64); +} + +#[test] +fn bulk_memory_bytes_cost_on_top_of_the_base() { + assert_eq!( + points_used_by("copyTen"), + (MEMORY_COPY_COST + 10 * MEMORY_COPY_PER_BYTE_COST) as u64 + ); + assert_eq!( + points_used_by("fillTen"), + (MEMORY_FILL_COST + 10 * MEMORY_FILL_PER_BYTE_COST) as u64 + ); +} + +/// The injected metering code takes the size operand off the stack and puts it back. +#[test] +fn bulk_memory_size_operand_survives_the_injection() { + assert_eq!(points_used_by("copyLocalTen"), points_used_by("copyTen")); +} diff --git a/vm-executor-wasmer/tests/bulk-memory.wat b/vm-executor-wasmer/tests/bulk-memory.wat index 6d19ee5..ea04c72 100644 --- a/vm-executor-wasmer/tests/bulk-memory.wat +++ b/vm-executor-wasmer/tests/bulk-memory.wat @@ -28,10 +28,21 @@ (i32.const 10) ;; size of memory region in bytes ) ) + ;; same as $copyTen, but with a size that the compiler cannot see through, + ;; to check that the size operand survives the metering injection unchanged + (func $copyLocalTen (type $void) (local $size i32) + (local.set $size (i32.const 10)) + (memory.copy + (i32.const 0) ;; destination address + (i32.const 64) ;; source address + (local.get $size) ;; size of memory region in bytes + ) + ) (type $void (func)) (export "memory" (memory $mem)) (export "copyZero" (func $copyZero)) (export "copyTen" (func $copyTen)) (export "fillZero" (func $fillZero)) (export "fillTen" (func $fillTen)) + (export "copyLocalTen" (func $copyLocalTen)) ) diff --git a/vm-executor-wasmer/tests/bulk_memory_metering_test.rs b/vm-executor-wasmer/tests/bulk_memory_metering_test.rs index 66589ff..93a0dec 100644 --- a/vm-executor-wasmer/tests/bulk_memory_metering_test.rs +++ b/vm-executor-wasmer/tests/bulk_memory_metering_test.rs @@ -79,3 +79,14 @@ fn bulk_memory_bytes_cost_on_top_of_the_base() { (MEMORY_FILL_COST + 10 * MEMORY_FILL_PER_BYTE_COST) as u64 ); } + +/// The injected metering code takes the size operand off the stack and puts it back. +#[test] +fn bulk_memory_size_operand_survives_the_injection() { + let instance = bulk_memory_instance(); + + assert_eq!( + points_used_by(instance.as_ref(), "copyLocalTen"), + points_used_by(instance.as_ref(), "copyTen") + ); +} From 9b0b28cd45abf7274dd96d25cce1d54ef40407c7 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Wed, 23 Sep 2026 18:43:33 +0300 Subject: [PATCH 26/35] clippy fix --- vm-executor/src/missing_wasm.rs | 2 +- vm-executor/src/service_error.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vm-executor/src/missing_wasm.rs b/vm-executor/src/missing_wasm.rs index 40e083d..3592a83 100644 --- a/vm-executor/src/missing_wasm.rs +++ b/vm-executor/src/missing_wasm.rs @@ -20,7 +20,7 @@ pub struct MissingWasmError(String); impl fmt::Display for MissingWasmError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Contract {}", &self.0) + write!(f, "Contract {}", self.0) } } diff --git a/vm-executor/src/service_error.rs b/vm-executor/src/service_error.rs index 576f4e2..3076320 100644 --- a/vm-executor/src/service_error.rs +++ b/vm-executor/src/service_error.rs @@ -14,7 +14,7 @@ impl ServiceError { impl Display for ServiceError { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}", &self.message) + write!(f, "{}", self.message) } } From 6803e32885f198f9ee66d9b3f9bbc3986f2b15cd Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Wed, 23 Sep 2026 18:54:37 +0300 Subject: [PATCH 27/35] Rust versio nupgrade: 1.98 --- .github/workflows/libvmexeccapi-build.yml | 2 +- .github/workflows/rust-ci.yml | 6 +++--- Docker/arm64.dockerfile | 2 +- rust-toolchain.toml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/libvmexeccapi-build.yml b/.github/workflows/libvmexeccapi-build.yml index c164325..733eedf 100644 --- a/.github/workflows/libvmexeccapi-build.yml +++ b/.github/workflows/libvmexeccapi-build.yml @@ -29,7 +29,7 @@ jobs: - name: Install rust uses: actions-rust-lang/setup-rust-toolchain@v1 with: - toolchain: "1.92" + toolchain: "1.98" - name: Checkout uses: actions/checkout@v4 diff --git a/.github/workflows/rust-ci.yml b/.github/workflows/rust-ci.yml index a11557f..cc46fef 100644 --- a/.github/workflows/rust-ci.yml +++ b/.github/workflows/rust-ci.yml @@ -15,9 +15,9 @@ jobs: - uses: actions-rs/toolchain@v1 with: default: true - toolchain: "1.92" + toolchain: "1.98" - name: Run rust tests - run: cargo +1.92 test --release + run: cargo +1.98 test --release clippy_check: permissions: write-all name: Clippy linter check @@ -26,7 +26,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: - toolchain: stable + toolchain: "1.98" components: clippy default: true - uses: actions-rs/clippy-check@v1 diff --git a/Docker/arm64.dockerfile b/Docker/arm64.dockerfile index 0f2f776..b6ea433 100644 --- a/Docker/arm64.dockerfile +++ b/Docker/arm64.dockerfile @@ -1,4 +1,4 @@ -FROM arm64v8/rust:1.77.0 +FROM arm64v8/rust:1.98 RUN apt-get update && apt-get install -y \ wget \ diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 292fe49..e000fd2 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "stable" +channel = "1.98" From bbc71f735438e54248457cb741ff87aab34abcde Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Wed, 23 Sep 2026 20:12:06 +0300 Subject: [PATCH 28/35] doc fix --- vm-executor-experimental/src/middlewares/we_metering.rs | 7 +++++-- vm-executor-wasmer/src/wasmer_metering.rs | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/vm-executor-experimental/src/middlewares/we_metering.rs b/vm-executor-experimental/src/middlewares/we_metering.rs index 4305336..28c3c0f 100644 --- a/vm-executor-experimental/src/middlewares/we_metering.rs +++ b/vm-executor-experimental/src/middlewares/we_metering.rs @@ -161,6 +161,9 @@ impl FunctionMetering { /// This only covers the cost of the bytes. The flat cost of the instruction itself goes /// through the regular accumulator, so that a zero-size copy or fill is never free. /// + /// Both operators take `size` as their last operand - `memory.copy` is `[dst, src, size]`, + /// `memory.fill` is `[dst, value, size]` - so the same injection works for both. + /// /// The multiplication is plain wrapping `i64` arithmetic (wasm has no trapping or /// saturating integer multiply, and Wasmer doesn't offer one either), so it can in theory /// wrap around for a large enough `size`. This is not exploitable under the current setup: @@ -186,7 +189,7 @@ impl FunctionMetering { // inject bulk memory cost state.extend(&[ - // memory size * price + // size * cost_per_byte Operator::GlobalGet { global_index: self .global_indexes @@ -197,7 +200,7 @@ impl FunctionMetering { value: cost_per_byte as i64, }, Operator::I64Mul, - // points used += memory size * price + // points_used += size * cost_per_byte Operator::GlobalGet { global_index: self.global_indexes.points_used_global_index.as_u32(), }, diff --git a/vm-executor-wasmer/src/wasmer_metering.rs b/vm-executor-wasmer/src/wasmer_metering.rs index 2621b75..bcf06dc 100644 --- a/vm-executor-wasmer/src/wasmer_metering.rs +++ b/vm-executor-wasmer/src/wasmer_metering.rs @@ -183,6 +183,9 @@ impl FunctionMetering { /// This only covers the cost of the bytes. The flat cost of the instruction itself goes /// through the regular accumulator, so that a zero-size copy or fill is never free. /// + /// Both operators take `size` as their last operand - `memory.copy` is `[dst, src, size]`, + /// `memory.fill` is `[dst, value, size]` - so the same injection works for both. + /// /// The multiplication is plain wrapping `i64` arithmetic (wasm has no trapping or /// saturating integer multiply, and Wasmer doesn't offer one either), so it can in theory /// wrap around for a large enough `size`. This is not exploitable under the current setup: @@ -205,7 +208,7 @@ impl FunctionMetering { // inject bulk memory cost state.extend(&[ - // memory size * price + // size * cost_per_byte Operator::GlobalGet { global_index: self .global_indexes @@ -216,7 +219,7 @@ impl FunctionMetering { value: cost_per_byte as i64, }, Operator::I64Mul, - // points user += memory size * price + // points_used += size * cost_per_byte Operator::GlobalGet { global_index: self.global_indexes.points_used_global_index.as_u32(), }, From 80f4c8d6c2d2b3d185227418439c4eb5ff269fba Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Wed, 23 Sep 2026 20:17:49 +0300 Subject: [PATCH 29/35] docs & naming fixes --- vm-executor-experimental/src/middlewares/we_metering.rs | 4 ++-- vm-executor-experimental/tests/bulk-memory.wat | 4 ++-- vm-executor-experimental/tests/bulk_memory_metering_test.rs | 3 ++- vm-executor-wasmer/src/wasmer_metering.rs | 4 ++-- vm-executor-wasmer/tests/bulk-memory.wat | 4 ++-- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/vm-executor-experimental/src/middlewares/we_metering.rs b/vm-executor-experimental/src/middlewares/we_metering.rs index 28c3c0f..a771ad8 100644 --- a/vm-executor-experimental/src/middlewares/we_metering.rs +++ b/vm-executor-experimental/src/middlewares/we_metering.rs @@ -232,8 +232,8 @@ impl FunctionMiddleware for FunctionMetering { // Get the cost of the current operator, and add it to the accumulator. // This needs to be done before the metering logic, to prevent operators like `Call` from escaping metering in some // corner cases. - let op_exec_cost = get_opcode_cost(&operator, &self.opcode_config); - match op_exec_cost { + let cost = get_opcode_cost(&operator, &self.opcode_config); + match cost { Cost::Illegal => { return Err(MiddlewareError::new( "metering_middleware", diff --git a/vm-executor-experimental/tests/bulk-memory.wat b/vm-executor-experimental/tests/bulk-memory.wat index ea04c72..f5997d2 100644 --- a/vm-executor-experimental/tests/bulk-memory.wat +++ b/vm-executor-experimental/tests/bulk-memory.wat @@ -28,8 +28,8 @@ (i32.const 10) ;; size of memory region in bytes ) ) - ;; same as $copyTen, but with a size that the compiler cannot see through, - ;; to check that the size operand survives the metering injection unchanged + ;; same as $copyTen, but with the size coming from a local instead of an + ;; immediate constant, to check that the metering injection gives it back unchanged (func $copyLocalTen (type $void) (local $size i32) (local.set $size (i32.const 10)) (memory.copy diff --git a/vm-executor-experimental/tests/bulk_memory_metering_test.rs b/vm-executor-experimental/tests/bulk_memory_metering_test.rs index 2f78b90..b163c21 100644 --- a/vm-executor-experimental/tests/bulk_memory_metering_test.rs +++ b/vm-executor-experimental/tests/bulk_memory_metering_test.rs @@ -26,7 +26,8 @@ const COMPILATION_OPTIONS: CompilationOptions = CompilationOptions { /// All opcodes are free, except the bulk memory ones, so that `points_used` after a call /// is exactly the cost of the single `memory.copy`/`memory.fill` in the called function. /// -/// A fresh instance per call, since `points_used` only starts at zero. +/// A fresh instance for every call, since the `Instance` trait offers no way to reset +/// `points_used` back to zero. fn points_used_by(func_name: &str) -> u64 { let wasm_bytes = wat2wasm(BULK_MEMORY_WAT).unwrap(); diff --git a/vm-executor-wasmer/src/wasmer_metering.rs b/vm-executor-wasmer/src/wasmer_metering.rs index bcf06dc..310e8b4 100644 --- a/vm-executor-wasmer/src/wasmer_metering.rs +++ b/vm-executor-wasmer/src/wasmer_metering.rs @@ -248,8 +248,8 @@ impl FunctionMiddleware for FunctionMetering { // Get the cost of the current operator, and add it to the accumulator. // This needs to be done before the metering logic, to prevent operators like `Call` from escaping metering in some // corner cases. - let op_exec_cost = get_opcode_cost(&operator, &self.opcode_config.lock().unwrap()); - match op_exec_cost { + let cost = get_opcode_cost(&operator, &self.opcode_config.lock().unwrap()); + match cost { Cost::Illegal => { return Err(MiddlewareError::new( "metering_middleware", diff --git a/vm-executor-wasmer/tests/bulk-memory.wat b/vm-executor-wasmer/tests/bulk-memory.wat index ea04c72..f5997d2 100644 --- a/vm-executor-wasmer/tests/bulk-memory.wat +++ b/vm-executor-wasmer/tests/bulk-memory.wat @@ -28,8 +28,8 @@ (i32.const 10) ;; size of memory region in bytes ) ) - ;; same as $copyTen, but with a size that the compiler cannot see through, - ;; to check that the size operand survives the metering injection unchanged + ;; same as $copyTen, but with the size coming from a local instead of an + ;; immediate constant, to check that the metering injection gives it back unchanged (func $copyLocalTen (type $void) (local $size i32) (local.set $size (i32.const 10)) (memory.copy From d5d7d8a997d898ded7e04a9a5a1cf174982fd8b1 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Thu, 24 Sep 2026 10:00:48 +0300 Subject: [PATCH 30/35] bulk memory cost temp global changed to i32 --- .../src/middlewares/we_breakpoints.rs | 4 +- .../src/middlewares/we_metering.rs | 43 +++++++++---------- .../src/middlewares/we_opcode_control.rs | 6 +-- vm-executor-experimental/src/we_helpers.rs | 29 ++++++++++--- vm-executor-wasmer/src/wasmer_breakpoints.rs | 4 +- vm-executor-wasmer/src/wasmer_helpers.rs | 38 +++++++++++++--- vm-executor-wasmer/src/wasmer_metering.rs | 14 +++--- .../src/wasmer_opcode_control.rs | 6 +-- 8 files changed, 96 insertions(+), 48 deletions(-) diff --git a/vm-executor-experimental/src/middlewares/we_breakpoints.rs b/vm-executor-experimental/src/middlewares/we_breakpoints.rs index aacecd0..70a279c 100644 --- a/vm-executor-experimental/src/middlewares/we_breakpoints.rs +++ b/vm-executor-experimental/src/middlewares/we_breakpoints.rs @@ -6,7 +6,7 @@ use wasmer::wasmparser::Operator; use wasmer::{AsStoreMut, Instance, LocalFunctionIndex}; use wasmer_types::{GlobalIndex, MiddlewareError, ModuleInfo}; -use crate::we_helpers::{create_global_index, get_global_value_u64, is_control_flow_operator}; +use crate::we_helpers::{create_i64_global_index, get_global_value_u64, is_control_flow_operator}; const BREAKPOINT_VALUE: &str = "breakpoint_value"; @@ -77,7 +77,7 @@ impl ModuleMiddleware for Breakpoints { let mut global_index = self.global_index.lock().unwrap(); *global_index = Some(BreakpointsGlobalIndex { - breakpoint_value_global_index: create_global_index( + breakpoint_value_global_index: create_i64_global_index( module_info, BREAKPOINT_VALUE, BREAKPOINT_VALUE_NO_BREAKPOINT as i64, diff --git a/vm-executor-experimental/src/middlewares/we_metering.rs b/vm-executor-experimental/src/middlewares/we_metering.rs index a771ad8..e6196cd 100644 --- a/vm-executor-experimental/src/middlewares/we_metering.rs +++ b/vm-executor-experimental/src/middlewares/we_metering.rs @@ -4,7 +4,8 @@ use super::{ BREAKPOINT_VALUE_OUT_OF_GAS, Breakpoints, Cost, MiddlewareWithProtectedGlobals, get_opcode_cost, }; use crate::we_helpers::{ - create_global_index, get_global_value_u64, is_control_flow_operator, set_global_value_u64, + create_i32_global_index, create_i64_global_index, get_global_value_u64, + is_control_flow_operator, set_global_value_u64, }; use multiversx_chain_vm_executor::{ExecutorError, OpcodeConfig, OpcodeCost}; use std::mem; @@ -98,13 +99,13 @@ impl ModuleMiddleware for Metering { let mut global_indexes = self.global_indexes.lock().unwrap(); *global_indexes = Some(MeteringGlobalIndexes { - points_limit_global_index: create_global_index( + points_limit_global_index: create_i64_global_index( module_info, METERING_POINTS_LIMIT, POINTS_LIMIT_INIT, ), - points_used_global_index: create_global_index(module_info, METERING_POINTS_USED, 0), - bulk_memory_size_operand_backup_global_index: create_global_index( + points_used_global_index: create_i64_global_index(module_info, METERING_POINTS_USED, 0), + bulk_memory_size_operand_backup_global_index: create_i32_global_index( module_info, METERING_BULK_MEMORY_SIZE_OPERAND_BACKUP, 0, @@ -164,6 +165,9 @@ impl FunctionMetering { /// Both operators take `size` as their last operand - `memory.copy` is `[dst, src, size]`, /// `memory.fill` is `[dst, value, size]` - so the same injection works for both. /// + /// `size` is an `i32` and so is the global it is parked in, so it makes the round trip + /// untouched. Only the multiplication is widened to `i64`, to leave room for the product. + /// /// The multiplication is plain wrapping `i64` arithmetic (wasm has no trapping or /// saturating integer multiply, and Wasmer doesn't offer one either), so it can in theory /// wrap around for a large enough `size`. This is not exploitable under the current setup: @@ -177,15 +181,12 @@ impl FunctionMetering { /// `size * cost_per_byte` tops out around `5.6e15` for a `u32` cost, far below `i64::MAX`. fn inject_bulk_memory_cost(&self, state: &mut MiddlewareReaderState, cost_per_byte: u32) { // backup the bulk memory size - state.extend(&[ - Operator::I64ExtendI32U, - Operator::GlobalSet { - global_index: self - .global_indexes - .bulk_memory_size_operand_backup_global_index - .as_u32(), - }, - ]); + state.extend(&[Operator::GlobalSet { + global_index: self + .global_indexes + .bulk_memory_size_operand_backup_global_index + .as_u32(), + }]); // inject bulk memory cost state.extend(&[ @@ -196,6 +197,7 @@ impl FunctionMetering { .bulk_memory_size_operand_backup_global_index .as_u32(), }, + Operator::I64ExtendI32U, Operator::I64Const { value: cost_per_byte as i64, }, @@ -211,15 +213,12 @@ impl FunctionMetering { ]); // bring back the bulk memory size - state.extend(&[ - Operator::GlobalGet { - global_index: self - .global_indexes - .bulk_memory_size_operand_backup_global_index - .as_u32(), - }, - Operator::I32WrapI64, - ]); + state.extend(&[Operator::GlobalGet { + global_index: self + .global_indexes + .bulk_memory_size_operand_backup_global_index + .as_u32(), + }]); } } diff --git a/vm-executor-experimental/src/middlewares/we_opcode_control.rs b/vm-executor-experimental/src/middlewares/we_opcode_control.rs index 2624123..b3ce492 100644 --- a/vm-executor-experimental/src/middlewares/we_opcode_control.rs +++ b/vm-executor-experimental/src/middlewares/we_opcode_control.rs @@ -9,7 +9,7 @@ use wasmer_types::{GlobalIndex, MiddlewareError, ModuleInfo}; use crate::{ // we_breakpoints::{Breakpoints, BREAKPOINT_VALUE_MEMORY_LIMIT}, - we_helpers::create_global_index, + we_helpers::create_i64_global_index, // MiddlewareWithProtectedGlobals, }; @@ -92,12 +92,12 @@ impl ModuleMiddleware for OpcodeControl { let mut global_indexes = self.global_indexes.lock().unwrap(); *global_indexes = Some(OpcodeControlGlobalIndexes { - memory_grow_count_global_index: create_global_index( + memory_grow_count_global_index: create_i64_global_index( module_info, OPCODE_CONTROL_MEMORY_GROW_COUNT, 0, ), - operand_backup_global_index: create_global_index( + operand_backup_global_index: create_i64_global_index( module_info, OPCODE_CONTROL_OPERAND_BACKUP, 0, diff --git a/vm-executor-experimental/src/we_helpers.rs b/vm-executor-experimental/src/we_helpers.rs index be4345b..5ba36c5 100644 --- a/vm-executor-experimental/src/we_helpers.rs +++ b/vm-executor-experimental/src/we_helpers.rs @@ -7,18 +7,37 @@ use wasmer_types::{GlobalIndex, ModuleInfo}; use crate::ExperimentalError; -pub(crate) fn create_global_index( +/// Creates and exports a fresh mutable i32 global in the module and initializes it. +pub(crate) fn create_i32_global_index( + module_info: &mut ModuleInfo, + key: &str, + init: i32, +) -> GlobalIndex { + create_global_index(module_info, key, Type::I32, GlobalInit::I32Const(init)) +} + +/// Creates and exports a fresh mutable i64 global in the module and initializes it. +pub(crate) fn create_i64_global_index( module_info: &mut ModuleInfo, key: &str, init: i64, +) -> GlobalIndex { + create_global_index(module_info, key, Type::I64, GlobalInit::I64Const(init)) +} + +/// Only reachable through the typed constructors above, which are what keeps the declared +/// type and the initializer from disagreeing. +fn create_global_index( + module_info: &mut ModuleInfo, + key: &str, + global_type: Type, + init: GlobalInit, ) -> GlobalIndex { let global_index = module_info .globals - .push(GlobalType::new(Type::I64, Mutability::Var)); + .push(GlobalType::new(global_type, Mutability::Var)); - module_info - .global_initializers - .push(GlobalInit::I64Const(init)); + module_info.global_initializers.push(init); module_info .exports diff --git a/vm-executor-wasmer/src/wasmer_breakpoints.rs b/vm-executor-wasmer/src/wasmer_breakpoints.rs index bf8af13..836ce4d 100644 --- a/vm-executor-wasmer/src/wasmer_breakpoints.rs +++ b/vm-executor-wasmer/src/wasmer_breakpoints.rs @@ -10,7 +10,7 @@ use wasmer::{ use wasmer_types::{GlobalIndex, ModuleInfo}; use crate::wasmer_helpers::{ - MiddlewareWithProtectedGlobals, create_global_index, get_global_value_u64, + MiddlewareWithProtectedGlobals, create_i64_global_index, get_global_value_u64, is_control_flow_operator, set_global_value_u64, }; @@ -90,7 +90,7 @@ impl ModuleMiddleware for Breakpoints { let mut global_index = self.global_index.lock().unwrap(); *global_index = Some(BreakpointsGlobalIndex { - breakpoint_value_global_index: create_global_index( + breakpoint_value_global_index: create_i64_global_index( module_info, BREAKPOINT_VALUE, BREAKPOINT_VALUE_NO_BREAKPOINT as i64, diff --git a/vm-executor-wasmer/src/wasmer_helpers.rs b/vm-executor-wasmer/src/wasmer_helpers.rs index 861b8b4..5c6c540 100644 --- a/vm-executor-wasmer/src/wasmer_helpers.rs +++ b/vm-executor-wasmer/src/wasmer_helpers.rs @@ -16,7 +16,7 @@ impl std::fmt::Debug for dyn MiddlewareWithProtectedGlobals { } } -/// Creates and exports a fresh i64 global in the module and initializes it. +/// Creates and exports a fresh mutable i32 global in the module and initializes it. /// /// # Parameters /// - `module_info`: the module metadata to update @@ -25,18 +25,44 @@ impl std::fmt::Debug for dyn MiddlewareWithProtectedGlobals { /// /// # Returns /// The index of the newly created global in the module. -pub(crate) fn create_global_index( +pub(crate) fn create_i32_global_index( + module_info: &mut ModuleInfo, + key: &str, + init: i32, +) -> GlobalIndex { + create_global_index(module_info, key, Type::I32, GlobalInit::I32Const(init)) +} + +/// Creates and exports a fresh mutable i64 global in the module and initializes it. +/// +/// # Parameters +/// - `module_info`: the module metadata to update +/// - `key`: the exported name for the global +/// - `init`: the initial value assigned to the global +/// +/// # Returns +/// The index of the newly created global in the module. +pub(crate) fn create_i64_global_index( module_info: &mut ModuleInfo, key: &str, init: i64, +) -> GlobalIndex { + create_global_index(module_info, key, Type::I64, GlobalInit::I64Const(init)) +} + +/// Only reachable through the typed constructors above, which are what keeps the declared +/// type and the initializer from disagreeing. +fn create_global_index( + module_info: &mut ModuleInfo, + key: &str, + global_type: Type, + init: GlobalInit, ) -> GlobalIndex { let global_index = module_info .globals - .push(GlobalType::new(Type::I64, Mutability::Var)); + .push(GlobalType::new(global_type, Mutability::Var)); - module_info - .global_initializers - .push(GlobalInit::I64Const(init)); + module_info.global_initializers.push(init); module_info .exports diff --git a/vm-executor-wasmer/src/wasmer_metering.rs b/vm-executor-wasmer/src/wasmer_metering.rs index 310e8b4..6661685 100644 --- a/vm-executor-wasmer/src/wasmer_metering.rs +++ b/vm-executor-wasmer/src/wasmer_metering.rs @@ -2,8 +2,8 @@ use crate::executor_interface::OpcodeConfig; use crate::get_opcode_cost; use crate::wasmer_breakpoints::{BREAKPOINT_VALUE_OUT_OF_GAS, Breakpoints}; use crate::wasmer_helpers::{ - MiddlewareWithProtectedGlobals, create_global_index, get_global_value_u64, - is_control_flow_operator, set_global_value_u64, + MiddlewareWithProtectedGlobals, create_i32_global_index, create_i64_global_index, + get_global_value_u64, is_control_flow_operator, set_global_value_u64, }; use crate::wasmer_opcode_cost_type::Cost; use loupe::{MemoryUsage, MemoryUsageTracker}; @@ -111,13 +111,13 @@ impl ModuleMiddleware for Metering { let points_limit = self.points_limit as i64; *global_indexes = Some(MeteringGlobalIndexes { - points_limit_global_index: create_global_index( + points_limit_global_index: create_i64_global_index( module_info, METERING_POINTS_LIMIT, points_limit, ), - points_used_global_index: create_global_index(module_info, METERING_POINTS_USED, 0), - bulk_memory_size_operand_backup_global_index: create_global_index( + points_used_global_index: create_i64_global_index(module_info, METERING_POINTS_USED, 0), + bulk_memory_size_operand_backup_global_index: create_i32_global_index( module_info, METERING_BULK_MEMORY_SIZE_OPERAND_BACKUP, 0, @@ -186,6 +186,9 @@ impl FunctionMetering { /// Both operators take `size` as their last operand - `memory.copy` is `[dst, src, size]`, /// `memory.fill` is `[dst, value, size]` - so the same injection works for both. /// + /// `size` is an `i32` and so is the global it is parked in, so it makes the round trip + /// untouched. Only the multiplication is widened to `i64`, to leave room for the product. + /// /// The multiplication is plain wrapping `i64` arithmetic (wasm has no trapping or /// saturating integer multiply, and Wasmer doesn't offer one either), so it can in theory /// wrap around for a large enough `size`. This is not exploitable under the current setup: @@ -215,6 +218,7 @@ impl FunctionMetering { .bulk_memory_size_operand_backup_global_index .as_u32(), }, + Operator::I64ExtendI32U, Operator::I64Const { value: cost_per_byte as i64, }, diff --git a/vm-executor-wasmer/src/wasmer_opcode_control.rs b/vm-executor-wasmer/src/wasmer_opcode_control.rs index 3c74b40..d51021d 100644 --- a/vm-executor-wasmer/src/wasmer_opcode_control.rs +++ b/vm-executor-wasmer/src/wasmer_opcode_control.rs @@ -12,7 +12,7 @@ use wasmer_types::{GlobalIndex, ModuleInfo}; use crate::{ wasmer_breakpoints::{BREAKPOINT_VALUE_MEMORY_LIMIT, Breakpoints}, - wasmer_helpers::{MiddlewareWithProtectedGlobals, create_global_index}, + wasmer_helpers::{MiddlewareWithProtectedGlobals, create_i64_global_index}, }; const OPCODE_CONTROL_MEMORY_GROW_COUNT: &str = "opcode_control_memory_grow_count"; @@ -99,12 +99,12 @@ impl ModuleMiddleware for OpcodeControl { let mut global_indexes = self.global_indexes.lock().unwrap(); *global_indexes = Some(OpcodeControlGlobalIndexes { - memory_grow_count_global_index: create_global_index( + memory_grow_count_global_index: create_i64_global_index( module_info, OPCODE_CONTROL_MEMORY_GROW_COUNT, 0, ), - operand_backup_global_index: create_global_index( + operand_backup_global_index: create_i64_global_index( module_info, OPCODE_CONTROL_OPERAND_BACKUP, 0, From ebc3092caa1dc1d3e9dbb6179098a152a0f2f103 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Thu, 24 Sep 2026 19:57:52 +0300 Subject: [PATCH 31/35] build.rs revert style --- c-api/build.rs | 7 +- c-api/libvmexeccapi.h | 968 ++++++++---------------------------------- 2 files changed, 179 insertions(+), 796 deletions(-) diff --git a/c-api/build.rs b/c-api/build.rs index a2a8266..ddb0426 100644 --- a/c-api/build.rs +++ b/c-api/build.rs @@ -1,6 +1,6 @@ extern crate cbindgen; -use cbindgen::{Builder, Language}; +use cbindgen::{Builder, Language, Style}; use std::{env, fs, path::PathBuf}; const HEADER_FILE_NAME: &str = "libvmexeccapi"; @@ -19,6 +19,11 @@ fn main() { Builder::new() .with_crate(crate_dir) .with_language(Language::C) + // Keep the historical formatting: no line wrapping, `typedef struct { ... } name;` + // without a tag. Both differ from the cbindgen defaults and would otherwise rewrite + // the whole header on every re-generation. + .with_line_length(usize::MAX) + .with_style(Style::Type) .generate() .expect("Unable to generate C bindings") .write_to_file(out_wasmer_header_file.as_path()); diff --git a/c-api/libvmexeccapi.h b/c-api/libvmexeccapi.h index bd04054..4cee9a6 100644 --- a/c-api/libvmexeccapi.h +++ b/c-api/libvmexeccapi.h @@ -7,7 +7,7 @@ * The `wasmer_result_t` enum is a type that represents either a * success, or a failure. */ -typedef enum vm_exec_result_t { +typedef enum { /** * Represents a success. */ @@ -25,15 +25,15 @@ typedef enum vm_exec_result_t { * is generally generated by the `wasmer_instantiate()` function, or by * the `wasmer_module_instantiate()` function for the most common paths. */ -typedef struct vm_exec_instance_t { +typedef struct { } vm_exec_instance_t; -typedef struct vm_exec_executor_t { +typedef struct { } vm_exec_executor_t; -typedef struct vm_exec_vm_hook_c_func_pointers { +typedef struct { int64_t (*get_gas_left_func_ptr)(void *context); void (*get_sc_address_func_ptr)(void *context, int32_t result_offset); void (*get_owner_address_func_ptr)(void *context, int32_t result_offset); @@ -42,160 +42,33 @@ typedef struct vm_exec_vm_hook_c_func_pointers { void (*signal_error_func_ptr)(void *context, int32_t message_offset, int32_t message_length); void (*get_external_balance_func_ptr)(void *context, int32_t address_offset, int32_t result_offset); int32_t (*get_block_hash_func_ptr)(void *context, int64_t nonce, int32_t result_offset); - int32_t (*get_esdt_balance_func_ptr)(void *context, - int32_t address_offset, - int32_t token_id_offset, - int32_t token_id_len, - int64_t nonce, - int32_t result_offset); - int32_t (*get_esdt_nft_name_length_func_ptr)(void *context, - int32_t address_offset, - int32_t token_id_offset, - int32_t token_id_len, - int64_t nonce); - int32_t (*get_esdt_nft_attribute_length_func_ptr)(void *context, - int32_t address_offset, - int32_t token_id_offset, - int32_t token_id_len, - int64_t nonce); - int32_t (*get_esdt_nft_uri_length_func_ptr)(void *context, - int32_t address_offset, - int32_t token_id_offset, - int32_t token_id_len, - int64_t nonce); - int32_t (*get_esdt_token_data_func_ptr)(void *context, - int32_t address_offset, - int32_t token_id_offset, - int32_t token_id_len, - int64_t nonce, - int32_t value_handle, - int32_t properties_offset, - int32_t hash_offset, - int32_t name_offset, - int32_t attributes_offset, - int32_t creator_offset, - int32_t royalties_handle, - int32_t uris_offset); + int32_t (*get_esdt_balance_func_ptr)(void *context, int32_t address_offset, int32_t token_id_offset, int32_t token_id_len, int64_t nonce, int32_t result_offset); + int32_t (*get_esdt_nft_name_length_func_ptr)(void *context, int32_t address_offset, int32_t token_id_offset, int32_t token_id_len, int64_t nonce); + int32_t (*get_esdt_nft_attribute_length_func_ptr)(void *context, int32_t address_offset, int32_t token_id_offset, int32_t token_id_len, int64_t nonce); + int32_t (*get_esdt_nft_uri_length_func_ptr)(void *context, int32_t address_offset, int32_t token_id_offset, int32_t token_id_len, int64_t nonce); + int32_t (*get_esdt_token_data_func_ptr)(void *context, int32_t address_offset, int32_t token_id_offset, int32_t token_id_len, int64_t nonce, int32_t value_handle, int32_t properties_offset, int32_t hash_offset, int32_t name_offset, int32_t attributes_offset, int32_t creator_offset, int32_t royalties_handle, int32_t uris_offset); int64_t (*get_esdt_local_roles_func_ptr)(void *context, int32_t token_id_handle); int32_t (*validate_token_identifier_func_ptr)(void *context, int32_t token_id_handle); - int32_t (*transfer_value_func_ptr)(void *context, - int32_t dest_offset, - int32_t value_offset, - int32_t data_offset, - int32_t length); - int32_t (*transfer_value_execute_func_ptr)(void *context, - int32_t dest_offset, - int32_t value_offset, - int64_t gas_limit, - int32_t function_offset, - int32_t function_length, - int32_t num_arguments, - int32_t arguments_length_offset, - int32_t data_offset); - int32_t (*transfer_esdt_execute_func_ptr)(void *context, - int32_t dest_offset, - int32_t token_id_offset, - int32_t token_id_len, - int32_t value_offset, - int64_t gas_limit, - int32_t function_offset, - int32_t function_length, - int32_t num_arguments, - int32_t arguments_length_offset, - int32_t data_offset); - int32_t (*transfer_esdt_nft_execute_func_ptr)(void *context, - int32_t dest_offset, - int32_t token_id_offset, - int32_t token_id_len, - int32_t value_offset, - int64_t nonce, - int64_t gas_limit, - int32_t function_offset, - int32_t function_length, - int32_t num_arguments, - int32_t arguments_length_offset, - int32_t data_offset); - int32_t (*multi_transfer_esdt_nft_execute_func_ptr)(void *context, - int32_t dest_offset, - int32_t num_token_transfers, - int32_t token_transfers_args_length_offset, - int32_t token_transfer_data_offset, - int64_t gas_limit, - int32_t function_offset, - int32_t function_length, - int32_t num_arguments, - int32_t arguments_length_offset, - int32_t data_offset); - int32_t (*create_async_call_func_ptr)(void *context, - int32_t dest_offset, - int32_t value_offset, - int32_t data_offset, - int32_t data_length, - int32_t success_offset, - int32_t success_length, - int32_t error_offset, - int32_t error_length, - int64_t gas, - int64_t extra_gas_for_callback); - int32_t (*set_async_context_callback_func_ptr)(void *context, - int32_t callback, - int32_t callback_length, - int32_t data, - int32_t data_length, - int64_t gas); - void (*upgrade_contract_func_ptr)(void *context, - int32_t dest_offset, - int64_t gas_limit, - int32_t value_offset, - int32_t code_offset, - int32_t code_metadata_offset, - int32_t length, - int32_t num_arguments, - int32_t arguments_length_offset, - int32_t data_offset); - void (*upgrade_from_source_contract_func_ptr)(void *context, - int32_t dest_offset, - int64_t gas_limit, - int32_t value_offset, - int32_t source_contract_address_offset, - int32_t code_metadata_offset, - int32_t num_arguments, - int32_t arguments_length_offset, - int32_t data_offset); - void (*delete_contract_func_ptr)(void *context, - int32_t dest_offset, - int64_t gas_limit, - int32_t num_arguments, - int32_t arguments_length_offset, - int32_t data_offset); - void (*async_call_func_ptr)(void *context, - int32_t dest_offset, - int32_t value_offset, - int32_t data_offset, - int32_t length); + int32_t (*transfer_value_func_ptr)(void *context, int32_t dest_offset, int32_t value_offset, int32_t data_offset, int32_t length); + int32_t (*transfer_value_execute_func_ptr)(void *context, int32_t dest_offset, int32_t value_offset, int64_t gas_limit, int32_t function_offset, int32_t function_length, int32_t num_arguments, int32_t arguments_length_offset, int32_t data_offset); + int32_t (*transfer_esdt_execute_func_ptr)(void *context, int32_t dest_offset, int32_t token_id_offset, int32_t token_id_len, int32_t value_offset, int64_t gas_limit, int32_t function_offset, int32_t function_length, int32_t num_arguments, int32_t arguments_length_offset, int32_t data_offset); + int32_t (*transfer_esdt_nft_execute_func_ptr)(void *context, int32_t dest_offset, int32_t token_id_offset, int32_t token_id_len, int32_t value_offset, int64_t nonce, int64_t gas_limit, int32_t function_offset, int32_t function_length, int32_t num_arguments, int32_t arguments_length_offset, int32_t data_offset); + int32_t (*multi_transfer_esdt_nft_execute_func_ptr)(void *context, int32_t dest_offset, int32_t num_token_transfers, int32_t token_transfers_args_length_offset, int32_t token_transfer_data_offset, int64_t gas_limit, int32_t function_offset, int32_t function_length, int32_t num_arguments, int32_t arguments_length_offset, int32_t data_offset); + int32_t (*create_async_call_func_ptr)(void *context, int32_t dest_offset, int32_t value_offset, int32_t data_offset, int32_t data_length, int32_t success_offset, int32_t success_length, int32_t error_offset, int32_t error_length, int64_t gas, int64_t extra_gas_for_callback); + int32_t (*set_async_context_callback_func_ptr)(void *context, int32_t callback, int32_t callback_length, int32_t data, int32_t data_length, int64_t gas); + void (*upgrade_contract_func_ptr)(void *context, int32_t dest_offset, int64_t gas_limit, int32_t value_offset, int32_t code_offset, int32_t code_metadata_offset, int32_t length, int32_t num_arguments, int32_t arguments_length_offset, int32_t data_offset); + void (*upgrade_from_source_contract_func_ptr)(void *context, int32_t dest_offset, int64_t gas_limit, int32_t value_offset, int32_t source_contract_address_offset, int32_t code_metadata_offset, int32_t num_arguments, int32_t arguments_length_offset, int32_t data_offset); + void (*delete_contract_func_ptr)(void *context, int32_t dest_offset, int64_t gas_limit, int32_t num_arguments, int32_t arguments_length_offset, int32_t data_offset); + void (*async_call_func_ptr)(void *context, int32_t dest_offset, int32_t value_offset, int32_t data_offset, int32_t length); int32_t (*get_argument_length_func_ptr)(void *context, int32_t id); int32_t (*get_argument_func_ptr)(void *context, int32_t id, int32_t arg_offset); int32_t (*get_function_func_ptr)(void *context, int32_t function_offset); int32_t (*get_num_arguments_func_ptr)(void *context); - int32_t (*storage_store_func_ptr)(void *context, - int32_t key_offset, - int32_t key_length, - int32_t data_offset, - int32_t data_length); + int32_t (*storage_store_func_ptr)(void *context, int32_t key_offset, int32_t key_length, int32_t data_offset, int32_t data_length); int32_t (*storage_load_length_func_ptr)(void *context, int32_t key_offset, int32_t key_length); - int32_t (*storage_load_from_address_func_ptr)(void *context, - int32_t address_offset, - int32_t key_offset, - int32_t key_length, - int32_t data_offset); - int32_t (*storage_load_func_ptr)(void *context, - int32_t key_offset, - int32_t key_length, - int32_t data_offset); - int32_t (*set_storage_lock_func_ptr)(void *context, - int32_t key_offset, - int32_t key_length, - int64_t lock_timestamp); + int32_t (*storage_load_from_address_func_ptr)(void *context, int32_t address_offset, int32_t key_offset, int32_t key_length, int32_t data_offset); + int32_t (*storage_load_func_ptr)(void *context, int32_t key_offset, int32_t key_length, int32_t data_offset); + int32_t (*set_storage_lock_func_ptr)(void *context, int32_t key_offset, int32_t key_length, int64_t lock_timestamp); int64_t (*get_storage_lock_func_ptr)(void *context, int32_t key_offset, int32_t key_length); int32_t (*is_storage_locked_func_ptr)(void *context, int32_t key_offset, int32_t key_length); int32_t (*clear_storage_lock_func_ptr)(void *context, int32_t key_offset, int32_t key_length); @@ -205,37 +78,18 @@ typedef struct vm_exec_vm_hook_c_func_pointers { int32_t (*get_esdt_value_func_ptr)(void *context, int32_t result_offset); int32_t (*get_esdt_value_by_index_func_ptr)(void *context, int32_t result_offset, int32_t index); int32_t (*get_esdt_token_name_func_ptr)(void *context, int32_t result_offset); - int32_t (*get_esdt_token_name_by_index_func_ptr)(void *context, - int32_t result_offset, - int32_t index); + int32_t (*get_esdt_token_name_by_index_func_ptr)(void *context, int32_t result_offset, int32_t index); int64_t (*get_esdt_token_nonce_func_ptr)(void *context); int64_t (*get_esdt_token_nonce_by_index_func_ptr)(void *context, int32_t index); - int64_t (*get_current_esdt_nft_nonce_func_ptr)(void *context, - int32_t address_offset, - int32_t token_id_offset, - int32_t token_id_len); + int64_t (*get_current_esdt_nft_nonce_func_ptr)(void *context, int32_t address_offset, int32_t token_id_offset, int32_t token_id_len); int32_t (*get_esdt_token_type_func_ptr)(void *context); int32_t (*get_esdt_token_type_by_index_func_ptr)(void *context, int32_t index); int32_t (*get_num_esdt_transfers_func_ptr)(void *context); - int32_t (*get_call_value_token_name_func_ptr)(void *context, - int32_t call_value_offset, - int32_t token_name_offset); - int32_t (*get_call_value_token_name_by_index_func_ptr)(void *context, - int32_t call_value_offset, - int32_t token_name_offset, - int32_t index); + int32_t (*get_call_value_token_name_func_ptr)(void *context, int32_t call_value_offset, int32_t token_name_offset); + int32_t (*get_call_value_token_name_by_index_func_ptr)(void *context, int32_t call_value_offset, int32_t token_name_offset, int32_t index); int32_t (*is_reserved_function_name_func_ptr)(void *context, int32_t name_handle); - void (*write_log_func_ptr)(void *context, - int32_t data_pointer, - int32_t data_length, - int32_t topic_ptr, - int32_t num_topics); - void (*write_event_log_func_ptr)(void *context, - int32_t num_topics, - int32_t topic_lengths_offset, - int32_t topic_offset, - int32_t data_offset, - int32_t data_length); + void (*write_log_func_ptr)(void *context, int32_t data_pointer, int32_t data_length, int32_t topic_ptr, int32_t num_topics); + void (*write_event_log_func_ptr)(void *context, int32_t num_topics, int32_t topic_lengths_offset, int32_t topic_offset, int32_t data_offset, int32_t data_length); int64_t (*get_block_timestamp_func_ptr)(void *context); int64_t (*get_block_timestamp_ms_func_ptr)(void *context); int64_t (*get_block_nonce_func_ptr)(void *context); @@ -254,51 +108,11 @@ typedef struct vm_exec_vm_hook_c_func_pointers { int64_t (*epoch_start_block_nonce_func_ptr)(void *context); int64_t (*epoch_start_block_round_func_ptr)(void *context); void (*finish_func_ptr)(void *context, int32_t pointer, int32_t length); - int32_t (*execute_on_same_context_func_ptr)(void *context, - int64_t gas_limit, - int32_t address_offset, - int32_t value_offset, - int32_t function_offset, - int32_t function_length, - int32_t num_arguments, - int32_t arguments_length_offset, - int32_t data_offset); - int32_t (*execute_on_dest_context_func_ptr)(void *context, - int64_t gas_limit, - int32_t address_offset, - int32_t value_offset, - int32_t function_offset, - int32_t function_length, - int32_t num_arguments, - int32_t arguments_length_offset, - int32_t data_offset); - int32_t (*execute_read_only_func_ptr)(void *context, - int64_t gas_limit, - int32_t address_offset, - int32_t function_offset, - int32_t function_length, - int32_t num_arguments, - int32_t arguments_length_offset, - int32_t data_offset); - int32_t (*create_contract_func_ptr)(void *context, - int64_t gas_limit, - int32_t value_offset, - int32_t code_offset, - int32_t code_metadata_offset, - int32_t length, - int32_t result_offset, - int32_t num_arguments, - int32_t arguments_length_offset, - int32_t data_offset); - int32_t (*deploy_from_source_contract_func_ptr)(void *context, - int64_t gas_limit, - int32_t value_offset, - int32_t source_contract_address_offset, - int32_t code_metadata_offset, - int32_t result_address_offset, - int32_t num_arguments, - int32_t arguments_length_offset, - int32_t data_offset); + int32_t (*execute_on_same_context_func_ptr)(void *context, int64_t gas_limit, int32_t address_offset, int32_t value_offset, int32_t function_offset, int32_t function_length, int32_t num_arguments, int32_t arguments_length_offset, int32_t data_offset); + int32_t (*execute_on_dest_context_func_ptr)(void *context, int64_t gas_limit, int32_t address_offset, int32_t value_offset, int32_t function_offset, int32_t function_length, int32_t num_arguments, int32_t arguments_length_offset, int32_t data_offset); + int32_t (*execute_read_only_func_ptr)(void *context, int64_t gas_limit, int32_t address_offset, int32_t function_offset, int32_t function_length, int32_t num_arguments, int32_t arguments_length_offset, int32_t data_offset); + int32_t (*create_contract_func_ptr)(void *context, int64_t gas_limit, int32_t value_offset, int32_t code_offset, int32_t code_metadata_offset, int32_t length, int32_t result_offset, int32_t num_arguments, int32_t arguments_length_offset, int32_t data_offset); + int32_t (*deploy_from_source_contract_func_ptr)(void *context, int64_t gas_limit, int32_t value_offset, int32_t source_contract_address_offset, int32_t code_metadata_offset, int32_t result_address_offset, int32_t num_arguments, int32_t arguments_length_offset, int32_t data_offset); int32_t (*get_num_return_data_func_ptr)(void *context); int32_t (*get_return_data_size_func_ptr)(void *context, int32_t result_id); int32_t (*get_return_data_func_ptr)(void *context, int32_t result_id, int32_t data_offset); @@ -320,596 +134,183 @@ typedef struct vm_exec_vm_hook_c_func_pointers { void (*managed_get_prev_block_random_seed_func_ptr)(void *context, int32_t result_handle); void (*managed_get_return_data_func_ptr)(void *context, int32_t result_id, int32_t result_handle); void (*managed_get_multi_esdt_call_value_func_ptr)(void *context, int32_t multi_call_value_handle); - void (*managed_get_all_transfers_call_value_func_ptr)(void *context, - int32_t transfer_call_values_list_handle); - void (*managed_get_back_transfers_func_ptr)(void *context, - int32_t esdt_transfers_value_handle, - int32_t egld_value_handle); - void (*managed_get_esdt_balance_func_ptr)(void *context, - int32_t address_handle, - int32_t token_id_handle, - int64_t nonce, - int32_t value_handle); - void (*managed_get_esdt_token_data_func_ptr)(void *context, - int32_t address_handle, - int32_t token_id_handle, - int64_t nonce, - int32_t value_handle, - int32_t properties_handle, - int32_t hash_handle, - int32_t name_handle, - int32_t attributes_handle, - int32_t creator_handle, - int32_t royalties_handle, - int32_t uris_handle); - void (*managed_get_esdt_token_type_func_ptr)(void *context, - int32_t address_handle, - int32_t token_id_handle, - int64_t nonce, - int32_t type_handle); - void (*managed_async_call_func_ptr)(void *context, - int32_t dest_handle, - int32_t value_handle, - int32_t function_handle, - int32_t arguments_handle); - int32_t (*managed_create_async_call_func_ptr)(void *context, - int32_t dest_handle, - int32_t value_handle, - int32_t function_handle, - int32_t arguments_handle, - int32_t success_offset, - int32_t success_length, - int32_t error_offset, - int32_t error_length, - int64_t gas, - int64_t extra_gas_for_callback, - int32_t callback_closure_handle); + void (*managed_get_all_transfers_call_value_func_ptr)(void *context, int32_t transfer_call_values_list_handle); + void (*managed_get_back_transfers_func_ptr)(void *context, int32_t esdt_transfers_value_handle, int32_t egld_value_handle); + void (*managed_get_esdt_balance_func_ptr)(void *context, int32_t address_handle, int32_t token_id_handle, int64_t nonce, int32_t value_handle); + void (*managed_get_esdt_token_data_func_ptr)(void *context, int32_t address_handle, int32_t token_id_handle, int64_t nonce, int32_t value_handle, int32_t properties_handle, int32_t hash_handle, int32_t name_handle, int32_t attributes_handle, int32_t creator_handle, int32_t royalties_handle, int32_t uris_handle); + void (*managed_get_esdt_token_type_func_ptr)(void *context, int32_t address_handle, int32_t token_id_handle, int64_t nonce, int32_t type_handle); + void (*managed_async_call_func_ptr)(void *context, int32_t dest_handle, int32_t value_handle, int32_t function_handle, int32_t arguments_handle); + int32_t (*managed_create_async_call_func_ptr)(void *context, int32_t dest_handle, int32_t value_handle, int32_t function_handle, int32_t arguments_handle, int32_t success_offset, int32_t success_length, int32_t error_offset, int32_t error_length, int64_t gas, int64_t extra_gas_for_callback, int32_t callback_closure_handle); void (*managed_get_callback_closure_func_ptr)(void *context, int32_t callback_closure_handle); - void (*managed_upgrade_from_source_contract_func_ptr)(void *context, - int32_t dest_handle, - int64_t gas, - int32_t value_handle, - int32_t address_handle, - int32_t code_metadata_handle, - int32_t arguments_handle, - int32_t result_handle); - void (*managed_upgrade_contract_func_ptr)(void *context, - int32_t dest_handle, - int64_t gas, - int32_t value_handle, - int32_t code_handle, - int32_t code_metadata_handle, - int32_t arguments_handle, - int32_t result_handle); - void (*managed_delete_contract_func_ptr)(void *context, - int32_t dest_handle, - int64_t gas_limit, - int32_t arguments_handle); - int32_t (*managed_deploy_from_source_contract_func_ptr)(void *context, - int64_t gas, - int32_t value_handle, - int32_t address_handle, - int32_t code_metadata_handle, - int32_t arguments_handle, - int32_t result_address_handle, - int32_t result_handle); - int32_t (*managed_create_contract_func_ptr)(void *context, - int64_t gas, - int32_t value_handle, - int32_t code_handle, - int32_t code_metadata_handle, - int32_t arguments_handle, - int32_t result_address_handle, - int32_t result_handle); - int32_t (*managed_execute_read_only_func_ptr)(void *context, - int64_t gas, - int32_t address_handle, - int32_t function_handle, - int32_t arguments_handle, - int32_t result_handle); - int32_t (*managed_execute_on_same_context_func_ptr)(void *context, - int64_t gas, - int32_t address_handle, - int32_t value_handle, - int32_t function_handle, - int32_t arguments_handle, - int32_t result_handle); - int32_t (*managed_execute_on_dest_context_func_ptr)(void *context, - int64_t gas, - int32_t address_handle, - int32_t value_handle, - int32_t function_handle, - int32_t arguments_handle, - int32_t result_handle); - int32_t (*managed_execute_on_dest_context_with_error_return_func_ptr)(void *context, - int64_t gas, - int32_t address_handle, - int32_t value_handle, - int32_t function_handle, - int32_t arguments_handle, - int32_t result_handle); - int32_t (*managed_multi_transfer_esdt_nft_execute_func_ptr)(void *context, - int32_t dst_handle, - int32_t token_transfers_handle, - int64_t gas_limit, - int32_t function_handle, - int32_t arguments_handle); - int32_t (*managed_multi_transfer_esdt_nft_execute_with_return_func_ptr)(void *context, - int32_t dst_handle, - int32_t token_transfers_handle, - int64_t gas_limit, - int32_t function_handle, - int32_t arguments_handle); - int32_t (*managed_multi_transfer_esdt_nft_execute_by_user_func_ptr)(void *context, - int32_t user_handle, - int32_t dst_handle, - int32_t token_transfers_handle, - int64_t gas_limit, - int32_t function_handle, - int32_t arguments_handle); - int32_t (*managed_transfer_value_execute_func_ptr)(void *context, - int32_t dst_handle, - int32_t value_handle, - int64_t gas_limit, - int32_t function_handle, - int32_t arguments_handle); - int32_t (*managed_is_esdt_frozen_func_ptr)(void *context, - int32_t address_handle, - int32_t token_id_handle, - int64_t nonce); + void (*managed_upgrade_from_source_contract_func_ptr)(void *context, int32_t dest_handle, int64_t gas, int32_t value_handle, int32_t address_handle, int32_t code_metadata_handle, int32_t arguments_handle, int32_t result_handle); + void (*managed_upgrade_contract_func_ptr)(void *context, int32_t dest_handle, int64_t gas, int32_t value_handle, int32_t code_handle, int32_t code_metadata_handle, int32_t arguments_handle, int32_t result_handle); + void (*managed_delete_contract_func_ptr)(void *context, int32_t dest_handle, int64_t gas_limit, int32_t arguments_handle); + int32_t (*managed_deploy_from_source_contract_func_ptr)(void *context, int64_t gas, int32_t value_handle, int32_t address_handle, int32_t code_metadata_handle, int32_t arguments_handle, int32_t result_address_handle, int32_t result_handle); + int32_t (*managed_create_contract_func_ptr)(void *context, int64_t gas, int32_t value_handle, int32_t code_handle, int32_t code_metadata_handle, int32_t arguments_handle, int32_t result_address_handle, int32_t result_handle); + int32_t (*managed_execute_read_only_func_ptr)(void *context, int64_t gas, int32_t address_handle, int32_t function_handle, int32_t arguments_handle, int32_t result_handle); + int32_t (*managed_execute_on_same_context_func_ptr)(void *context, int64_t gas, int32_t address_handle, int32_t value_handle, int32_t function_handle, int32_t arguments_handle, int32_t result_handle); + int32_t (*managed_execute_on_dest_context_func_ptr)(void *context, int64_t gas, int32_t address_handle, int32_t value_handle, int32_t function_handle, int32_t arguments_handle, int32_t result_handle); + int32_t (*managed_execute_on_dest_context_with_error_return_func_ptr)(void *context, int64_t gas, int32_t address_handle, int32_t value_handle, int32_t function_handle, int32_t arguments_handle, int32_t result_handle); + int32_t (*managed_multi_transfer_esdt_nft_execute_func_ptr)(void *context, int32_t dst_handle, int32_t token_transfers_handle, int64_t gas_limit, int32_t function_handle, int32_t arguments_handle); + int32_t (*managed_multi_transfer_esdt_nft_execute_with_return_func_ptr)(void *context, int32_t dst_handle, int32_t token_transfers_handle, int64_t gas_limit, int32_t function_handle, int32_t arguments_handle); + int32_t (*managed_multi_transfer_esdt_nft_execute_by_user_func_ptr)(void *context, int32_t user_handle, int32_t dst_handle, int32_t token_transfers_handle, int64_t gas_limit, int32_t function_handle, int32_t arguments_handle); + int32_t (*managed_transfer_value_execute_func_ptr)(void *context, int32_t dst_handle, int32_t value_handle, int64_t gas_limit, int32_t function_handle, int32_t arguments_handle); + int32_t (*managed_is_esdt_frozen_func_ptr)(void *context, int32_t address_handle, int32_t token_id_handle, int64_t nonce); int32_t (*managed_is_esdt_limited_transfer_func_ptr)(void *context, int32_t token_id_handle); int32_t (*managed_is_esdt_paused_func_ptr)(void *context, int32_t token_id_handle); void (*managed_buffer_to_hex_func_ptr)(void *context, int32_t source_handle, int32_t dest_handle); - void (*managed_get_code_metadata_func_ptr)(void *context, - int32_t address_handle, - int32_t response_handle); - void (*managed_get_code_hash_func_ptr)(void *context, - int32_t address_handle, - int32_t code_hash_handle); + void (*managed_get_code_metadata_func_ptr)(void *context, int32_t address_handle, int32_t response_handle); + void (*managed_get_code_hash_func_ptr)(void *context, int32_t address_handle, int32_t code_hash_handle); int32_t (*managed_is_builtin_function_func_ptr)(void *context, int32_t function_name_handle); - int32_t (*big_float_new_from_parts_func_ptr)(void *context, - int32_t integral_part, - int32_t fractional_part, - int32_t exponent); + int32_t (*big_float_new_from_parts_func_ptr)(void *context, int32_t integral_part, int32_t fractional_part, int32_t exponent); int32_t (*big_float_new_from_frac_func_ptr)(void *context, int64_t numerator, int64_t denominator); int32_t (*big_float_new_from_sci_func_ptr)(void *context, int64_t significand, int64_t exponent); - void (*big_float_add_func_ptr)(void *context, - int32_t destination_handle, - int32_t op1_handle, - int32_t op2_handle); - void (*big_float_sub_func_ptr)(void *context, - int32_t destination_handle, - int32_t op1_handle, - int32_t op2_handle); - void (*big_float_mul_func_ptr)(void *context, - int32_t destination_handle, - int32_t op1_handle, - int32_t op2_handle); - void (*big_float_div_func_ptr)(void *context, - int32_t destination_handle, - int32_t op1_handle, - int32_t op2_handle); + void (*big_float_add_func_ptr)(void *context, int32_t destination_handle, int32_t op1_handle, int32_t op2_handle); + void (*big_float_sub_func_ptr)(void *context, int32_t destination_handle, int32_t op1_handle, int32_t op2_handle); + void (*big_float_mul_func_ptr)(void *context, int32_t destination_handle, int32_t op1_handle, int32_t op2_handle); + void (*big_float_div_func_ptr)(void *context, int32_t destination_handle, int32_t op1_handle, int32_t op2_handle); void (*big_float_neg_func_ptr)(void *context, int32_t destination_handle, int32_t op_handle); void (*big_float_clone_func_ptr)(void *context, int32_t destination_handle, int32_t op_handle); int32_t (*big_float_cmp_func_ptr)(void *context, int32_t op1_handle, int32_t op2_handle); void (*big_float_abs_func_ptr)(void *context, int32_t destination_handle, int32_t op_handle); int32_t (*big_float_sign_func_ptr)(void *context, int32_t op_handle); void (*big_float_sqrt_func_ptr)(void *context, int32_t destination_handle, int32_t op_handle); - void (*big_float_pow_func_ptr)(void *context, - int32_t destination_handle, - int32_t op_handle, - int32_t exponent); + void (*big_float_pow_func_ptr)(void *context, int32_t destination_handle, int32_t op_handle, int32_t exponent); void (*big_float_floor_func_ptr)(void *context, int32_t dest_big_int_handle, int32_t op_handle); void (*big_float_ceil_func_ptr)(void *context, int32_t dest_big_int_handle, int32_t op_handle); void (*big_float_truncate_func_ptr)(void *context, int32_t dest_big_int_handle, int32_t op_handle); void (*big_float_set_int64_func_ptr)(void *context, int32_t destination_handle, int64_t value); int32_t (*big_float_is_int_func_ptr)(void *context, int32_t op_handle); - void (*big_float_set_big_int_func_ptr)(void *context, - int32_t destination_handle, - int32_t big_int_handle); + void (*big_float_set_big_int_func_ptr)(void *context, int32_t destination_handle, int32_t big_int_handle); void (*big_float_get_const_pi_func_ptr)(void *context, int32_t destination_handle); void (*big_float_get_const_e_func_ptr)(void *context, int32_t destination_handle); - void (*big_int_get_unsigned_argument_func_ptr)(void *context, - int32_t id, - int32_t destination_handle); + void (*big_int_get_unsigned_argument_func_ptr)(void *context, int32_t id, int32_t destination_handle); void (*big_int_get_signed_argument_func_ptr)(void *context, int32_t id, int32_t destination_handle); - int32_t (*big_int_storage_store_unsigned_func_ptr)(void *context, - int32_t key_offset, - int32_t key_length, - int32_t source_handle); - int32_t (*big_int_storage_load_unsigned_func_ptr)(void *context, - int32_t key_offset, - int32_t key_length, - int32_t destination_handle); + int32_t (*big_int_storage_store_unsigned_func_ptr)(void *context, int32_t key_offset, int32_t key_length, int32_t source_handle); + int32_t (*big_int_storage_load_unsigned_func_ptr)(void *context, int32_t key_offset, int32_t key_length, int32_t destination_handle); void (*big_int_get_call_value_func_ptr)(void *context, int32_t destination_handle); void (*big_int_get_esdt_call_value_func_ptr)(void *context, int32_t destination); - void (*big_int_get_esdt_call_value_by_index_func_ptr)(void *context, - int32_t destination_handle, - int32_t index); - void (*big_int_get_external_balance_func_ptr)(void *context, - int32_t address_offset, - int32_t result); - void (*big_int_get_esdt_external_balance_func_ptr)(void *context, - int32_t address_offset, - int32_t token_id_offset, - int32_t token_id_len, - int64_t nonce, - int32_t result_handle); + void (*big_int_get_esdt_call_value_by_index_func_ptr)(void *context, int32_t destination_handle, int32_t index); + void (*big_int_get_external_balance_func_ptr)(void *context, int32_t address_offset, int32_t result); + void (*big_int_get_esdt_external_balance_func_ptr)(void *context, int32_t address_offset, int32_t token_id_offset, int32_t token_id_len, int64_t nonce, int32_t result_handle); int32_t (*big_int_new_func_ptr)(void *context, int64_t small_value); int32_t (*big_int_unsigned_byte_length_func_ptr)(void *context, int32_t reference_handle); int32_t (*big_int_signed_byte_length_func_ptr)(void *context, int32_t reference_handle); - int32_t (*big_int_get_unsigned_bytes_func_ptr)(void *context, - int32_t reference_handle, - int32_t byte_offset); - int32_t (*big_int_get_signed_bytes_func_ptr)(void *context, - int32_t reference_handle, - int32_t byte_offset); - void (*big_int_set_unsigned_bytes_func_ptr)(void *context, - int32_t destination_handle, - int32_t byte_offset, - int32_t byte_length); - void (*big_int_set_signed_bytes_func_ptr)(void *context, - int32_t destination_handle, - int32_t byte_offset, - int32_t byte_length); + int32_t (*big_int_get_unsigned_bytes_func_ptr)(void *context, int32_t reference_handle, int32_t byte_offset); + int32_t (*big_int_get_signed_bytes_func_ptr)(void *context, int32_t reference_handle, int32_t byte_offset); + void (*big_int_set_unsigned_bytes_func_ptr)(void *context, int32_t destination_handle, int32_t byte_offset, int32_t byte_length); + void (*big_int_set_signed_bytes_func_ptr)(void *context, int32_t destination_handle, int32_t byte_offset, int32_t byte_length); int32_t (*big_int_is_int64_func_ptr)(void *context, int32_t destination_handle); int64_t (*big_int_get_int64_func_ptr)(void *context, int32_t destination_handle); void (*big_int_set_int64_func_ptr)(void *context, int32_t destination_handle, int64_t value); - void (*big_int_add_func_ptr)(void *context, - int32_t destination_handle, - int32_t op1_handle, - int32_t op2_handle); - void (*big_int_sub_func_ptr)(void *context, - int32_t destination_handle, - int32_t op1_handle, - int32_t op2_handle); - void (*big_int_mul_func_ptr)(void *context, - int32_t destination_handle, - int32_t op1_handle, - int32_t op2_handle); - void (*big_int_tdiv_func_ptr)(void *context, - int32_t destination_handle, - int32_t op1_handle, - int32_t op2_handle); - void (*big_int_tmod_func_ptr)(void *context, - int32_t destination_handle, - int32_t op1_handle, - int32_t op2_handle); - void (*big_int_ediv_func_ptr)(void *context, - int32_t destination_handle, - int32_t op1_handle, - int32_t op2_handle); - void (*big_int_emod_func_ptr)(void *context, - int32_t destination_handle, - int32_t op1_handle, - int32_t op2_handle); + void (*big_int_add_func_ptr)(void *context, int32_t destination_handle, int32_t op1_handle, int32_t op2_handle); + void (*big_int_sub_func_ptr)(void *context, int32_t destination_handle, int32_t op1_handle, int32_t op2_handle); + void (*big_int_mul_func_ptr)(void *context, int32_t destination_handle, int32_t op1_handle, int32_t op2_handle); + void (*big_int_tdiv_func_ptr)(void *context, int32_t destination_handle, int32_t op1_handle, int32_t op2_handle); + void (*big_int_tmod_func_ptr)(void *context, int32_t destination_handle, int32_t op1_handle, int32_t op2_handle); + void (*big_int_ediv_func_ptr)(void *context, int32_t destination_handle, int32_t op1_handle, int32_t op2_handle); + void (*big_int_emod_func_ptr)(void *context, int32_t destination_handle, int32_t op1_handle, int32_t op2_handle); void (*big_int_sqrt_func_ptr)(void *context, int32_t destination_handle, int32_t op_handle); - void (*big_int_pow_func_ptr)(void *context, - int32_t destination_handle, - int32_t op1_handle, - int32_t op2_handle); + void (*big_int_pow_func_ptr)(void *context, int32_t destination_handle, int32_t op1_handle, int32_t op2_handle); int32_t (*big_int_log2_func_ptr)(void *context, int32_t op1_handle); void (*big_int_abs_func_ptr)(void *context, int32_t destination_handle, int32_t op_handle); void (*big_int_neg_func_ptr)(void *context, int32_t destination_handle, int32_t op_handle); int32_t (*big_int_sign_func_ptr)(void *context, int32_t op_handle); int32_t (*big_int_cmp_func_ptr)(void *context, int32_t op1_handle, int32_t op2_handle); void (*big_int_not_func_ptr)(void *context, int32_t destination_handle, int32_t op_handle); - void (*big_int_and_func_ptr)(void *context, - int32_t destination_handle, - int32_t op1_handle, - int32_t op2_handle); - void (*big_int_or_func_ptr)(void *context, - int32_t destination_handle, - int32_t op1_handle, - int32_t op2_handle); - void (*big_int_xor_func_ptr)(void *context, - int32_t destination_handle, - int32_t op1_handle, - int32_t op2_handle); - void (*big_int_shr_func_ptr)(void *context, - int32_t destination_handle, - int32_t op_handle, - int32_t bits); - void (*big_int_shl_func_ptr)(void *context, - int32_t destination_handle, - int32_t op_handle, - int32_t bits); + void (*big_int_and_func_ptr)(void *context, int32_t destination_handle, int32_t op1_handle, int32_t op2_handle); + void (*big_int_or_func_ptr)(void *context, int32_t destination_handle, int32_t op1_handle, int32_t op2_handle); + void (*big_int_xor_func_ptr)(void *context, int32_t destination_handle, int32_t op1_handle, int32_t op2_handle); + void (*big_int_shr_func_ptr)(void *context, int32_t destination_handle, int32_t op_handle, int32_t bits); + void (*big_int_shl_func_ptr)(void *context, int32_t destination_handle, int32_t op_handle, int32_t bits); void (*big_int_finish_unsigned_func_ptr)(void *context, int32_t reference_handle); void (*big_int_finish_signed_func_ptr)(void *context, int32_t reference_handle); - void (*big_int_to_string_func_ptr)(void *context, - int32_t big_int_handle, - int32_t destination_handle); + void (*big_int_to_string_func_ptr)(void *context, int32_t big_int_handle, int32_t destination_handle); int32_t (*mbuffer_new_func_ptr)(void *context); int32_t (*mbuffer_new_from_bytes_func_ptr)(void *context, int32_t data_offset, int32_t data_length); int32_t (*mbuffer_get_length_func_ptr)(void *context, int32_t m_buffer_handle); - int32_t (*mbuffer_get_bytes_func_ptr)(void *context, - int32_t m_buffer_handle, - int32_t result_offset); - int32_t (*mbuffer_get_byte_slice_func_ptr)(void *context, - int32_t source_handle, - int32_t starting_position, - int32_t slice_length, - int32_t result_offset); - int32_t (*mbuffer_copy_byte_slice_func_ptr)(void *context, - int32_t source_handle, - int32_t starting_position, - int32_t slice_length, - int32_t destination_handle); + int32_t (*mbuffer_get_bytes_func_ptr)(void *context, int32_t m_buffer_handle, int32_t result_offset); + int32_t (*mbuffer_get_byte_slice_func_ptr)(void *context, int32_t source_handle, int32_t starting_position, int32_t slice_length, int32_t result_offset); + int32_t (*mbuffer_copy_byte_slice_func_ptr)(void *context, int32_t source_handle, int32_t starting_position, int32_t slice_length, int32_t destination_handle); int32_t (*mbuffer_eq_func_ptr)(void *context, int32_t m_buffer_handle1, int32_t m_buffer_handle2); - int32_t (*mbuffer_set_bytes_func_ptr)(void *context, - int32_t m_buffer_handle, - int32_t data_offset, - int32_t data_length); - int32_t (*mbuffer_set_byte_slice_func_ptr)(void *context, - int32_t m_buffer_handle, - int32_t starting_position, - int32_t data_length, - int32_t data_offset); + int32_t (*mbuffer_set_bytes_func_ptr)(void *context, int32_t m_buffer_handle, int32_t data_offset, int32_t data_length); + int32_t (*mbuffer_set_byte_slice_func_ptr)(void *context, int32_t m_buffer_handle, int32_t starting_position, int32_t data_length, int32_t data_offset); int32_t (*mbuffer_append_func_ptr)(void *context, int32_t accumulator_handle, int32_t data_handle); - int32_t (*mbuffer_append_bytes_func_ptr)(void *context, - int32_t accumulator_handle, - int32_t data_offset, - int32_t data_length); - int32_t (*mbuffer_to_big_int_unsigned_func_ptr)(void *context, - int32_t m_buffer_handle, - int32_t big_int_handle); - int32_t (*mbuffer_to_big_int_signed_func_ptr)(void *context, - int32_t m_buffer_handle, - int32_t big_int_handle); - int32_t (*mbuffer_from_big_int_unsigned_func_ptr)(void *context, - int32_t m_buffer_handle, - int32_t big_int_handle); - int32_t (*mbuffer_from_big_int_signed_func_ptr)(void *context, - int32_t m_buffer_handle, - int32_t big_int_handle); + int32_t (*mbuffer_append_bytes_func_ptr)(void *context, int32_t accumulator_handle, int32_t data_offset, int32_t data_length); + int32_t (*mbuffer_to_big_int_unsigned_func_ptr)(void *context, int32_t m_buffer_handle, int32_t big_int_handle); + int32_t (*mbuffer_to_big_int_signed_func_ptr)(void *context, int32_t m_buffer_handle, int32_t big_int_handle); + int32_t (*mbuffer_from_big_int_unsigned_func_ptr)(void *context, int32_t m_buffer_handle, int32_t big_int_handle); + int32_t (*mbuffer_from_big_int_signed_func_ptr)(void *context, int32_t m_buffer_handle, int32_t big_int_handle); int64_t (*mbuffer_to_small_int_unsigned_func_ptr)(void *context, int32_t m_buffer_handle); int64_t (*mbuffer_to_small_int_signed_func_ptr)(void *context, int32_t m_buffer_handle); - void (*mbuffer_from_small_int_unsigned_func_ptr)(void *context, - int32_t m_buffer_handle, - int64_t value); - void (*mbuffer_from_small_int_signed_func_ptr)(void *context, - int32_t m_buffer_handle, - int64_t value); - int32_t (*mbuffer_to_big_float_func_ptr)(void *context, - int32_t m_buffer_handle, - int32_t big_float_handle); - int32_t (*mbuffer_from_big_float_func_ptr)(void *context, - int32_t m_buffer_handle, - int32_t big_float_handle); + void (*mbuffer_from_small_int_unsigned_func_ptr)(void *context, int32_t m_buffer_handle, int64_t value); + void (*mbuffer_from_small_int_signed_func_ptr)(void *context, int32_t m_buffer_handle, int64_t value); + int32_t (*mbuffer_to_big_float_func_ptr)(void *context, int32_t m_buffer_handle, int32_t big_float_handle); + int32_t (*mbuffer_from_big_float_func_ptr)(void *context, int32_t m_buffer_handle, int32_t big_float_handle); int32_t (*mbuffer_storage_store_func_ptr)(void *context, int32_t key_handle, int32_t source_handle); - int32_t (*mbuffer_storage_load_func_ptr)(void *context, - int32_t key_handle, - int32_t destination_handle); - void (*mbuffer_storage_load_from_address_func_ptr)(void *context, - int32_t address_handle, - int32_t key_handle, - int32_t destination_handle); + int32_t (*mbuffer_storage_load_func_ptr)(void *context, int32_t key_handle, int32_t destination_handle); + void (*mbuffer_storage_load_from_address_func_ptr)(void *context, int32_t address_handle, int32_t key_handle, int32_t destination_handle); int32_t (*mbuffer_get_argument_func_ptr)(void *context, int32_t id, int32_t destination_handle); int32_t (*mbuffer_finish_func_ptr)(void *context, int32_t source_handle); int32_t (*mbuffer_set_random_func_ptr)(void *context, int32_t destination_handle, int32_t length); int32_t (*managed_map_new_func_ptr)(void *context); - int32_t (*managed_map_put_func_ptr)(void *context, - int32_t m_map_handle, - int32_t key_handle, - int32_t value_handle); - int32_t (*managed_map_get_func_ptr)(void *context, - int32_t m_map_handle, - int32_t key_handle, - int32_t out_value_handle); - int32_t (*managed_map_remove_func_ptr)(void *context, - int32_t m_map_handle, - int32_t key_handle, - int32_t out_value_handle); + int32_t (*managed_map_put_func_ptr)(void *context, int32_t m_map_handle, int32_t key_handle, int32_t value_handle); + int32_t (*managed_map_get_func_ptr)(void *context, int32_t m_map_handle, int32_t key_handle, int32_t out_value_handle); + int32_t (*managed_map_remove_func_ptr)(void *context, int32_t m_map_handle, int32_t key_handle, int32_t out_value_handle); int32_t (*managed_map_contains_func_ptr)(void *context, int32_t m_map_handle, int32_t key_handle); int64_t (*small_int_get_unsigned_argument_func_ptr)(void *context, int32_t id); int64_t (*small_int_get_signed_argument_func_ptr)(void *context, int32_t id); void (*small_int_finish_unsigned_func_ptr)(void *context, int64_t value); void (*small_int_finish_signed_func_ptr)(void *context, int64_t value); - int32_t (*small_int_storage_store_unsigned_func_ptr)(void *context, - int32_t key_offset, - int32_t key_length, - int64_t value); - int32_t (*small_int_storage_store_signed_func_ptr)(void *context, - int32_t key_offset, - int32_t key_length, - int64_t value); - int64_t (*small_int_storage_load_unsigned_func_ptr)(void *context, - int32_t key_offset, - int32_t key_length); - int64_t (*small_int_storage_load_signed_func_ptr)(void *context, - int32_t key_offset, - int32_t key_length); + int32_t (*small_int_storage_store_unsigned_func_ptr)(void *context, int32_t key_offset, int32_t key_length, int64_t value); + int32_t (*small_int_storage_store_signed_func_ptr)(void *context, int32_t key_offset, int32_t key_length, int64_t value); + int64_t (*small_int_storage_load_unsigned_func_ptr)(void *context, int32_t key_offset, int32_t key_length); + int64_t (*small_int_storage_load_signed_func_ptr)(void *context, int32_t key_offset, int32_t key_length); int64_t (*int64get_argument_func_ptr)(void *context, int32_t id); void (*int64finish_func_ptr)(void *context, int64_t value); - int32_t (*int64storage_store_func_ptr)(void *context, - int32_t key_offset, - int32_t key_length, - int64_t value); + int32_t (*int64storage_store_func_ptr)(void *context, int32_t key_offset, int32_t key_length, int64_t value); int64_t (*int64storage_load_func_ptr)(void *context, int32_t key_offset, int32_t key_length); - int32_t (*sha256_func_ptr)(void *context, - int32_t data_offset, - int32_t length, - int32_t result_offset); + int32_t (*sha256_func_ptr)(void *context, int32_t data_offset, int32_t length, int32_t result_offset); int32_t (*managed_sha256_func_ptr)(void *context, int32_t input_handle, int32_t output_handle); - int32_t (*keccak256_func_ptr)(void *context, - int32_t data_offset, - int32_t length, - int32_t result_offset); + int32_t (*keccak256_func_ptr)(void *context, int32_t data_offset, int32_t length, int32_t result_offset); int32_t (*managed_keccak256_func_ptr)(void *context, int32_t input_handle, int32_t output_handle); - int32_t (*ripemd160_func_ptr)(void *context, - int32_t data_offset, - int32_t length, - int32_t result_offset); + int32_t (*ripemd160_func_ptr)(void *context, int32_t data_offset, int32_t length, int32_t result_offset); int32_t (*managed_ripemd160_func_ptr)(void *context, int32_t input_handle, int32_t output_handle); - int32_t (*verify_bls_func_ptr)(void *context, - int32_t key_offset, - int32_t message_offset, - int32_t message_length, - int32_t sig_offset); - int32_t (*managed_verify_bls_func_ptr)(void *context, - int32_t key_handle, - int32_t message_handle, - int32_t sig_handle); - int32_t (*verify_ed25519_func_ptr)(void *context, - int32_t key_offset, - int32_t message_offset, - int32_t message_length, - int32_t sig_offset); - int32_t (*managed_verify_ed25519_func_ptr)(void *context, - int32_t key_handle, - int32_t message_handle, - int32_t sig_handle); - int32_t (*verify_custom_secp256k1_func_ptr)(void *context, - int32_t key_offset, - int32_t key_length, - int32_t message_offset, - int32_t message_length, - int32_t sig_offset, - int32_t hash_type); - int32_t (*managed_verify_custom_secp256k1_func_ptr)(void *context, - int32_t key_handle, - int32_t message_handle, - int32_t sig_handle, - int32_t hash_type); - int32_t (*verify_secp256k1_func_ptr)(void *context, - int32_t key_offset, - int32_t key_length, - int32_t message_offset, - int32_t message_length, - int32_t sig_offset); - int32_t (*managed_verify_secp256k1_func_ptr)(void *context, - int32_t key_handle, - int32_t message_handle, - int32_t sig_handle); - int32_t (*encode_secp256k1_der_signature_func_ptr)(void *context, - int32_t r_offset, - int32_t r_length, - int32_t s_offset, - int32_t s_length, - int32_t sig_offset); - int32_t (*managed_encode_secp256k1_der_signature_func_ptr)(void *context, - int32_t r_handle, - int32_t s_handle, - int32_t sig_handle); - void (*add_ec_func_ptr)(void *context, - int32_t x_result_handle, - int32_t y_result_handle, - int32_t ec_handle, - int32_t fst_point_xhandle, - int32_t fst_point_yhandle, - int32_t snd_point_xhandle, - int32_t snd_point_yhandle); - void (*double_ec_func_ptr)(void *context, - int32_t x_result_handle, - int32_t y_result_handle, - int32_t ec_handle, - int32_t point_xhandle, - int32_t point_yhandle); - int32_t (*is_on_curve_ec_func_ptr)(void *context, - int32_t ec_handle, - int32_t point_xhandle, - int32_t point_yhandle); - int32_t (*scalar_base_mult_ec_func_ptr)(void *context, - int32_t x_result_handle, - int32_t y_result_handle, - int32_t ec_handle, - int32_t data_offset, - int32_t length); - int32_t (*managed_scalar_base_mult_ec_func_ptr)(void *context, - int32_t x_result_handle, - int32_t y_result_handle, - int32_t ec_handle, - int32_t data_handle); - int32_t (*scalar_mult_ec_func_ptr)(void *context, - int32_t x_result_handle, - int32_t y_result_handle, - int32_t ec_handle, - int32_t point_xhandle, - int32_t point_yhandle, - int32_t data_offset, - int32_t length); - int32_t (*managed_scalar_mult_ec_func_ptr)(void *context, - int32_t x_result_handle, - int32_t y_result_handle, - int32_t ec_handle, - int32_t point_xhandle, - int32_t point_yhandle, - int32_t data_handle); - int32_t (*marshal_ec_func_ptr)(void *context, - int32_t x_pair_handle, - int32_t y_pair_handle, - int32_t ec_handle, - int32_t result_offset); - int32_t (*managed_marshal_ec_func_ptr)(void *context, - int32_t x_pair_handle, - int32_t y_pair_handle, - int32_t ec_handle, - int32_t result_handle); - int32_t (*marshal_compressed_ec_func_ptr)(void *context, - int32_t x_pair_handle, - int32_t y_pair_handle, - int32_t ec_handle, - int32_t result_offset); - int32_t (*managed_marshal_compressed_ec_func_ptr)(void *context, - int32_t x_pair_handle, - int32_t y_pair_handle, - int32_t ec_handle, - int32_t result_handle); - int32_t (*unmarshal_ec_func_ptr)(void *context, - int32_t x_result_handle, - int32_t y_result_handle, - int32_t ec_handle, - int32_t data_offset, - int32_t length); - int32_t (*managed_unmarshal_ec_func_ptr)(void *context, - int32_t x_result_handle, - int32_t y_result_handle, - int32_t ec_handle, - int32_t data_handle); - int32_t (*unmarshal_compressed_ec_func_ptr)(void *context, - int32_t x_result_handle, - int32_t y_result_handle, - int32_t ec_handle, - int32_t data_offset, - int32_t length); - int32_t (*managed_unmarshal_compressed_ec_func_ptr)(void *context, - int32_t x_result_handle, - int32_t y_result_handle, - int32_t ec_handle, - int32_t data_handle); - int32_t (*generate_key_ec_func_ptr)(void *context, - int32_t x_pub_key_handle, - int32_t y_pub_key_handle, - int32_t ec_handle, - int32_t result_offset); - int32_t (*managed_generate_key_ec_func_ptr)(void *context, - int32_t x_pub_key_handle, - int32_t y_pub_key_handle, - int32_t ec_handle, - int32_t result_handle); + int32_t (*verify_bls_func_ptr)(void *context, int32_t key_offset, int32_t message_offset, int32_t message_length, int32_t sig_offset); + int32_t (*managed_verify_bls_func_ptr)(void *context, int32_t key_handle, int32_t message_handle, int32_t sig_handle); + int32_t (*verify_ed25519_func_ptr)(void *context, int32_t key_offset, int32_t message_offset, int32_t message_length, int32_t sig_offset); + int32_t (*managed_verify_ed25519_func_ptr)(void *context, int32_t key_handle, int32_t message_handle, int32_t sig_handle); + int32_t (*verify_custom_secp256k1_func_ptr)(void *context, int32_t key_offset, int32_t key_length, int32_t message_offset, int32_t message_length, int32_t sig_offset, int32_t hash_type); + int32_t (*managed_verify_custom_secp256k1_func_ptr)(void *context, int32_t key_handle, int32_t message_handle, int32_t sig_handle, int32_t hash_type); + int32_t (*verify_secp256k1_func_ptr)(void *context, int32_t key_offset, int32_t key_length, int32_t message_offset, int32_t message_length, int32_t sig_offset); + int32_t (*managed_verify_secp256k1_func_ptr)(void *context, int32_t key_handle, int32_t message_handle, int32_t sig_handle); + int32_t (*encode_secp256k1_der_signature_func_ptr)(void *context, int32_t r_offset, int32_t r_length, int32_t s_offset, int32_t s_length, int32_t sig_offset); + int32_t (*managed_encode_secp256k1_der_signature_func_ptr)(void *context, int32_t r_handle, int32_t s_handle, int32_t sig_handle); + void (*add_ec_func_ptr)(void *context, int32_t x_result_handle, int32_t y_result_handle, int32_t ec_handle, int32_t fst_point_xhandle, int32_t fst_point_yhandle, int32_t snd_point_xhandle, int32_t snd_point_yhandle); + void (*double_ec_func_ptr)(void *context, int32_t x_result_handle, int32_t y_result_handle, int32_t ec_handle, int32_t point_xhandle, int32_t point_yhandle); + int32_t (*is_on_curve_ec_func_ptr)(void *context, int32_t ec_handle, int32_t point_xhandle, int32_t point_yhandle); + int32_t (*scalar_base_mult_ec_func_ptr)(void *context, int32_t x_result_handle, int32_t y_result_handle, int32_t ec_handle, int32_t data_offset, int32_t length); + int32_t (*managed_scalar_base_mult_ec_func_ptr)(void *context, int32_t x_result_handle, int32_t y_result_handle, int32_t ec_handle, int32_t data_handle); + int32_t (*scalar_mult_ec_func_ptr)(void *context, int32_t x_result_handle, int32_t y_result_handle, int32_t ec_handle, int32_t point_xhandle, int32_t point_yhandle, int32_t data_offset, int32_t length); + int32_t (*managed_scalar_mult_ec_func_ptr)(void *context, int32_t x_result_handle, int32_t y_result_handle, int32_t ec_handle, int32_t point_xhandle, int32_t point_yhandle, int32_t data_handle); + int32_t (*marshal_ec_func_ptr)(void *context, int32_t x_pair_handle, int32_t y_pair_handle, int32_t ec_handle, int32_t result_offset); + int32_t (*managed_marshal_ec_func_ptr)(void *context, int32_t x_pair_handle, int32_t y_pair_handle, int32_t ec_handle, int32_t result_handle); + int32_t (*marshal_compressed_ec_func_ptr)(void *context, int32_t x_pair_handle, int32_t y_pair_handle, int32_t ec_handle, int32_t result_offset); + int32_t (*managed_marshal_compressed_ec_func_ptr)(void *context, int32_t x_pair_handle, int32_t y_pair_handle, int32_t ec_handle, int32_t result_handle); + int32_t (*unmarshal_ec_func_ptr)(void *context, int32_t x_result_handle, int32_t y_result_handle, int32_t ec_handle, int32_t data_offset, int32_t length); + int32_t (*managed_unmarshal_ec_func_ptr)(void *context, int32_t x_result_handle, int32_t y_result_handle, int32_t ec_handle, int32_t data_handle); + int32_t (*unmarshal_compressed_ec_func_ptr)(void *context, int32_t x_result_handle, int32_t y_result_handle, int32_t ec_handle, int32_t data_offset, int32_t length); + int32_t (*managed_unmarshal_compressed_ec_func_ptr)(void *context, int32_t x_result_handle, int32_t y_result_handle, int32_t ec_handle, int32_t data_handle); + int32_t (*generate_key_ec_func_ptr)(void *context, int32_t x_pub_key_handle, int32_t y_pub_key_handle, int32_t ec_handle, int32_t result_offset); + int32_t (*managed_generate_key_ec_func_ptr)(void *context, int32_t x_pub_key_handle, int32_t y_pub_key_handle, int32_t ec_handle, int32_t result_handle); int32_t (*create_ec_func_ptr)(void *context, int32_t data_offset, int32_t data_length); int32_t (*managed_create_ec_func_ptr)(void *context, int32_t data_handle); int32_t (*get_curve_length_ec_func_ptr)(void *context, int32_t ec_handle); int32_t (*get_priv_key_byte_length_ec_func_ptr)(void *context, int32_t ec_handle); - int32_t (*elliptic_curve_get_values_func_ptr)(void *context, - int32_t ec_handle, - int32_t field_order_handle, - int32_t base_point_order_handle, - int32_t eq_constant_handle, - int32_t x_base_point_handle, - int32_t y_base_point_handle); - int32_t (*managed_verify_secp256r1_func_ptr)(void *context, - int32_t key_handle, - int32_t message_handle, - int32_t sig_handle); - int32_t (*managed_verify_blssignature_share_func_ptr)(void *context, - int32_t key_handle, - int32_t message_handle, - int32_t sig_handle); - int32_t (*managed_verify_blsaggregated_signature_func_ptr)(void *context, - int32_t key_handle, - int32_t message_handle, - int32_t sig_handle); + int32_t (*elliptic_curve_get_values_func_ptr)(void *context, int32_t ec_handle, int32_t field_order_handle, int32_t base_point_order_handle, int32_t eq_constant_handle, int32_t x_base_point_handle, int32_t y_base_point_handle); + int32_t (*managed_verify_secp256r1_func_ptr)(void *context, int32_t key_handle, int32_t message_handle, int32_t sig_handle); + int32_t (*managed_verify_blssignature_share_func_ptr)(void *context, int32_t key_handle, int32_t message_handle, int32_t sig_handle); + int32_t (*managed_verify_blsaggregated_signature_func_ptr)(void *context, int32_t key_handle, int32_t message_handle, int32_t sig_handle); void (*activate_unsafe_mode_func_ptr)(void *context); void (*deactivate_unsafe_mode_func_ptr)(void *context); int32_t (*managed_get_num_errors_func_ptr)(void *context); @@ -917,11 +318,11 @@ typedef struct vm_exec_vm_hook_c_func_pointers { void (*managed_get_last_error_func_ptr)(void *context, int32_t error_handle); } vm_exec_vm_hook_c_func_pointers; -typedef struct vm_exec_compilation_options_t { +typedef struct { } vm_exec_compilation_options_t; -typedef struct vm_exec_opcode_cost_t { +typedef struct { } vm_exec_opcode_cost_t; @@ -936,8 +337,7 @@ typedef struct vm_exec_opcode_cost_t { * * C API function, works with raw object pointers. */ -enum vm_exec_result_t vm_exec_instance_set_breakpoint_value(const struct vm_exec_instance_t *instance_ptr, - uint64_t value); +vm_exec_result_t vm_exec_instance_set_breakpoint_value(const vm_exec_instance_t *instance_ptr, uint64_t value); /** * Returns the runtime breakpoint value from the given instance. @@ -946,7 +346,7 @@ enum vm_exec_result_t vm_exec_instance_set_breakpoint_value(const struct vm_exec * * C API function, works with raw object pointers. */ -uint64_t vm_exec_instance_get_breakpoint_value(const struct vm_exec_instance_t *instance_ptr); +uint64_t vm_exec_instance_get_breakpoint_value(const vm_exec_instance_t *instance_ptr); /** * Gets the length in bytes of the last error if any. @@ -985,8 +385,7 @@ int vm_exec_last_error_message(char *dest_buffer, int dest_buffer_len); * * C API function, works with raw object pointers. */ -enum vm_exec_result_t vm_exec_new_executor(struct vm_exec_executor_t **executor, - struct vm_exec_vm_hook_c_func_pointers **vm_hook_pointers_ptr_ptr); +vm_exec_result_t vm_exec_new_executor(vm_exec_executor_t **executor, vm_exec_vm_hook_c_func_pointers **vm_hook_pointers_ptr_ptr); /** * Forces reinstalling the sighandlers. @@ -1011,8 +410,7 @@ void vm_force_sighandler_reinstall(void); * * C API function, works with raw object pointers. */ -enum vm_exec_result_t vm_exec_executor_set_vm_hooks_ptr(struct vm_exec_executor_t *executor_ptr, - void *vm_hooks_ptr); +vm_exec_result_t vm_exec_executor_set_vm_hooks_ptr(vm_exec_executor_t *executor_ptr, void *vm_hooks_ptr); /** * Destroys a VM executor object. @@ -1021,7 +419,7 @@ enum vm_exec_result_t vm_exec_executor_set_vm_hooks_ptr(struct vm_exec_executor_ * * C API function, works with raw object pointers. */ -void vm_exec_executor_destroy(struct vm_exec_executor_t *executor_ptr); +void vm_exec_executor_destroy(vm_exec_executor_t *executor_ptr); /** * Creates a new VM executor instance. @@ -1032,11 +430,7 @@ void vm_exec_executor_destroy(struct vm_exec_executor_t *executor_ptr); * * C API function, works with raw object pointers. */ -enum vm_exec_result_t vm_exec_new_instance(struct vm_exec_executor_t *executor_ptr, - struct vm_exec_instance_t **instance_ptr_ptr, - uint8_t *wasm_bytes_ptr, - uint32_t wasm_bytes_len, - const struct vm_exec_compilation_options_t *options_ptr); +vm_exec_result_t vm_exec_new_instance(vm_exec_executor_t *executor_ptr, vm_exec_instance_t **instance_ptr_ptr, uint8_t *wasm_bytes_ptr, uint32_t wasm_bytes_len, const vm_exec_compilation_options_t *options_ptr); /** * Calls an exported function of a WebAssembly instance by `name` @@ -1057,8 +451,7 @@ enum vm_exec_result_t vm_exec_new_instance(struct vm_exec_executor_t *executor_p * * C API function, works with raw object pointers. */ -enum vm_exec_result_t vm_exec_instance_call(struct vm_exec_instance_t *instance_ptr, - const char *func_name_ptr); +vm_exec_result_t vm_exec_instance_call(vm_exec_instance_t *instance_ptr, const char *func_name_ptr); /** * Checks that all public module functions (SC endpoints) have no arguments or results. @@ -1069,7 +462,7 @@ enum vm_exec_result_t vm_exec_instance_call(struct vm_exec_instance_t *instance_ * * C API function, works with raw object pointers. */ -enum vm_exec_result_t vm_check_signatures(struct vm_exec_instance_t *instance_ptr); +vm_exec_result_t vm_check_signatures(vm_exec_instance_t *instance_ptr); /** * Checks whether SC has an endpoint with given name. @@ -1078,8 +471,7 @@ enum vm_exec_result_t vm_check_signatures(struct vm_exec_instance_t *instance_pt * * C API function, works with raw object pointers. */ -int vm_exec_instance_has_function(struct vm_exec_instance_t *instance_ptr, - const char *func_name_ptr); +int vm_exec_instance_has_function(vm_exec_instance_t *instance_ptr, const char *func_name_ptr); /** * Checks whether SC has an endpoint with given name. @@ -1088,8 +480,7 @@ int vm_exec_instance_has_function(struct vm_exec_instance_t *instance_ptr, * * C API function, works with raw object pointers. */ -int vm_exec_instance_has_imported_function(struct vm_exec_instance_t *instance_ptr, - const char *func_name_ptr); +int vm_exec_instance_has_imported_function(vm_exec_instance_t *instance_ptr, const char *func_name_ptr); /** * Required to be able to extract all SC endpoint names. See `vm_exported_function_names`. @@ -1098,7 +489,7 @@ int vm_exec_instance_has_imported_function(struct vm_exec_instance_t *instance_p * * C API function, works with raw object pointers. */ -int vm_exported_function_names_length(struct vm_exec_instance_t *instance_ptr); +int vm_exported_function_names_length(vm_exec_instance_t *instance_ptr); /** * Returns all SC endpoint names, separated by pipes. @@ -1113,9 +504,7 @@ int vm_exported_function_names_length(struct vm_exec_instance_t *instance_ptr); * * C API function, works with raw object pointers. */ -int vm_exported_function_names(struct vm_exec_instance_t *instance_ptr, - char *dest_buffer, - int dest_buffer_len); +int vm_exported_function_names(vm_exec_instance_t *instance_ptr, char *dest_buffer, int dest_buffer_len); /** * Frees memory for the given `vm_exec_instance_t`. @@ -1129,7 +518,7 @@ int vm_exported_function_names(struct vm_exec_instance_t *instance_ptr, * * C API function, works with raw object pointers. */ -void vm_exec_instance_destroy(struct vm_exec_instance_t *instance_ptr); +void vm_exec_instance_destroy(vm_exec_instance_t *instance_ptr); /** * Resets an instance, cleaning memories and globals. @@ -1138,7 +527,7 @@ void vm_exec_instance_destroy(struct vm_exec_instance_t *instance_ptr); * * C API function, works with raw object pointers. */ -enum vm_exec_result_t vm_exec_instance_reset(struct vm_exec_instance_t *instance_ptr); +vm_exec_result_t vm_exec_instance_reset(vm_exec_instance_t *instance_ptr); /** * Caches an instance. @@ -1147,9 +536,7 @@ enum vm_exec_result_t vm_exec_instance_reset(struct vm_exec_instance_t *instance * * C API function, works with raw object pointers. */ -enum vm_exec_result_t vm_exec_instance_cache(const struct vm_exec_instance_t *instance_ptr, - const uint8_t **cache_bytes_ptr, - uint32_t *cache_bytes_len); +vm_exec_result_t vm_exec_instance_cache(const vm_exec_instance_t *instance_ptr, const uint8_t **cache_bytes_ptr, uint32_t *cache_bytes_len); /** * Creates a new VM executor instance from cache. @@ -1160,16 +547,12 @@ enum vm_exec_result_t vm_exec_instance_cache(const struct vm_exec_instance_t *in * * C API function, works with raw object pointers. */ -enum vm_exec_result_t vm_exec_instance_from_cache(struct vm_exec_executor_t *executor_ptr, - struct vm_exec_instance_t **instance_ptr_ptr, - uint8_t *cache_bytes_ptr, - uint32_t cache_bytes_len, - const struct vm_exec_compilation_options_t *options_ptr); +vm_exec_result_t vm_exec_instance_from_cache(vm_exec_executor_t *executor_ptr, vm_exec_instance_t **instance_ptr_ptr, uint8_t *cache_bytes_ptr, uint32_t cache_bytes_len, const vm_exec_compilation_options_t *options_ptr); /** * Sets the log level. */ -enum vm_exec_result_t vm_exec_set_log_level(uint64_t value); +vm_exec_result_t vm_exec_set_log_level(uint64_t value); /** * Gets the size in bytes of the memory data. @@ -1180,7 +563,7 @@ enum vm_exec_result_t vm_exec_set_log_level(uint64_t value); * * C API function, works with raw object pointers. */ -uint64_t vm_exec_instance_memory_data_length(struct vm_exec_instance_t *instance_ptr); +uint64_t vm_exec_instance_memory_data_length(vm_exec_instance_t *instance_ptr); /** * Gets a pointer to the beginning of the contiguous memory data @@ -1195,7 +578,7 @@ uint64_t vm_exec_instance_memory_data_length(struct vm_exec_instance_t *instance * * C API function, works with raw object pointers. */ -uint8_t *vm_exec_instance_memory_data(struct vm_exec_instance_t *instance_ptr); +uint8_t *vm_exec_instance_memory_data(vm_exec_instance_t *instance_ptr); /** * Grows a memory by the given number of pages (of 65Kb each). @@ -1209,8 +592,7 @@ uint8_t *vm_exec_instance_memory_data(struct vm_exec_instance_t *instance_ptr); * * C API function, works with raw object pointers. */ -enum vm_exec_result_t vm_exec_instance_memory_grow(struct vm_exec_instance_t *instance_ptr, - uint32_t by_num_pages); +vm_exec_result_t vm_exec_instance_memory_grow(vm_exec_instance_t *instance_ptr, uint32_t by_num_pages); /** * Sets the opcode costs for the given executor. @@ -1223,9 +605,7 @@ enum vm_exec_result_t vm_exec_instance_memory_grow(struct vm_exec_instance_t *in * * C API function, works with raw object pointers. */ -enum vm_exec_result_t vm_exec_set_opcode_config(struct vm_exec_executor_t *executor_ptr, - int32_t opcode_version_code, - const struct vm_exec_opcode_cost_t *opcode_cost_ptr); +vm_exec_result_t vm_exec_set_opcode_config(vm_exec_executor_t *executor_ptr, int32_t opcode_version_code, const vm_exec_opcode_cost_t *opcode_cost_ptr); /** * Sets the number of points(gas) limit for the given instance. @@ -1238,8 +618,7 @@ enum vm_exec_result_t vm_exec_set_opcode_config(struct vm_exec_executor_t *execu * * C API function, works with raw object pointers. */ -enum vm_exec_result_t vm_exec_instance_set_points_limit(const struct vm_exec_instance_t *instance_ptr, - uint64_t limit); +vm_exec_result_t vm_exec_instance_set_points_limit(const vm_exec_instance_t *instance_ptr, uint64_t limit); /** * Sets the number of points(gas) for the given instance. @@ -1252,8 +631,7 @@ enum vm_exec_result_t vm_exec_instance_set_points_limit(const struct vm_exec_ins * * C API function, works with raw object pointers. */ -enum vm_exec_result_t vm_exec_instance_set_points_used(const struct vm_exec_instance_t *instance_ptr, - uint64_t points); +vm_exec_result_t vm_exec_instance_set_points_used(const vm_exec_instance_t *instance_ptr, uint64_t points); /** * Returns the number of points(gas) used by the given instance. @@ -1262,4 +640,4 @@ enum vm_exec_result_t vm_exec_instance_set_points_used(const struct vm_exec_inst * * C API function, works with raw object pointers. */ -uint64_t vm_exec_instance_get_points_used(const struct vm_exec_instance_t *instance_ptr); +uint64_t vm_exec_instance_get_points_used(const vm_exec_instance_t *instance_ptr); From 0275f6058d28e50508653cffb98e4b390e54cd0c Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Fri, 25 Sep 2026 11:01:19 +0300 Subject: [PATCH 32/35] ffi hardening: compilation options --- c-api/libvmexeccapi.h | 17 ++++++++++++- c-api/src/capi_compilation_options.rs | 36 +++++++++++++++++++++++++++ c-api/src/capi_instance.rs | 14 +++++------ c-api/src/capi_instance_cache.rs | 11 ++++---- c-api/src/lib.rs | 1 + 5 files changed, 65 insertions(+), 14 deletions(-) create mode 100644 c-api/src/capi_compilation_options.rs diff --git a/c-api/libvmexeccapi.h b/c-api/libvmexeccapi.h index 4cee9a6..2a45813 100644 --- a/c-api/libvmexeccapi.h +++ b/c-api/libvmexeccapi.h @@ -318,8 +318,23 @@ typedef struct { void (*managed_get_last_error_func_ptr)(void *context, int32_t error_handle); } vm_exec_vm_hook_c_func_pointers; +/** + * FFI-safe mirror of `CompilationOptionsLegacy`. + * + * This is a distinct type rather than a cast of `CompilationOptionsLegacy` + * itself, so that the general-purpose struct is free to change shape + * without touching the C ABI, and vice versa. Fields that are `usize` on + * the Rust side are fixed to `u64` here, since `usize` has no guaranteed + * width across host platforms. + */ typedef struct { - + uint64_t gas_limit; + uint64_t unmetered_locals; + uint64_t max_memory_grow; + uint64_t max_memory_grow_delta; + bool opcode_trace; + bool metering; + bool runtime_breakpoints; } vm_exec_compilation_options_t; typedef struct { diff --git a/c-api/src/capi_compilation_options.rs b/c-api/src/capi_compilation_options.rs new file mode 100644 index 0000000..704bf89 --- /dev/null +++ b/c-api/src/capi_compilation_options.rs @@ -0,0 +1,36 @@ +//! FFI-safe mirror of `CompilationOptionsLegacy`. + +use multiversx_chain_vm_executor::CompilationOptionsLegacy; + +/// FFI-safe mirror of `CompilationOptionsLegacy`. +/// +/// This is a distinct type rather than a cast of `CompilationOptionsLegacy` +/// itself, so that the general-purpose struct is free to change shape +/// without touching the C ABI, and vice versa. Fields that are `usize` on +/// the Rust side are fixed to `u64` here, since `usize` has no guaranteed +/// width across host platforms. +#[allow(non_camel_case_types)] +#[repr(C)] +pub struct vm_exec_compilation_options_t { + pub gas_limit: u64, + pub unmetered_locals: u64, + pub max_memory_grow: u64, + pub max_memory_grow_delta: u64, + pub opcode_trace: bool, + pub metering: bool, + pub runtime_breakpoints: bool, +} + +impl vm_exec_compilation_options_t { + pub(crate) fn to_legacy(&self) -> CompilationOptionsLegacy { + CompilationOptionsLegacy { + gas_limit: self.gas_limit, + unmetered_locals: self.unmetered_locals as usize, + max_memory_grow: self.max_memory_grow as usize, + max_memory_grow_delta: self.max_memory_grow_delta as usize, + opcode_trace: self.opcode_trace, + metering: self.metering, + runtime_breakpoints: self.runtime_breakpoints, + } + } +} diff --git a/c-api/src/capi_instance.rs b/c-api/src/capi_instance.rs index 5e1edab..d38544e 100644 --- a/c-api/src/capi_instance.rs +++ b/c-api/src/capi_instance.rs @@ -1,13 +1,14 @@ //! Instantiate a module, call functions, and read exports. use crate::{ + capi_compilation_options::vm_exec_compilation_options_t, capi_executor::{CapiExecutor, vm_exec_executor_t}, service_singleton::with_service, string_copy, vm_exec_result_t, }; use libc::{c_char, c_int}; use meta::capi_safe_unwind; -use multiversx_chain_vm_executor::{CompilationOptionsLegacy, InstanceLegacy}; +use multiversx_chain_vm_executor::InstanceLegacy; use std::{ffi::CStr, slice}; /// Opaque pointer to a `wasmer_runtime::Instance` value in Rust. @@ -19,10 +20,6 @@ use std::{ffi::CStr, slice}; #[repr(C)] pub struct vm_exec_instance_t; -#[allow(non_camel_case_types)] -#[repr(C)] -pub struct vm_exec_compilation_options_t; - pub struct CapiInstance { pub(crate) content: Box, } @@ -51,13 +48,14 @@ pub unsafe extern "C" fn vm_exec_new_instance( return vm_exec_result_t::VM_EXEC_ERROR; } + return_if_ptr_null!(options_ptr, "compilation options ptr is null"); + let wasm_bytes: &[u8] = unsafe { slice::from_raw_parts(wasm_bytes_ptr, wasm_bytes_len as usize) }; - let compilation_options: &CompilationOptionsLegacy = - unsafe { &*(options_ptr as *const CompilationOptionsLegacy) }; + let compilation_options = unsafe { (*options_ptr).to_legacy() }; let instance_result = capi_executor .content - .new_instance(wasm_bytes, compilation_options); + .new_instance(wasm_bytes, &compilation_options); match instance_result { Ok(instance_box) => { let capi_instance = CapiInstance { diff --git a/c-api/src/capi_instance_cache.rs b/c-api/src/capi_instance_cache.rs index 807e1cf..58a0380 100644 --- a/c-api/src/capi_instance_cache.rs +++ b/c-api/src/capi_instance_cache.rs @@ -1,11 +1,11 @@ use std::slice; use meta::capi_safe_unwind; -use multiversx_chain_vm_executor::CompilationOptionsLegacy; use crate::{ + capi_compilation_options::vm_exec_compilation_options_t, capi_executor::{CapiExecutor, vm_exec_executor_t}, - capi_instance::{CapiInstance, vm_exec_compilation_options_t, vm_exec_instance_t}, + capi_instance::{CapiInstance, vm_exec_instance_t}, service_singleton::with_service, vm_exec_result_t, }; @@ -68,13 +68,14 @@ pub unsafe extern "C" fn vm_exec_instance_from_cache( return vm_exec_result_t::VM_EXEC_ERROR; } + return_if_ptr_null!(options_ptr, "compilation options ptr is null"); + let cache_bytes: &[u8] = unsafe { slice::from_raw_parts(cache_bytes_ptr, cache_bytes_len as usize) }; - let compilation_options: &CompilationOptionsLegacy = - unsafe { &*(options_ptr as *const CompilationOptionsLegacy) }; + let compilation_options = unsafe { (*options_ptr).to_legacy() }; let instance_result = capi_executor .content - .new_instance_from_cache(cache_bytes, compilation_options); + .new_instance_from_cache(cache_bytes, &compilation_options); match instance_result { Ok(instance_box) => { let capi_instance = CapiInstance { diff --git a/c-api/src/lib.rs b/c-api/src/lib.rs index 1329102..c3a0ad8 100644 --- a/c-api/src/lib.rs +++ b/c-api/src/lib.rs @@ -3,6 +3,7 @@ mod macros; mod basic_types; pub mod capi_breakpoints; +pub mod capi_compilation_options; pub mod capi_error; pub mod capi_executor; pub mod capi_instance; From eb527718250969192b8171cf4004450fefba8d38 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Fri, 25 Sep 2026 12:07:57 +0300 Subject: [PATCH 33/35] ffi hardening: opcode cost --- c-api/libvmexeccapi.h | 140 ++++++++++++++++- c-api/src/capi_metering.rs | 11 +- c-api/src/capi_opcode_cost.rs | 288 ++++++++++++++++++++++++++++++++++ c-api/src/lib.rs | 1 + 4 files changed, 432 insertions(+), 8 deletions(-) create mode 100644 c-api/src/capi_opcode_cost.rs diff --git a/c-api/libvmexeccapi.h b/c-api/libvmexeccapi.h index 2a45813..c0f5b96 100644 --- a/c-api/libvmexeccapi.h +++ b/c-api/libvmexeccapi.h @@ -337,8 +337,146 @@ typedef struct { bool runtime_breakpoints; } vm_exec_compilation_options_t; +/** + * FFI-safe mirror of `OpcodeCost`. + * + * This is a distinct type rather than a cast of `OpcodeCost` itself, so that + * the general-purpose struct is free to change shape without touching the C + * ABI, and vice versa. + */ typedef struct { - + uint32_t opcode_block; + uint32_t opcode_br; + uint32_t opcode_brif; + uint32_t opcode_brtable; + uint32_t opcode_call; + uint32_t opcode_callindirect; + uint32_t opcode_catch; + uint32_t opcode_catchall; + uint32_t opcode_delegate; + uint32_t opcode_drop; + uint32_t opcode_else; + uint32_t opcode_end; + uint32_t opcode_globalget; + uint32_t opcode_globalset; + uint32_t opcode_i32add; + uint32_t opcode_i32and; + uint32_t opcode_i32clz; + uint32_t opcode_i32const; + uint32_t opcode_i32ctz; + uint32_t opcode_i32divs; + uint32_t opcode_i32divu; + uint32_t opcode_i32eq; + uint32_t opcode_i32eqz; + uint32_t opcode_i32extend16s; + uint32_t opcode_i32extend8s; + uint32_t opcode_i32ges; + uint32_t opcode_i32geu; + uint32_t opcode_i32gts; + uint32_t opcode_i32gtu; + uint32_t opcode_i32les; + uint32_t opcode_i32leu; + uint32_t opcode_i32load; + uint32_t opcode_i32load16s; + uint32_t opcode_i32load16u; + uint32_t opcode_i32load8s; + uint32_t opcode_i32load8u; + uint32_t opcode_i32lts; + uint32_t opcode_i32ltu; + uint32_t opcode_i32mul; + uint32_t opcode_i32ne; + uint32_t opcode_i32or; + uint32_t opcode_i32popcnt; + uint32_t opcode_i32rems; + uint32_t opcode_i32remu; + uint32_t opcode_i32rotl; + uint32_t opcode_i32rotr; + uint32_t opcode_i32shl; + uint32_t opcode_i32shrs; + uint32_t opcode_i32shru; + uint32_t opcode_i32store; + uint32_t opcode_i32store16; + uint32_t opcode_i32store8; + uint32_t opcode_i32sub; + uint32_t opcode_i32wrapi64; + uint32_t opcode_i32xor; + uint32_t opcode_i64add; + uint32_t opcode_i64and; + uint32_t opcode_i64clz; + uint32_t opcode_i64const; + uint32_t opcode_i64ctz; + uint32_t opcode_i64divs; + uint32_t opcode_i64divu; + uint32_t opcode_i64eq; + uint32_t opcode_i64eqz; + uint32_t opcode_i64extend16s; + uint32_t opcode_i64extend32s; + uint32_t opcode_i64extend8s; + uint32_t opcode_i64extendi32s; + uint32_t opcode_i64extendi32u; + uint32_t opcode_i64ges; + uint32_t opcode_i64geu; + uint32_t opcode_i64gts; + uint32_t opcode_i64gtu; + uint32_t opcode_i64les; + uint32_t opcode_i64leu; + uint32_t opcode_i64load; + uint32_t opcode_i64load16s; + uint32_t opcode_i64load16u; + uint32_t opcode_i64load32s; + uint32_t opcode_i64load32u; + uint32_t opcode_i64load8s; + uint32_t opcode_i64load8u; + uint32_t opcode_i64lts; + uint32_t opcode_i64ltu; + uint32_t opcode_i64mul; + uint32_t opcode_i64ne; + uint32_t opcode_i64or; + uint32_t opcode_i64popcnt; + uint32_t opcode_i64rems; + uint32_t opcode_i64remu; + uint32_t opcode_i64rotl; + uint32_t opcode_i64rotr; + uint32_t opcode_i64shl; + uint32_t opcode_i64shrs; + uint32_t opcode_i64shru; + uint32_t opcode_i64store; + uint32_t opcode_i64store16; + uint32_t opcode_i64store32; + uint32_t opcode_i64store8; + uint32_t opcode_i64sub; + uint32_t opcode_i64xor; + uint32_t opcode_if; + uint32_t opcode_localget; + uint32_t opcode_localset; + uint32_t opcode_localtee; + uint32_t opcode_loop; + uint32_t opcode_memorygrow; + uint32_t opcode_memorysize; + uint32_t opcode_nop; + uint32_t opcode_reffunc; + uint32_t opcode_refisnull; + uint32_t opcode_refnull; + uint32_t opcode_rethrow; + uint32_t opcode_return; + uint32_t opcode_returncall; + uint32_t opcode_returncallindirect; + uint32_t opcode_select; + uint32_t opcode_tableget; + uint32_t opcode_tablegrow; + uint32_t opcode_tableinit; + uint32_t opcode_tableset; + uint32_t opcode_tablesize; + uint32_t opcode_throw; + uint32_t opcode_try; + uint32_t opcode_typedselect; + uint32_t opcode_unreachable; + uint32_t opcode_unwind; + uint32_t opcode_memorycopy; + uint32_t opcode_memoryfill; + uint32_t opcode_memorycopyperbyte; + uint32_t opcode_memoryfillperbyte; + uint32_t opcode_localallocate; } vm_exec_opcode_cost_t; /** diff --git a/c-api/src/capi_metering.rs b/c-api/src/capi_metering.rs index 6b455c9..350d797 100644 --- a/c-api/src/capi_metering.rs +++ b/c-api/src/capi_metering.rs @@ -1,13 +1,10 @@ use crate::capi_executor::{CapiExecutor, vm_exec_executor_t}; use crate::capi_instance::{CapiInstance, vm_exec_instance_t}; +use crate::capi_opcode_cost::vm_exec_opcode_cost_t; use crate::service_singleton::with_service; use crate::vm_exec_result_t; use meta::capi_safe_unwind; -use multiversx_chain_vm_executor::{OpcodeConfig, OpcodeCost, OpcodeVersion}; - -#[allow(non_camel_case_types)] -#[repr(C)] -pub struct vm_exec_opcode_cost_t; +use multiversx_chain_vm_executor::{OpcodeConfig, OpcodeVersion}; /// Sets the opcode costs for the given executor. /// @@ -38,10 +35,10 @@ pub unsafe extern "C" fn vm_exec_set_opcode_config( return vm_exec_result_t::VM_EXEC_ERROR; }; - let opcode_costs_ref: &OpcodeCost = unsafe { &*(opcode_cost_ptr as *const OpcodeCost) }; + let opcode_cost = unsafe { (*opcode_cost_ptr).to_opcode_cost() }; let opcode_config = OpcodeConfig { opcode_version, - opcode_cost: opcode_costs_ref.clone(), + opcode_cost, }; let result = capi_executor.content.set_opcode_config(opcode_config); diff --git a/c-api/src/capi_opcode_cost.rs b/c-api/src/capi_opcode_cost.rs new file mode 100644 index 0000000..26abdb2 --- /dev/null +++ b/c-api/src/capi_opcode_cost.rs @@ -0,0 +1,288 @@ +// Code generated by vmhooks generator. DO NOT EDIT. + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// !!!!!!!!!!!!!!!!!!!!!! AUTO-GENERATED FILE !!!!!!!!!!!!!!!!!!!!!! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +use multiversx_chain_vm_executor::OpcodeCost; + +/// FFI-safe mirror of `OpcodeCost`. +/// +/// This is a distinct type rather than a cast of `OpcodeCost` itself, so that +/// the general-purpose struct is free to change shape without touching the C +/// ABI, and vice versa. +#[allow(non_camel_case_types)] +#[repr(C)] +pub struct vm_exec_opcode_cost_t { + pub opcode_block: u32, + pub opcode_br: u32, + pub opcode_brif: u32, + pub opcode_brtable: u32, + pub opcode_call: u32, + pub opcode_callindirect: u32, + pub opcode_catch: u32, + pub opcode_catchall: u32, + pub opcode_delegate: u32, + pub opcode_drop: u32, + pub opcode_else: u32, + pub opcode_end: u32, + pub opcode_globalget: u32, + pub opcode_globalset: u32, + pub opcode_i32add: u32, + pub opcode_i32and: u32, + pub opcode_i32clz: u32, + pub opcode_i32const: u32, + pub opcode_i32ctz: u32, + pub opcode_i32divs: u32, + pub opcode_i32divu: u32, + pub opcode_i32eq: u32, + pub opcode_i32eqz: u32, + pub opcode_i32extend16s: u32, + pub opcode_i32extend8s: u32, + pub opcode_i32ges: u32, + pub opcode_i32geu: u32, + pub opcode_i32gts: u32, + pub opcode_i32gtu: u32, + pub opcode_i32les: u32, + pub opcode_i32leu: u32, + pub opcode_i32load: u32, + pub opcode_i32load16s: u32, + pub opcode_i32load16u: u32, + pub opcode_i32load8s: u32, + pub opcode_i32load8u: u32, + pub opcode_i32lts: u32, + pub opcode_i32ltu: u32, + pub opcode_i32mul: u32, + pub opcode_i32ne: u32, + pub opcode_i32or: u32, + pub opcode_i32popcnt: u32, + pub opcode_i32rems: u32, + pub opcode_i32remu: u32, + pub opcode_i32rotl: u32, + pub opcode_i32rotr: u32, + pub opcode_i32shl: u32, + pub opcode_i32shrs: u32, + pub opcode_i32shru: u32, + pub opcode_i32store: u32, + pub opcode_i32store16: u32, + pub opcode_i32store8: u32, + pub opcode_i32sub: u32, + pub opcode_i32wrapi64: u32, + pub opcode_i32xor: u32, + pub opcode_i64add: u32, + pub opcode_i64and: u32, + pub opcode_i64clz: u32, + pub opcode_i64const: u32, + pub opcode_i64ctz: u32, + pub opcode_i64divs: u32, + pub opcode_i64divu: u32, + pub opcode_i64eq: u32, + pub opcode_i64eqz: u32, + pub opcode_i64extend16s: u32, + pub opcode_i64extend32s: u32, + pub opcode_i64extend8s: u32, + pub opcode_i64extendi32s: u32, + pub opcode_i64extendi32u: u32, + pub opcode_i64ges: u32, + pub opcode_i64geu: u32, + pub opcode_i64gts: u32, + pub opcode_i64gtu: u32, + pub opcode_i64les: u32, + pub opcode_i64leu: u32, + pub opcode_i64load: u32, + pub opcode_i64load16s: u32, + pub opcode_i64load16u: u32, + pub opcode_i64load32s: u32, + pub opcode_i64load32u: u32, + pub opcode_i64load8s: u32, + pub opcode_i64load8u: u32, + pub opcode_i64lts: u32, + pub opcode_i64ltu: u32, + pub opcode_i64mul: u32, + pub opcode_i64ne: u32, + pub opcode_i64or: u32, + pub opcode_i64popcnt: u32, + pub opcode_i64rems: u32, + pub opcode_i64remu: u32, + pub opcode_i64rotl: u32, + pub opcode_i64rotr: u32, + pub opcode_i64shl: u32, + pub opcode_i64shrs: u32, + pub opcode_i64shru: u32, + pub opcode_i64store: u32, + pub opcode_i64store16: u32, + pub opcode_i64store32: u32, + pub opcode_i64store8: u32, + pub opcode_i64sub: u32, + pub opcode_i64xor: u32, + pub opcode_if: u32, + pub opcode_localget: u32, + pub opcode_localset: u32, + pub opcode_localtee: u32, + pub opcode_loop: u32, + pub opcode_memorygrow: u32, + pub opcode_memorysize: u32, + pub opcode_nop: u32, + pub opcode_reffunc: u32, + pub opcode_refisnull: u32, + pub opcode_refnull: u32, + pub opcode_rethrow: u32, + pub opcode_return: u32, + pub opcode_returncall: u32, + pub opcode_returncallindirect: u32, + pub opcode_select: u32, + pub opcode_tableget: u32, + pub opcode_tablegrow: u32, + pub opcode_tableinit: u32, + pub opcode_tableset: u32, + pub opcode_tablesize: u32, + pub opcode_throw: u32, + pub opcode_try: u32, + pub opcode_typedselect: u32, + pub opcode_unreachable: u32, + pub opcode_unwind: u32, + pub opcode_memorycopy: u32, + pub opcode_memoryfill: u32, + pub opcode_memorycopyperbyte: u32, + pub opcode_memoryfillperbyte: u32, + pub opcode_localallocate: u32, +} + +impl vm_exec_opcode_cost_t { + pub(crate) fn to_opcode_cost(&self) -> OpcodeCost { + OpcodeCost { + opcode_block: self.opcode_block, + opcode_br: self.opcode_br, + opcode_brif: self.opcode_brif, + opcode_brtable: self.opcode_brtable, + opcode_call: self.opcode_call, + opcode_callindirect: self.opcode_callindirect, + opcode_catch: self.opcode_catch, + opcode_catchall: self.opcode_catchall, + opcode_delegate: self.opcode_delegate, + opcode_drop: self.opcode_drop, + opcode_else: self.opcode_else, + opcode_end: self.opcode_end, + opcode_globalget: self.opcode_globalget, + opcode_globalset: self.opcode_globalset, + opcode_i32add: self.opcode_i32add, + opcode_i32and: self.opcode_i32and, + opcode_i32clz: self.opcode_i32clz, + opcode_i32const: self.opcode_i32const, + opcode_i32ctz: self.opcode_i32ctz, + opcode_i32divs: self.opcode_i32divs, + opcode_i32divu: self.opcode_i32divu, + opcode_i32eq: self.opcode_i32eq, + opcode_i32eqz: self.opcode_i32eqz, + opcode_i32extend16s: self.opcode_i32extend16s, + opcode_i32extend8s: self.opcode_i32extend8s, + opcode_i32ges: self.opcode_i32ges, + opcode_i32geu: self.opcode_i32geu, + opcode_i32gts: self.opcode_i32gts, + opcode_i32gtu: self.opcode_i32gtu, + opcode_i32les: self.opcode_i32les, + opcode_i32leu: self.opcode_i32leu, + opcode_i32load: self.opcode_i32load, + opcode_i32load16s: self.opcode_i32load16s, + opcode_i32load16u: self.opcode_i32load16u, + opcode_i32load8s: self.opcode_i32load8s, + opcode_i32load8u: self.opcode_i32load8u, + opcode_i32lts: self.opcode_i32lts, + opcode_i32ltu: self.opcode_i32ltu, + opcode_i32mul: self.opcode_i32mul, + opcode_i32ne: self.opcode_i32ne, + opcode_i32or: self.opcode_i32or, + opcode_i32popcnt: self.opcode_i32popcnt, + opcode_i32rems: self.opcode_i32rems, + opcode_i32remu: self.opcode_i32remu, + opcode_i32rotl: self.opcode_i32rotl, + opcode_i32rotr: self.opcode_i32rotr, + opcode_i32shl: self.opcode_i32shl, + opcode_i32shrs: self.opcode_i32shrs, + opcode_i32shru: self.opcode_i32shru, + opcode_i32store: self.opcode_i32store, + opcode_i32store16: self.opcode_i32store16, + opcode_i32store8: self.opcode_i32store8, + opcode_i32sub: self.opcode_i32sub, + opcode_i32wrapi64: self.opcode_i32wrapi64, + opcode_i32xor: self.opcode_i32xor, + opcode_i64add: self.opcode_i64add, + opcode_i64and: self.opcode_i64and, + opcode_i64clz: self.opcode_i64clz, + opcode_i64const: self.opcode_i64const, + opcode_i64ctz: self.opcode_i64ctz, + opcode_i64divs: self.opcode_i64divs, + opcode_i64divu: self.opcode_i64divu, + opcode_i64eq: self.opcode_i64eq, + opcode_i64eqz: self.opcode_i64eqz, + opcode_i64extend16s: self.opcode_i64extend16s, + opcode_i64extend32s: self.opcode_i64extend32s, + opcode_i64extend8s: self.opcode_i64extend8s, + opcode_i64extendi32s: self.opcode_i64extendi32s, + opcode_i64extendi32u: self.opcode_i64extendi32u, + opcode_i64ges: self.opcode_i64ges, + opcode_i64geu: self.opcode_i64geu, + opcode_i64gts: self.opcode_i64gts, + opcode_i64gtu: self.opcode_i64gtu, + opcode_i64les: self.opcode_i64les, + opcode_i64leu: self.opcode_i64leu, + opcode_i64load: self.opcode_i64load, + opcode_i64load16s: self.opcode_i64load16s, + opcode_i64load16u: self.opcode_i64load16u, + opcode_i64load32s: self.opcode_i64load32s, + opcode_i64load32u: self.opcode_i64load32u, + opcode_i64load8s: self.opcode_i64load8s, + opcode_i64load8u: self.opcode_i64load8u, + opcode_i64lts: self.opcode_i64lts, + opcode_i64ltu: self.opcode_i64ltu, + opcode_i64mul: self.opcode_i64mul, + opcode_i64ne: self.opcode_i64ne, + opcode_i64or: self.opcode_i64or, + opcode_i64popcnt: self.opcode_i64popcnt, + opcode_i64rems: self.opcode_i64rems, + opcode_i64remu: self.opcode_i64remu, + opcode_i64rotl: self.opcode_i64rotl, + opcode_i64rotr: self.opcode_i64rotr, + opcode_i64shl: self.opcode_i64shl, + opcode_i64shrs: self.opcode_i64shrs, + opcode_i64shru: self.opcode_i64shru, + opcode_i64store: self.opcode_i64store, + opcode_i64store16: self.opcode_i64store16, + opcode_i64store32: self.opcode_i64store32, + opcode_i64store8: self.opcode_i64store8, + opcode_i64sub: self.opcode_i64sub, + opcode_i64xor: self.opcode_i64xor, + opcode_if: self.opcode_if, + opcode_localget: self.opcode_localget, + opcode_localset: self.opcode_localset, + opcode_localtee: self.opcode_localtee, + opcode_loop: self.opcode_loop, + opcode_memorygrow: self.opcode_memorygrow, + opcode_memorysize: self.opcode_memorysize, + opcode_nop: self.opcode_nop, + opcode_reffunc: self.opcode_reffunc, + opcode_refisnull: self.opcode_refisnull, + opcode_refnull: self.opcode_refnull, + opcode_rethrow: self.opcode_rethrow, + opcode_return: self.opcode_return, + opcode_returncall: self.opcode_returncall, + opcode_returncallindirect: self.opcode_returncallindirect, + opcode_select: self.opcode_select, + opcode_tableget: self.opcode_tableget, + opcode_tablegrow: self.opcode_tablegrow, + opcode_tableinit: self.opcode_tableinit, + opcode_tableset: self.opcode_tableset, + opcode_tablesize: self.opcode_tablesize, + opcode_throw: self.opcode_throw, + opcode_try: self.opcode_try, + opcode_typedselect: self.opcode_typedselect, + opcode_unreachable: self.opcode_unreachable, + opcode_unwind: self.opcode_unwind, + opcode_memorycopy: self.opcode_memorycopy, + opcode_memoryfill: self.opcode_memoryfill, + opcode_memorycopyperbyte: self.opcode_memorycopyperbyte, + opcode_memoryfillperbyte: self.opcode_memoryfillperbyte, + opcode_localallocate: self.opcode_localallocate, + } + } +} diff --git a/c-api/src/lib.rs b/c-api/src/lib.rs index c3a0ad8..0e28529 100644 --- a/c-api/src/lib.rs +++ b/c-api/src/lib.rs @@ -11,6 +11,7 @@ pub mod capi_instance_cache; pub mod capi_logger; pub mod capi_memory; pub mod capi_metering; +pub mod capi_opcode_cost; pub mod capi_vm_hook_pointers; pub mod capi_vm_hooks; pub mod service_singleton; From f8df5c676423d7914e443c24ae2514422d4ab4b4 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Fri, 25 Sep 2026 12:56:45 +0300 Subject: [PATCH 34/35] opcodes v2 - removed 15 opcodes --- .../src/middlewares/we_opcode_cost.rs | 15 -------------- vm-executor-wasmer/src/wasmer_opcode_cost.rs | 15 -------------- vm-executor/src/opcode_cost.rs | 20 +++++++++---------- vm-executor/src/opcode_version.rs | 20 ++++++++++++++++++- 4 files changed, 29 insertions(+), 41 deletions(-) diff --git a/vm-executor-experimental/src/middlewares/we_opcode_cost.rs b/vm-executor-experimental/src/middlewares/we_opcode_cost.rs index 9b46553..846ab54 100644 --- a/vm-executor-experimental/src/middlewares/we_opcode_cost.rs +++ b/vm-executor-experimental/src/middlewares/we_opcode_cost.rs @@ -158,9 +158,6 @@ fn get_opcode_cost_v2(op: &Operator, opcode_cost: &OpcodeCost) -> Cost { Operator::BrTable { .. } => Cost::Base(opcode_cost.opcode_brtable), Operator::Call { .. } => Cost::Base(opcode_cost.opcode_call), Operator::CallIndirect { .. } => Cost::Base(opcode_cost.opcode_callindirect), - Operator::Catch { .. } => Cost::Base(opcode_cost.opcode_catch), - Operator::CatchAll { .. } => Cost::Base(opcode_cost.opcode_catchall), - Operator::Delegate { .. } => Cost::Base(opcode_cost.opcode_delegate), Operator::Drop { .. } => Cost::Base(opcode_cost.opcode_drop), Operator::Else { .. } => Cost::Base(opcode_cost.opcode_else), Operator::End { .. } => Cost::Base(opcode_cost.opcode_end), @@ -261,22 +258,10 @@ fn get_opcode_cost_v2(op: &Operator, opcode_cost: &OpcodeCost) -> Cost { Operator::MemoryGrow { .. } => Cost::Base(opcode_cost.opcode_memorygrow), Operator::MemorySize { .. } => Cost::Base(opcode_cost.opcode_memorysize), Operator::Nop { .. } => Cost::Base(opcode_cost.opcode_nop), - Operator::RefFunc { .. } => Cost::Base(opcode_cost.opcode_reffunc), - Operator::RefIsNull { .. } => Cost::Base(opcode_cost.opcode_refisnull), - Operator::RefNull { .. } => Cost::Base(opcode_cost.opcode_refnull), - Operator::Rethrow { .. } => Cost::Base(opcode_cost.opcode_rethrow), Operator::Return { .. } => Cost::Base(opcode_cost.opcode_return), Operator::ReturnCall { .. } => Cost::Base(opcode_cost.opcode_returncall), Operator::ReturnCallIndirect { .. } => Cost::Base(opcode_cost.opcode_returncallindirect), Operator::Select { .. } => Cost::Base(opcode_cost.opcode_select), - Operator::TableGet { .. } => Cost::Base(opcode_cost.opcode_tableget), - Operator::TableGrow { .. } => Cost::Base(opcode_cost.opcode_tablegrow), - Operator::TableInit { .. } => Cost::Base(opcode_cost.opcode_tableinit), - Operator::TableSet { .. } => Cost::Base(opcode_cost.opcode_tableset), - Operator::TableSize { .. } => Cost::Base(opcode_cost.opcode_tablesize), - Operator::Throw { .. } => Cost::Base(opcode_cost.opcode_throw), - Operator::Try { .. } => Cost::Base(opcode_cost.opcode_try), - Operator::TypedSelect { .. } => Cost::Base(opcode_cost.opcode_typedselect), Operator::Unreachable { .. } => Cost::Base(opcode_cost.opcode_unreachable), Operator::MemoryCopy { .. } => Cost::BulkMemory { base: opcode_cost.opcode_memorycopy, per_byte: opcode_cost.opcode_memorycopyperbyte }, Operator::MemoryFill { .. } => Cost::BulkMemory { base: opcode_cost.opcode_memoryfill, per_byte: opcode_cost.opcode_memoryfillperbyte }, diff --git a/vm-executor-wasmer/src/wasmer_opcode_cost.rs b/vm-executor-wasmer/src/wasmer_opcode_cost.rs index 9829887..44e1594 100644 --- a/vm-executor-wasmer/src/wasmer_opcode_cost.rs +++ b/vm-executor-wasmer/src/wasmer_opcode_cost.rs @@ -158,9 +158,6 @@ fn get_opcode_cost_v2(op: &Operator, opcode_cost: &OpcodeCost) -> Cost { Operator::BrTable { .. } => Cost::Base(opcode_cost.opcode_brtable), Operator::Call { .. } => Cost::Base(opcode_cost.opcode_call), Operator::CallIndirect { .. } => Cost::Base(opcode_cost.opcode_callindirect), - Operator::Catch { .. } => Cost::Base(opcode_cost.opcode_catch), - Operator::CatchAll { .. } => Cost::Base(opcode_cost.opcode_catchall), - Operator::Delegate { .. } => Cost::Base(opcode_cost.opcode_delegate), Operator::Drop { .. } => Cost::Base(opcode_cost.opcode_drop), Operator::Else { .. } => Cost::Base(opcode_cost.opcode_else), Operator::End { .. } => Cost::Base(opcode_cost.opcode_end), @@ -261,22 +258,10 @@ fn get_opcode_cost_v2(op: &Operator, opcode_cost: &OpcodeCost) -> Cost { Operator::MemoryGrow { .. } => Cost::Base(opcode_cost.opcode_memorygrow), Operator::MemorySize { .. } => Cost::Base(opcode_cost.opcode_memorysize), Operator::Nop { .. } => Cost::Base(opcode_cost.opcode_nop), - Operator::RefFunc { .. } => Cost::Base(opcode_cost.opcode_reffunc), - Operator::RefIsNull { .. } => Cost::Base(opcode_cost.opcode_refisnull), - Operator::RefNull { .. } => Cost::Base(opcode_cost.opcode_refnull), - Operator::Rethrow { .. } => Cost::Base(opcode_cost.opcode_rethrow), Operator::Return { .. } => Cost::Base(opcode_cost.opcode_return), Operator::ReturnCall { .. } => Cost::Base(opcode_cost.opcode_returncall), Operator::ReturnCallIndirect { .. } => Cost::Base(opcode_cost.opcode_returncallindirect), Operator::Select { .. } => Cost::Base(opcode_cost.opcode_select), - Operator::TableGet { .. } => Cost::Base(opcode_cost.opcode_tableget), - Operator::TableGrow { .. } => Cost::Base(opcode_cost.opcode_tablegrow), - Operator::TableInit { .. } => Cost::Base(opcode_cost.opcode_tableinit), - Operator::TableSet { .. } => Cost::Base(opcode_cost.opcode_tableset), - Operator::TableSize { .. } => Cost::Base(opcode_cost.opcode_tablesize), - Operator::Throw { .. } => Cost::Base(opcode_cost.opcode_throw), - Operator::Try { .. } => Cost::Base(opcode_cost.opcode_try), - Operator::TypedSelect { .. } => Cost::Base(opcode_cost.opcode_typedselect), Operator::Unreachable { .. } => Cost::Base(opcode_cost.opcode_unreachable), Operator::MemoryCopy { .. } => Cost::BulkMemory { base: opcode_cost.opcode_memorycopy, per_byte: opcode_cost.opcode_memorycopyperbyte }, Operator::MemoryFill { .. } => Cost::BulkMemory { base: opcode_cost.opcode_memoryfill, per_byte: opcode_cost.opcode_memoryfillperbyte }, diff --git a/vm-executor/src/opcode_cost.rs b/vm-executor/src/opcode_cost.rs index 85e9617..342ca0e 100644 --- a/vm-executor/src/opcode_cost.rs +++ b/vm-executor/src/opcode_cost.rs @@ -219,22 +219,12 @@ pub struct OpcodeCost { pub opcode_localset: u32, #[serde(rename = "LocalTee", default)] pub opcode_localtee: u32, - #[serde(rename = "LocalAllocate", default)] - pub opcode_localallocate: u32, #[serde(rename = "Loop", default)] pub opcode_loop: u32, #[serde(rename = "MemoryGrow", default)] pub opcode_memorygrow: u32, #[serde(rename = "MemorySize", default)] pub opcode_memorysize: u32, - #[serde(rename = "MemoryCopy", default)] - pub opcode_memorycopy: u32, - #[serde(rename = "MemoryCopyPerByte", default)] - pub opcode_memorycopyperbyte: u32, - #[serde(rename = "MemoryFill", default)] - pub opcode_memoryfill: u32, - #[serde(rename = "MemoryFillPerByte", default)] - pub opcode_memoryfillperbyte: u32, #[serde(rename = "Nop", default)] pub opcode_nop: u32, #[serde(rename = "RefFunc", default)] @@ -273,4 +263,14 @@ pub struct OpcodeCost { pub opcode_unreachable: u32, #[serde(rename = "Unwind", default)] pub opcode_unwind: u32, + #[serde(rename = "MemoryCopy", default)] + pub opcode_memorycopy: u32, + #[serde(rename = "MemoryFill", default)] + pub opcode_memoryfill: u32, + #[serde(rename = "MemoryCopyPerByte", default)] + pub opcode_memorycopyperbyte: u32, + #[serde(rename = "MemoryFillPerByte", default)] + pub opcode_memoryfillperbyte: u32, + #[serde(rename = "LocalAllocate", default)] + pub opcode_localallocate: u32, } diff --git a/vm-executor/src/opcode_version.rs b/vm-executor/src/opcode_version.rs index 1c1dead..fe3464f 100644 --- a/vm-executor/src/opcode_version.rs +++ b/vm-executor/src/opcode_version.rs @@ -2,7 +2,15 @@ /// /// `V1` is the legacy opcode set that does **not** include support for bulk /// memory operations. `V2` extends `V1` by adding bulk memory instructions, -/// such as `MemoryCopy` and `MemoryFill`. +/// such as `MemoryCopy` and `MemoryFill`, while dropping these categories +/// from the whitelist, since no contract built with the current SDK +/// toolchain can emit any of them: +/// +/// * legacy exception handling: `Catch`, `CatchAll`, `Delegate`, `Rethrow`, +/// `Throw`, `Try` +/// * reference types: `RefFunc`, `RefIsNull`, `RefNull`, `TypedSelect` +/// * table manipulation: `TableGet`, `TableGrow`, `TableInit`, `TableSet`, +/// `TableSize` #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum OpcodeVersion { /// Legacy opcode set without bulk memory support. @@ -17,6 +25,16 @@ pub enum OpcodeVersion { /// `MemoryCopy` and `MemoryFill`, or when targeting newer runtimes that /// support these instructions. /// + /// Relative to `V1`, `V2` also drops these categories from the + /// whitelist, since no contract built with today's tooling can produce + /// them: + /// + /// * legacy exception handling: `Catch`, `CatchAll`, `Delegate`, + /// `Rethrow`, `Throw`, `Try` + /// * reference types: `RefFunc`, `RefIsNull`, `RefNull`, `TypedSelect` + /// * table manipulation: `TableGet`, `TableGrow`, `TableInit`, + /// `TableSet`, `TableSize` + /// /// Note: `V2` does **not** add support for `memory.init` and `data.drop`. V2, } From da2f5a694dbb196efae738493f6d415fd90d9b4b Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Tue, 29 Sep 2026 20:51:40 +0300 Subject: [PATCH 35/35] VM hooks update --- c-api/libvmexeccapi.h | 5 ---- c-api/src/capi_vm_hook_pointers.rs | 5 ---- c-api/src/capi_vm_hooks.rs | 20 ------------- vm-executor-experimental/src/we_imports.rs | 30 ------------------- vm-executor-wasmer/src/wasmer_imports.rs | 30 ------------------- .../src/new_traits/vm_hooks_legacy_adapter.rs | 20 ------------- vm-executor/src/new_traits/vm_hooks_new.rs | 30 ------------------- vm-executor/src/vm_hooks.rs | 26 ---------------- 8 files changed, 166 deletions(-) diff --git a/c-api/libvmexeccapi.h b/c-api/libvmexeccapi.h index 4fc5500..9d7097b 100644 --- a/c-api/libvmexeccapi.h +++ b/c-api/libvmexeccapi.h @@ -311,11 +311,6 @@ typedef struct vm_exec_vm_hook_c_func_pointers { int32_t (*managed_verify_secp256r1_func_ptr)(void *context, int32_t key_handle, int32_t message_handle, int32_t sig_handle); int32_t (*managed_verify_blssignature_share_func_ptr)(void *context, int32_t key_handle, int32_t message_handle, int32_t sig_handle); int32_t (*managed_verify_blsaggregated_signature_func_ptr)(void *context, int32_t key_handle, int32_t message_handle, int32_t sig_handle); - void (*activate_unsafe_mode_func_ptr)(void *context); - void (*deactivate_unsafe_mode_func_ptr)(void *context); - int32_t (*managed_get_num_errors_func_ptr)(void *context); - void (*managed_get_error_with_index_func_ptr)(void *context, int32_t index, int32_t error_handle); - void (*managed_get_last_error_func_ptr)(void *context, int32_t error_handle); } vm_exec_vm_hook_c_func_pointers; /** diff --git a/c-api/src/capi_vm_hook_pointers.rs b/c-api/src/capi_vm_hook_pointers.rs index 1200dae..3029000 100644 --- a/c-api/src/capi_vm_hook_pointers.rs +++ b/c-api/src/capi_vm_hook_pointers.rs @@ -288,11 +288,6 @@ pub struct vm_exec_vm_hook_c_func_pointers { pub managed_verify_secp256r1_func_ptr: extern "C" fn(context: *mut c_void, key_handle: i32, message_handle: i32, sig_handle: i32) -> i32, pub managed_verify_blssignature_share_func_ptr: extern "C" fn(context: *mut c_void, key_handle: i32, message_handle: i32, sig_handle: i32) -> i32, pub managed_verify_blsaggregated_signature_func_ptr: extern "C" fn(context: *mut c_void, key_handle: i32, message_handle: i32, sig_handle: i32) -> i32, - pub activate_unsafe_mode_func_ptr: extern "C" fn(context: *mut c_void), - pub deactivate_unsafe_mode_func_ptr: extern "C" fn(context: *mut c_void), - pub managed_get_num_errors_func_ptr: extern "C" fn(context: *mut c_void) -> i32, - pub managed_get_error_with_index_func_ptr: extern "C" fn(context: *mut c_void, index: i32, error_handle: i32), - pub managed_get_last_error_func_ptr: extern "C" fn(context: *mut c_void, error_handle: i32), } impl std::fmt::Debug for vm_exec_vm_hook_c_func_pointers { diff --git a/c-api/src/capi_vm_hooks.rs b/c-api/src/capi_vm_hooks.rs index 5936bd3..f1a4295 100644 --- a/c-api/src/capi_vm_hooks.rs +++ b/c-api/src/capi_vm_hooks.rs @@ -1146,24 +1146,4 @@ impl multiversx_chain_vm_executor::VMHooksLegacy for CapiVMHooks { fn managed_verify_blsaggregated_signature(&self, key_handle: i32, message_handle: i32, sig_handle: i32) -> i32 { (self.c_func_pointers_ptr.managed_verify_blsaggregated_signature_func_ptr)(self.vm_hooks_ptr, key_handle, message_handle, sig_handle) } - - fn activate_unsafe_mode(&self) { - (self.c_func_pointers_ptr.activate_unsafe_mode_func_ptr)(self.vm_hooks_ptr) - } - - fn deactivate_unsafe_mode(&self) { - (self.c_func_pointers_ptr.deactivate_unsafe_mode_func_ptr)(self.vm_hooks_ptr) - } - - fn managed_get_num_errors(&self) -> i32 { - (self.c_func_pointers_ptr.managed_get_num_errors_func_ptr)(self.vm_hooks_ptr) - } - - fn managed_get_error_with_index(&self, index: i32, error_handle: i32) { - (self.c_func_pointers_ptr.managed_get_error_with_index_func_ptr)(self.vm_hooks_ptr, index, error_handle) - } - - fn managed_get_last_error(&self, error_handle: i32) { - (self.c_func_pointers_ptr.managed_get_last_error_func_ptr)(self.vm_hooks_ptr, error_handle) - } } diff --git a/vm-executor-experimental/src/we_imports.rs b/vm-executor-experimental/src/we_imports.rs index 554a7c0..8f077ae 100644 --- a/vm-executor-experimental/src/we_imports.rs +++ b/vm-executor-experimental/src/we_imports.rs @@ -1396,31 +1396,6 @@ fn wasmer_import_managed_verify_blsaggregated_signature(env: FunctionEnvMut) -> Result<(), VMHooksEarlyExit> { - with_vm_hooks(env, |vh| vh.activate_unsafe_mode()) -} - -#[rustfmt::skip] -fn wasmer_import_deactivate_unsafe_mode(env: FunctionEnvMut) -> Result<(), VMHooksEarlyExit> { - with_vm_hooks(env, |vh| vh.deactivate_unsafe_mode()) -} - -#[rustfmt::skip] -fn wasmer_import_managed_get_num_errors(env: FunctionEnvMut) -> Result { - with_vm_hooks(env, |vh| vh.managed_get_num_errors()) -} - -#[rustfmt::skip] -fn wasmer_import_managed_get_error_with_index(env: FunctionEnvMut, index: i32, error_handle: i32) -> Result<(), VMHooksEarlyExit> { - with_vm_hooks(env, |vh| vh.managed_get_error_with_index(index, error_handle)) -} - -#[rustfmt::skip] -fn wasmer_import_managed_get_last_error(env: FunctionEnvMut, error_handle: i32) -> Result<(), VMHooksEarlyExit> { - with_vm_hooks(env, |vh| vh.managed_get_last_error(error_handle)) -} - pub fn generate_import_object(store: &mut Store, vh_wrapper: VMHooksWrapper) -> Imports { let function_env = FunctionEnv::new(store, vh_wrapper); @@ -1703,11 +1678,6 @@ pub fn generate_import_object(store: &mut Store, vh_wrapper: VMHooksWrapper) -> "managedVerifySecp256r1" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_verify_secp256r1), "managedVerifyBLSSignatureShare" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_verify_blssignature_share), "managedVerifyBLSAggregatedSignature" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_verify_blsaggregated_signature), - "activateUnsafeMode" => Function::new_typed_with_env(store, &function_env, wasmer_import_activate_unsafe_mode), - "deactivateUnsafeMode" => Function::new_typed_with_env(store, &function_env, wasmer_import_deactivate_unsafe_mode), - "managedGetNumErrors" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_get_num_errors), - "managedGetErrorWithIndex" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_get_error_with_index), - "managedGetLastError" => Function::new_typed_with_env(store, &function_env, wasmer_import_managed_get_last_error), } } diff --git a/vm-executor-wasmer/src/wasmer_imports.rs b/vm-executor-wasmer/src/wasmer_imports.rs index 6a87c76..c5ec09b 100644 --- a/vm-executor-wasmer/src/wasmer_imports.rs +++ b/vm-executor-wasmer/src/wasmer_imports.rs @@ -1395,31 +1395,6 @@ fn wasmer_import_managed_verify_blsaggregated_signature(env: &VMHooksWrapper, ke env.vm_hooks.managed_verify_blsaggregated_signature(key_handle, message_handle, sig_handle) } -#[rustfmt::skip] -fn wasmer_import_activate_unsafe_mode(env: &VMHooksWrapper) { - env.vm_hooks.activate_unsafe_mode() -} - -#[rustfmt::skip] -fn wasmer_import_deactivate_unsafe_mode(env: &VMHooksWrapper) { - env.vm_hooks.deactivate_unsafe_mode() -} - -#[rustfmt::skip] -fn wasmer_import_managed_get_num_errors(env: &VMHooksWrapper) -> i32 { - env.vm_hooks.managed_get_num_errors() -} - -#[rustfmt::skip] -fn wasmer_import_managed_get_error_with_index(env: &VMHooksWrapper, index: i32, error_handle: i32) { - env.vm_hooks.managed_get_error_with_index(index, error_handle) -} - -#[rustfmt::skip] -fn wasmer_import_managed_get_last_error(env: &VMHooksWrapper, error_handle: i32) { - env.vm_hooks.managed_get_last_error(error_handle) -} - pub fn generate_import_object(store: &Store, env: &VMHooksWrapper) -> ImportObject { imports! { "env" => { @@ -1700,11 +1675,6 @@ pub fn generate_import_object(store: &Store, env: &VMHooksWrapper) -> ImportObje "managedVerifySecp256r1" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_verify_secp256r1), "managedVerifyBLSSignatureShare" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_verify_blssignature_share), "managedVerifyBLSAggregatedSignature" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_verify_blsaggregated_signature), - "activateUnsafeMode" => Function::new_native_with_env(store, env.clone(), wasmer_import_activate_unsafe_mode), - "deactivateUnsafeMode" => Function::new_native_with_env(store, env.clone(), wasmer_import_deactivate_unsafe_mode), - "managedGetNumErrors" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_get_num_errors), - "managedGetErrorWithIndex" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_get_error_with_index), - "managedGetLastError" => Function::new_native_with_env(store, env.clone(), wasmer_import_managed_get_last_error), } } diff --git a/vm-executor/src/new_traits/vm_hooks_legacy_adapter.rs b/vm-executor/src/new_traits/vm_hooks_legacy_adapter.rs index c79d9b6..1637554 100644 --- a/vm-executor/src/new_traits/vm_hooks_legacy_adapter.rs +++ b/vm-executor/src/new_traits/vm_hooks_legacy_adapter.rs @@ -1154,24 +1154,4 @@ impl VMHooksLegacy for VMHooksLegacyAdapter { fn managed_verify_blsaggregated_signature(&self, key_handle: i32, message_handle: i32, sig_handle: i32) -> i32 { self.adapt_vm_hooks(|inner| VMHooks::managed_verify_blsaggregated_signature(inner, key_handle, message_handle, sig_handle)) } - - fn activate_unsafe_mode(&self) { - self.adapt_vm_hooks(|inner| VMHooks::activate_unsafe_mode(inner)) - } - - fn deactivate_unsafe_mode(&self) { - self.adapt_vm_hooks(|inner| VMHooks::deactivate_unsafe_mode(inner)) - } - - fn managed_get_num_errors(&self) -> i32 { - self.adapt_vm_hooks(|inner| VMHooks::managed_get_num_errors(inner)) - } - - fn managed_get_error_with_index(&self, index: i32, error_handle: i32) { - self.adapt_vm_hooks(|inner| VMHooks::managed_get_error_with_index(inner, index, error_handle)) - } - - fn managed_get_last_error(&self, error_handle: i32) { - self.adapt_vm_hooks(|inner| VMHooks::managed_get_last_error(inner, error_handle)) - } } diff --git a/vm-executor/src/new_traits/vm_hooks_new.rs b/vm-executor/src/new_traits/vm_hooks_new.rs index 26a6aa5..0bd5410 100644 --- a/vm-executor/src/new_traits/vm_hooks_new.rs +++ b/vm-executor/src/new_traits/vm_hooks_new.rs @@ -286,11 +286,6 @@ pub trait VMHooks: core::fmt::Debug { fn managed_verify_secp256r1(&mut self, key_handle: i32, message_handle: i32, sig_handle: i32) -> Result; fn managed_verify_blssignature_share(&mut self, key_handle: i32, message_handle: i32, sig_handle: i32) -> Result; fn managed_verify_blsaggregated_signature(&mut self, key_handle: i32, message_handle: i32, sig_handle: i32) -> Result; - fn activate_unsafe_mode(&mut self) -> Result<(), VMHooksEarlyExit>; - fn deactivate_unsafe_mode(&mut self) -> Result<(), VMHooksEarlyExit>; - fn managed_get_num_errors(&mut self) -> Result; - fn managed_get_error_with_index(&mut self, index: i32, error_handle: i32) -> Result<(), VMHooksEarlyExit>; - fn managed_get_last_error(&mut self, error_handle: i32) -> Result<(), VMHooksEarlyExit>; } /// Dummy implementation for VMHooks. Can be used as placeholder, or in tests. @@ -1684,29 +1679,4 @@ impl VMHooks for VMHooksDefault { println!("Called: managed_verify_blsaggregated_signature"); Ok(0) } - - fn activate_unsafe_mode(&mut self) -> Result<(), VMHooksEarlyExit> { - println!("Called: activate_unsafe_mode"); - Ok(()) - } - - fn deactivate_unsafe_mode(&mut self) -> Result<(), VMHooksEarlyExit> { - println!("Called: deactivate_unsafe_mode"); - Ok(()) - } - - fn managed_get_num_errors(&mut self) -> Result { - println!("Called: managed_get_num_errors"); - Ok(0) - } - - fn managed_get_error_with_index(&mut self, index: i32, error_handle: i32) -> Result<(), VMHooksEarlyExit> { - println!("Called: managed_get_error_with_index"); - Ok(()) - } - - fn managed_get_last_error(&mut self, error_handle: i32) -> Result<(), VMHooksEarlyExit> { - println!("Called: managed_get_last_error"); - Ok(()) - } } diff --git a/vm-executor/src/vm_hooks.rs b/vm-executor/src/vm_hooks.rs index 07f0dd7..6cce8fb 100644 --- a/vm-executor/src/vm_hooks.rs +++ b/vm-executor/src/vm_hooks.rs @@ -290,11 +290,6 @@ pub trait VMHooksLegacy: core::fmt::Debug { fn managed_verify_secp256r1(&self, key_handle: i32, message_handle: i32, sig_handle: i32) -> i32; fn managed_verify_blssignature_share(&self, key_handle: i32, message_handle: i32, sig_handle: i32) -> i32; fn managed_verify_blsaggregated_signature(&self, key_handle: i32, message_handle: i32, sig_handle: i32) -> i32; - fn activate_unsafe_mode(&self); - fn deactivate_unsafe_mode(&self); - fn managed_get_num_errors(&self) -> i32; - fn managed_get_error_with_index(&self, index: i32, error_handle: i32); - fn managed_get_last_error(&self, error_handle: i32); } /// Dummy implementation for VMHooks. Can be used as placeholder, or in tests. @@ -1590,25 +1585,4 @@ impl VMHooksLegacy for VMHooksLegacyDefault { println!("Called: managed_verify_blsaggregated_signature"); 0 } - - fn activate_unsafe_mode(&self) { - println!("Called: activate_unsafe_mode"); - } - - fn deactivate_unsafe_mode(&self) { - println!("Called: deactivate_unsafe_mode"); - } - - fn managed_get_num_errors(&self) -> i32 { - println!("Called: managed_get_num_errors"); - 0 - } - - fn managed_get_error_with_index(&self, index: i32, error_handle: i32) { - println!("Called: managed_get_error_with_index"); - } - - fn managed_get_last_error(&self, error_handle: i32) { - println!("Called: managed_get_last_error"); - } }