Skip to content
This repository was archived by the owner on Apr 8, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 7 additions & 1 deletion bindings/rust/evmc-declare-tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use evmc_declare::evmc_declare_vm;
use evmc_vm::EvmcVm;
use evmc_vm::ExecutionContext;
use evmc_vm::ExecutionMessage;
use evmc_vm::ExecutionResult;

#[evmc_declare_vm("Foo VM", "ewasm, evm", "1.42-alpha.gamma.starship")]
Expand All @@ -16,7 +17,12 @@ impl EvmcVm for FooVM {
FooVM {}
}

fn execute(&self, _code: &[u8], _context: &ExecutionContext) -> ExecutionResult {
fn execute(
&self,
_code: &[u8],
_message: &ExecutionMessage,
_context: &ExecutionContext,
) -> ExecutionResult {
ExecutionResult::success(1337, None)
}
}
13 changes: 7 additions & 6 deletions bindings/rust/evmc-declare/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
//! ExampleVM {}
//! }
//!
//! fn execute(&self, code: &[u8], context: &evmc_vm::ExecutionContext) -> evmc_vm::ExecutionResult {
//! fn execute(&self, code: &[u8], message: &evmc_vm::ExecutionMessage, context: &evmc_vm::ExecutionContext) -> evmc_vm::ExecutionResult {
//! evmc_vm::ExecutionResult::success(1337, None)
//! }
//! }
Expand Down Expand Up @@ -342,11 +342,12 @@ fn build_execute_fn(names: &VMNameSet) -> proc_macro2::TokenStream {
assert!(!context.is_null());
assert!(!msg.is_null());

let execution_message: ::evmc_vm::ExecutionMessage = unsafe {
msg.as_ref().expect("EVMC message is null").into()
};

let execution_context = unsafe {
::evmc_vm::ExecutionContext::new(
msg.as_ref().expect("EVMC message is null"),
context.as_mut().expect("EVMC context is null")
)
::evmc_vm::ExecutionContext::new(context.as_mut().expect("EVMC context is null"))
};

let empty_code = [0u8;0];
Expand All @@ -364,7 +365,7 @@ fn build_execute_fn(names: &VMNameSet) -> proc_macro2::TokenStream {
};

let result = ::std::panic::catch_unwind(|| {
container.execute(code_ref, &execution_context)
container.execute(code_ref, &execution_message, &execution_context)
});

let result = if result.is_err() {
Expand Down
22 changes: 17 additions & 5 deletions bindings/rust/evmc-vm/src/container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,19 @@ where
mod tests {
use super::*;
use crate::types::*;
use crate::{ExecutionContext, ExecutionResult};
use crate::{ExecutionContext, ExecutionMessage, ExecutionResult};

struct TestVm {}
impl EvmcVm for TestVm {
fn init() -> Self {
TestVm {}
}
fn execute(&self, _code: &[u8], _context: &ExecutionContext) -> ExecutionResult {
fn execute(
&self,
_code: &[u8],
_message: &ExecutionMessage,
_context: &ExecutionContext,
) -> ExecutionResult {
ExecutionResult::failure()
}
}
Expand Down Expand Up @@ -90,6 +95,7 @@ mod tests {
};

let code = [0u8; 0];

let message = ::evmc_sys::evmc_message {
kind: ::evmc_sys::evmc_call_kind::EVMC_CALL,
flags: 0,
Expand All @@ -102,6 +108,8 @@ mod tests {
value: ::evmc_sys::evmc_uint256be::default(),
create2_salt: ::evmc_sys::evmc_bytes32::default(),
};
let message: ExecutionMessage = (&message).into();

let host = ::evmc_sys::evmc_host_interface {
account_exists: None,
get_storage: None,
Expand All @@ -117,19 +125,23 @@ mod tests {
emit_log: None,
};
let mut backing_context = ::evmc_sys::evmc_context { host: &host };
let context = ExecutionContext::new(&message, &mut backing_context);
let context = ExecutionContext::new(&mut backing_context);

let container = EvmcContainer::<TestVm>::new(instance);
assert_eq!(
container.execute(&code, &context).get_status_code(),
container
.execute(&code, &message, &context)
.get_status_code(),
::evmc_sys::evmc_status_code::EVMC_FAILURE
);

let ptr = unsafe { EvmcContainer::into_ffi_pointer(Box::new(container)) };

let container = unsafe { EvmcContainer::<TestVm>::from_ffi_pointer(ptr) };
assert_eq!(
container.execute(&code, &context).get_status_code(),
container
.execute(&code, &message, &context)
.get_status_code(),
::evmc_sys::evmc_status_code::EVMC_FAILURE
);
}
Expand Down
59 changes: 11 additions & 48 deletions bindings/rust/evmc-vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ pub use types::*;

pub trait EvmcVm {
fn init() -> Self;
fn execute(&self, code: &[u8], context: &ExecutionContext) -> ExecutionResult;
fn execute(
&self,
code: &[u8],
message: &ExecutionMessage,
context: &ExecutionContext,
) -> ExecutionResult;
}

/// EVMC result structure.
Expand All @@ -44,7 +49,6 @@ pub struct ExecutionMessage {
/// EVMC context structure. Exposes the EVMC host functions, message data, and transaction context
/// to the executing VM.
pub struct ExecutionContext<'a> {
message: ExecutionMessage,
context: &'a mut ffi::evmc_context,
tx_context: ffi::evmc_tx_context,
}
Expand Down Expand Up @@ -159,23 +163,18 @@ impl ExecutionMessage {
}

impl<'a> ExecutionContext<'a> {
pub fn new(_message: &'a ffi::evmc_message, _context: &'a mut ffi::evmc_context) -> Self {
pub fn new(_context: &'a mut ffi::evmc_context) -> Self {
let _tx_context = unsafe {
assert!((*(_context.host)).get_tx_context.is_some());
(*(_context.host)).get_tx_context.unwrap()(_context as *mut ffi::evmc_context)
};

ExecutionContext {
message: _message.into(),
context: _context,
tx_context: _tx_context,
}
}

pub fn get_message(&self) -> &ExecutionMessage {
&self.message
}

pub fn get_tx_context(&mut self) -> &ffi::evmc_tx_context {
&self.tx_context
}
Expand Down Expand Up @@ -789,63 +788,31 @@ mod tests {
}
}

fn get_dummy_message() -> ffi::evmc_message {
ffi::evmc_message {
kind: ffi::evmc_call_kind::EVMC_CALL,
flags: 0,
depth: 123,
gas: 105023,
destination: Address { bytes: [0u8; 20] },
sender: Address { bytes: [0u8; 20] },
input_data: std::ptr::null() as *const u8,
input_size: 0,
value: Uint256 { bytes: [0u8; 32] },
create2_salt: Uint256 { bytes: [0u8; 32] },
}
}

#[test]
fn execution_context() {
let msg = get_dummy_message();
let mut context_raw = get_dummy_context();
// Make a copy here so we don't let get_dummy_context() go out of scope when called again
// in get_dummy_tx_context() and cause LLVM
// sanitizers to complain
let mut context_raw_copy = context_raw.clone();

let mut exe_context = ExecutionContext::new(&msg, &mut context_raw);
let mut exe_context = ExecutionContext::new(&mut context_raw);
let a = exe_context.get_tx_context();
let b = unsafe { get_dummy_tx_context(&mut context_raw_copy as *mut ffi::evmc_context) };

assert_eq!(a.block_gas_limit, b.block_gas_limit);
assert_eq!(a.block_timestamp, b.block_timestamp);
assert_eq!(a.block_number, b.block_number);

let c = exe_context.get_message();
let d = get_dummy_message();

assert_eq!(c.kind, d.kind);
assert_eq!(c.flags, d.flags);
assert_eq!(c.depth, d.depth);
assert_eq!(c.gas, d.gas);
if d.input_data.is_null() {
assert!(c.input().is_none());
} else {
assert!(c.input().is_some());
assert_eq!(c.input().unwrap().len(), d.input_size);
}

dummy_context_dispose(context_raw);
}

#[test]
fn get_code_size() {
let msg = get_dummy_message();

// This address is useless. Just a dummy parameter for the interface function.
let test_addr = Address { bytes: [0u8; 20] };
let mut context_raw = get_dummy_context();
let mut exe_context = ExecutionContext::new(&msg, &mut context_raw);
let mut exe_context = ExecutionContext::new(&mut context_raw);

let a: usize = 105023;
let b = exe_context.get_code_size(&test_addr);
Expand All @@ -857,12 +824,10 @@ mod tests {

#[test]
fn test_call_empty_data() {
let msg = get_dummy_message();

// This address is useless. Just a dummy parameter for the interface function.
let test_addr = ffi::evmc_address { bytes: [0u8; 20] };
let mut context_raw = get_dummy_context();
let mut exe_context = ExecutionContext::new(&msg, &mut context_raw);
let mut exe_context = ExecutionContext::new(&mut context_raw);

let message = ExecutionMessage::new(
ffi::evmc_call_kind::EVMC_CALL,
Expand Down Expand Up @@ -892,12 +857,10 @@ mod tests {

#[test]
fn test_call_with_data() {
let msg = get_dummy_message();

// This address is useless. Just a dummy parameter for the interface function.
let test_addr = ffi::evmc_address { bytes: [0u8; 20] };
let mut context_raw = get_dummy_context();
let mut exe_context = ExecutionContext::new(&msg, &mut context_raw);
let mut exe_context = ExecutionContext::new(&mut context_raw);

let data = vec![0xc0, 0xff, 0xfe];

Expand Down
9 changes: 7 additions & 2 deletions examples/example-rust-vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,13 @@ impl EvmcVm for ExampleRustVM {
ExampleRustVM {}
}

fn execute(&self, _code: &[u8], context: &ExecutionContext) -> ExecutionResult {
let is_create = context.get_message().kind() == evmc_sys::evmc_call_kind::EVMC_CREATE;
fn execute(
&self,
_code: &[u8],
message: &ExecutionMessage,
_context: &ExecutionContext,
) -> ExecutionResult {
let is_create = message.kind() == evmc_sys::evmc_call_kind::EVMC_CREATE;

if is_create {
ExecutionResult::failure()
Expand Down