Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
d433c59
add meetering for bulk memory opcodes
Jul 21, 2025
ad1c798
Merge remote-tracking branch 'origin/rc/after-supernova' into mem-ops…
Aug 20, 2025
b82a9a6
add capi to check opcode usage
Aug 20, 2025
642fa74
fix mem_copy usage detection
Aug 20, 2025
265657f
removed get_local_cost, fmt
andrei-marinica Aug 27, 2025
00162a7
opcode version, opcode config refactor
andrei-marinica Sep 1, 2025
876a457
removed used opcode mechanism
andrei-marinica Sep 2, 2025
d434536
imports fix
andrei-marinica Sep 2, 2025
6aa525e
import fix
andrei-marinica Sep 2, 2025
d655288
get_opcode_cost fix
andrei-marinica Sep 3, 2025
e0fbc4e
opcode version test
andrei-marinica Sep 3, 2025
3b1185f
wasmer opcode cost file rename
andrei-marinica Sep 3, 2025
ed0ff7d
wasmer opcode cost fix
andrei-marinica Sep 3, 2025
61697d5
Merge branch 'rc/after-supernova' into mem-ops-wasm
andrei-marinica Jan 21, 2026
a5c00c1
fix after review
andrei-marinica Sep 8, 2026
66f6a4c
docs
andrei-marinica Sep 8, 2026
965eb28
gitignore fix
andrei-marinica Sep 8, 2026
f7f3d24
typos
andrei-marinica Sep 8, 2026
ab7d408
docs
andrei-marinica Sep 8, 2026
3196e7a
docs (bulk memory cost)
andrei-marinica Sep 9, 2026
2782518
docs
andrei-marinica Sep 9, 2026
63dbf92
Merge branch 'rc/after-supernova' into mem-ops-wasm
andrei-marinica Sep 9, 2026
168370c
re-generated VM hooks
andrei-marinica Sep 23, 2026
ca4b9f3
gitignore tweak
andrei-marinica Sep 23, 2026
be5e6f3
bulk memory base cost, opcode cost refactor
andrei-marinica Sep 23, 2026
59ea7f6
bulk memory gas for wasmer-experimental
andrei-marinica Sep 23, 2026
9b0b28c
clippy fix
andrei-marinica Sep 23, 2026
6803e32
Rust versio nupgrade: 1.98
andrei-marinica Sep 23, 2026
bbc71f7
doc fix
andrei-marinica Sep 23, 2026
80f4c8d
docs & naming fixes
andrei-marinica Sep 23, 2026
d5d7d8a
bulk memory cost temp global changed to i32
andrei-marinica Sep 24, 2026
ebc3092
build.rs revert style
andrei-marinica Sep 24, 2026
0275f60
ffi hardening: compilation options
andrei-marinica Sep 25, 2026
eb52771
ffi hardening: opcode cost
andrei-marinica Sep 25, 2026
f8df5c6
opcodes v2 - removed 15 opcodes
andrei-marinica Sep 25, 2026
20a7a52
Merge branch 'rc/after-supernova' into mem-ops-wasm
andrei-marinica Sep 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions _typos.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[default.extend-words]
groth = "groth" #groth16 crypto function
166 changes: 156 additions & 10 deletions c-api/libvmexeccapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,21 +316,167 @@ 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;
Comment thread
andrei-marinica marked this conversation as resolved.

/**
* 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 vm_exec_compilation_options_t {

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;

/**
* 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 vm_exec_opcode_cost_t {

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;

/**
Expand Down Expand Up @@ -612,7 +758,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_costs(struct vm_exec_executor_t *executor_ptr, const struct vm_exec_opcode_cost_t *opcode_cost_ptr);
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);

/**
* Sets the number of points(gas) limit for the given instance.
Expand Down
36 changes: 36 additions & 0 deletions c-api/src/capi_compilation_options.rs
Original file line number Diff line number Diff line change
@@ -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,
}
}
}
14 changes: 6 additions & 8 deletions c-api/src/capi_instance.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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<dyn InstanceLegacy>,
}
Expand Down Expand Up @@ -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 {
Expand Down
11 changes: 6 additions & 5 deletions c-api/src/capi_instance_cache.rs
Original file line number Diff line number Diff line change
@@ -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,
};
Expand Down Expand Up @@ -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 {
Expand Down
29 changes: 21 additions & 8 deletions c-api/src/capi_metering.rs
Original file line number Diff line number Diff line change
@@ -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::OpcodeCost;

#[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.
///
Expand All @@ -21,14 +18,30 @@ pub struct vm_exec_opcode_cost_t;
#[allow(clippy::cast_ptr_alignment)]
#[unsafe(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_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 opcode_costs: &OpcodeCost = unsafe { &*(opcode_cost_ptr as *const OpcodeCost) };

let result = capi_executor.content.set_opcode_cost(opcode_costs);
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_version_code
))
});
return vm_exec_result_t::VM_EXEC_ERROR;
};

let opcode_cost = unsafe { (*opcode_cost_ptr).to_opcode_cost() };
let opcode_config = OpcodeConfig {
opcode_version,
opcode_cost,
};

let result = capi_executor.content.set_opcode_config(opcode_config);
match result {
Ok(()) => vm_exec_result_t::VM_EXEC_OK,
Err(message) => {
Expand Down
Loading
Loading