diff --git a/bindings/rust/evmc-client/Cargo.toml b/bindings/rust/evmc-client/Cargo.toml index dfc09c8ca..57a561605 100644 --- a/bindings/rust/evmc-client/Cargo.toml +++ b/bindings/rust/evmc-client/Cargo.toml @@ -14,4 +14,5 @@ edition = "2018" [dependencies] evmc-sys = { path = "../evmc-sys", version = "7.4.0" } evmc-vm = { path = "../evmc-vm", version = "7.4.0" } -libloading = "0.5" \ No newline at end of file +libloading = "0.5" +lazy_static = "1.4.0" \ No newline at end of file diff --git a/bindings/rust/evmc-client/src/host.rs b/bindings/rust/evmc-client/src/host.rs index 728525348..c78a325a0 100644 --- a/bindings/rust/evmc-client/src/host.rs +++ b/bindings/rust/evmc-client/src/host.rs @@ -5,9 +5,38 @@ use crate::types::*; use evmc_sys as ffi; +use lazy_static::lazy_static; +use std::collections::HashMap; use std::mem; +use std::sync::Mutex; -pub trait HostInterface { +#[repr(C)] +pub(crate) struct ExtendedContext { + pub context: ffi::evmc_host_context, + pub index: i64, +} + +static mut HOST_CONTEXT_COUNTER: i64 = 0; + +lazy_static! { + static ref HOST_CONTEXT_MAP: Mutex>> = + Mutex::new(HashMap::new()); +} + +pub(crate) unsafe fn add_host_context(ctx: Box) -> i64 { + let mut map = HOST_CONTEXT_MAP.lock().unwrap(); + let id = HOST_CONTEXT_COUNTER; + HOST_CONTEXT_COUNTER += 1; + map.insert(id, ctx); + return id; +} + +pub(crate) fn remove_host_context(id: i64) { + let mut map = HOST_CONTEXT_MAP.lock().unwrap(); + map.remove(&id); +} + +pub trait HostContext { fn account_exists(&mut self, addr: &Address) -> bool; fn get_storage(&mut self, addr: &Address, key: &Bytes32) -> Bytes32; fn set_storage(&mut self, addr: &Address, key: &Bytes32, value: &Bytes32) -> StorageStatus; @@ -38,27 +67,13 @@ pub trait HostInterface { ) -> (Vec, i64, Address, StatusCode); } -struct Callback { - host_interface: ::std::option::Option>, -} - -static mut CALLBACK: Callback = Callback { - host_interface: None, -}; - -pub fn set_host_interface(interface: Option>) { - unsafe { - CALLBACK.host_interface = interface; - } -} - -pub fn get_evmc_host_context() -> ffi::evmc_host_context { +pub(crate) fn get_evmc_host_context() -> ffi::evmc_host_context { ffi::evmc_host_context { _bindgen_opaque_blob: [0u8; 0], } } -pub fn get_evmc_host_interface() -> ffi::evmc_host_interface { +pub(crate) fn get_evmc_host_interface() -> ffi::evmc_host_interface { ffi::evmc_host_interface { account_exists: Some(account_exists), get_storage: Some(get_storage), @@ -76,197 +91,159 @@ pub fn get_evmc_host_interface() -> ffi::evmc_host_interface { } unsafe extern "C" fn account_exists( - _context: *mut ffi::evmc_host_context, + context: *mut ffi::evmc_host_context, address: *const ffi::evmc_address, ) -> bool { - match &mut CALLBACK.host_interface { - Some(host_interface) => { - return host_interface.account_exists(&(*address).bytes); - } - None => { - panic!("Host context not implemented"); - } - } + let mut map = HOST_CONTEXT_MAP.lock().unwrap(); + let host_interface = map + .get_mut(&(*(context as *const ExtendedContext)).index) + .unwrap(); + return host_interface.account_exists(&(*address).bytes); } unsafe extern "C" fn get_storage( - _context: *mut ffi::evmc_host_context, + context: *mut ffi::evmc_host_context, address: *const ffi::evmc_address, key: *const ffi::evmc_bytes32, ) -> ffi::evmc_bytes32 { - match &mut CALLBACK.host_interface { - Some(host_interface) => { - return ffi::evmc_bytes32 { - bytes: host_interface.get_storage(&(*address).bytes, &(*key).bytes), - }; - } - None => { - panic!("Host context not implemented"); - } - } + let mut map = HOST_CONTEXT_MAP.lock().unwrap(); + let host_interface = map + .get_mut(&(*(context as *const ExtendedContext)).index) + .unwrap(); + return ffi::evmc_bytes32 { + bytes: host_interface.get_storage(&(*address).bytes, &(*key).bytes), + }; } unsafe extern "C" fn set_storage( - _context: *mut ffi::evmc_host_context, + context: *mut ffi::evmc_host_context, address: *const ffi::evmc_address, key: *const ffi::evmc_bytes32, value: *const ffi::evmc_bytes32, ) -> ffi::evmc_storage_status { - match &mut CALLBACK.host_interface { - Some(host_interface) => { - return host_interface.set_storage(&(*address).bytes, &(*key).bytes, &(*value).bytes); - } - None => { - panic!("Host context not implemented"); - } - } + let mut map = HOST_CONTEXT_MAP.lock().unwrap(); + let host_interface = map + .get_mut(&(*(context as *const ExtendedContext)).index) + .unwrap(); + return host_interface.set_storage(&(*address).bytes, &(*key).bytes, &(*value).bytes); } unsafe extern "C" fn get_balance( - _context: *mut ffi::evmc_host_context, + context: *mut ffi::evmc_host_context, address: *const ffi::evmc_address, ) -> ffi::evmc_uint256be { - match &mut CALLBACK.host_interface { - Some(host_interface) => { - return ffi::evmc_uint256be { - bytes: host_interface.get_balance(&(*address).bytes), - }; - } - None => { - panic!("Host context not implemented"); - } - } + let mut map = HOST_CONTEXT_MAP.lock().unwrap(); + let host_interface = map + .get_mut(&(*(context as *const ExtendedContext)).index) + .unwrap(); + return ffi::evmc_uint256be { + bytes: host_interface.get_balance(&(*address).bytes), + }; } unsafe extern "C" fn get_code_size( - _context: *mut ffi::evmc_host_context, + context: *mut ffi::evmc_host_context, address: *const ffi::evmc_address, ) -> usize { - match &mut CALLBACK.host_interface { - Some(host_interface) => { - return host_interface.get_code_size(&(*address).bytes); - } - None => { - panic!("Host context not implemented"); - } - } + let mut map = HOST_CONTEXT_MAP.lock().unwrap(); + let host_interface = map + .get_mut(&(*(context as *const ExtendedContext)).index) + .unwrap(); + return host_interface.get_code_size(&(*address).bytes); } unsafe extern "C" fn get_code_hash( - _context: *mut ffi::evmc_host_context, + context: *mut ffi::evmc_host_context, address: *const ffi::evmc_address, ) -> ffi::evmc_bytes32 { - match &mut CALLBACK.host_interface { - Some(host_interface) => { - return ffi::evmc_bytes32 { - bytes: host_interface.get_code_hash(&(*address).bytes), - }; - } - None => { - panic!("Host context not implemented"); - } - } + let mut map = HOST_CONTEXT_MAP.lock().unwrap(); + let host_interface = map + .get_mut(&(*(context as *const ExtendedContext)).index) + .unwrap(); + return ffi::evmc_bytes32 { + bytes: host_interface.get_code_hash(&(*address).bytes), + }; } unsafe extern "C" fn copy_code( - _context: *mut ffi::evmc_host_context, + context: *mut ffi::evmc_host_context, address: *const ffi::evmc_address, code_offset: usize, buffer_data: *mut u8, buffer_size: usize, ) -> usize { - match &mut CALLBACK.host_interface { - Some(host_interface) => { - return host_interface.copy_code( - &(*address).bytes, - &code_offset, - &buffer_data, - &buffer_size, - ); - } - None => { - panic!("Host context not implemented"); - } - } + let mut map = HOST_CONTEXT_MAP.lock().unwrap(); + let host_interface = map + .get_mut(&(*(context as *const ExtendedContext)).index) + .unwrap(); + return host_interface.copy_code(&(*address).bytes, &code_offset, &buffer_data, &buffer_size); } unsafe extern "C" fn selfdestruct( - _context: *mut ffi::evmc_host_context, + context: *mut ffi::evmc_host_context, address: *const ffi::evmc_address, beneficiary: *const ffi::evmc_address, ) { - match &mut CALLBACK.host_interface { - Some(host_interface) => { - host_interface.selfdestruct(&(*address).bytes, &(*beneficiary).bytes) - } - None => { - panic!("Host context not implemented"); - } - } + let mut map = HOST_CONTEXT_MAP.lock().unwrap(); + let host_interface = map + .get_mut(&(*(context as *const ExtendedContext)).index) + .unwrap(); + host_interface.selfdestruct(&(*address).bytes, &(*beneficiary).bytes) } -unsafe extern "C" fn get_tx_context(_context: *mut ffi::evmc_host_context) -> ffi::evmc_tx_context { - match &mut CALLBACK.host_interface { - Some(host_interface) => { - let (gas_price, origin, coinbase, number, timestamp, gas_limit, difficulty, chain_id) = - host_interface.get_tx_context(); - return ffi::evmc_tx_context { - tx_gas_price: evmc_sys::evmc_bytes32 { bytes: gas_price }, - tx_origin: evmc_sys::evmc_address { bytes: origin }, - block_coinbase: evmc_sys::evmc_address { bytes: coinbase }, - block_number: number, - block_timestamp: timestamp, - block_gas_limit: gas_limit, - block_difficulty: evmc_sys::evmc_bytes32 { bytes: difficulty }, - chain_id: evmc_sys::evmc_bytes32 { bytes: chain_id }, - }; - } - None => { - panic!("Host context not implemented"); - } - } +unsafe extern "C" fn get_tx_context(context: *mut ffi::evmc_host_context) -> ffi::evmc_tx_context { + let mut map = HOST_CONTEXT_MAP.lock().unwrap(); + let host_interface = map + .get_mut(&(*(context as *const ExtendedContext)).index) + .unwrap(); + let (gas_price, origin, coinbase, number, timestamp, gas_limit, difficulty, chain_id) = + host_interface.get_tx_context(); + return ffi::evmc_tx_context { + tx_gas_price: evmc_sys::evmc_bytes32 { bytes: gas_price }, + tx_origin: evmc_sys::evmc_address { bytes: origin }, + block_coinbase: evmc_sys::evmc_address { bytes: coinbase }, + block_number: number, + block_timestamp: timestamp, + block_gas_limit: gas_limit, + block_difficulty: evmc_sys::evmc_bytes32 { bytes: difficulty }, + chain_id: evmc_sys::evmc_bytes32 { bytes: chain_id }, + }; } unsafe extern "C" fn get_block_hash( - _context: *mut ffi::evmc_host_context, + context: *mut ffi::evmc_host_context, number: i64, ) -> ffi::evmc_bytes32 { - match &mut CALLBACK.host_interface { - Some(host_interface) => { - return ffi::evmc_bytes32 { - bytes: host_interface.get_block_hash(number), - }; - } - None => { - panic!("Host context not implemented"); - } - } + let mut map = HOST_CONTEXT_MAP.lock().unwrap(); + let host_interface = map + .get_mut(&(*(context as *const ExtendedContext)).index) + .unwrap(); + return ffi::evmc_bytes32 { + bytes: host_interface.get_block_hash(number), + }; } unsafe extern "C" fn emit_log( - _context: *mut ffi::evmc_host_context, + context: *mut ffi::evmc_host_context, address: *const ffi::evmc_address, data: *const u8, data_size: usize, topics: *const ffi::evmc_bytes32, topics_count: usize, ) { - match &mut CALLBACK.host_interface { - Some(host_interface) => { - let ts = &std::slice::from_raw_parts(topics, topics_count) - .iter() - .map(|topic| topic.bytes) - .collect::>(); - host_interface.emit_log( - &(*address).bytes, - &ts, - &std::slice::from_raw_parts(data, data_size), - ); - } - None => { - panic!("Host context not implemented"); - } - } + let mut map = HOST_CONTEXT_MAP.lock().unwrap(); + let host_interface = map + .get_mut(&(*(context as *const ExtendedContext)).index) + .unwrap(); + let ts = &std::slice::from_raw_parts(topics, topics_count) + .iter() + .map(|topic| topic.bytes) + .collect::>(); + host_interface.emit_log( + &(*address).bytes, + &ts, + &std::slice::from_raw_parts(data, data_size), + ); } unsafe extern "C" fn release(result: *const ffi::evmc_result) { @@ -277,39 +254,36 @@ unsafe extern "C" fn release(result: *const ffi::evmc_result) { } pub unsafe extern "C" fn call( - _context: *mut ffi::evmc_host_context, + context: *mut ffi::evmc_host_context, msg: *const ffi::evmc_message, ) -> ffi::evmc_result { - match &mut CALLBACK.host_interface { - Some(host_interface) => { - let msg = *msg; - let (output, gas_left, create_address, status_code) = host_interface.call( - msg.kind, - &msg.destination.bytes, - &msg.sender.bytes, - &msg.value.bytes, - &std::slice::from_raw_parts(msg.input_data, msg.input_size), - msg.gas, - msg.depth, - msg.flags != 0, - ); - let ptr = output.as_ptr(); - let len = output.len(); - mem::forget(output); - return ffi::evmc_result { - status_code: status_code, - gas_left: gas_left, - output_data: ptr, - output_size: len, - release: Some(release), - create_address: ffi::evmc_address { - bytes: create_address, - }, - padding: [0u8; 4], - }; - } - None => { - panic!("Host context not implemented"); - } - } + let mut map = HOST_CONTEXT_MAP.lock().unwrap(); + let host_interface = map + .get_mut(&(*(context as *const ExtendedContext)).index) + .unwrap(); + let msg = *msg; + let (output, gas_left, create_address, status_code) = host_interface.call( + msg.kind, + &msg.destination.bytes, + &msg.sender.bytes, + &msg.value.bytes, + &std::slice::from_raw_parts(msg.input_data, msg.input_size), + msg.gas, + msg.depth, + msg.flags != 0, + ); + let ptr = output.as_ptr(); + let len = output.len(); + mem::forget(output); + return ffi::evmc_result { + status_code: status_code, + gas_left: gas_left, + output_data: ptr, + output_size: len, + release: Some(release), + create_address: ffi::evmc_address { + bytes: create_address, + }, + padding: [0u8; 4], + }; } diff --git a/bindings/rust/evmc-client/src/lib.rs b/bindings/rust/evmc-client/src/lib.rs index 666d2d1cd..3522419c9 100644 --- a/bindings/rust/evmc-client/src/lib.rs +++ b/bindings/rust/evmc-client/src/lib.rs @@ -39,7 +39,6 @@ fn error(err: EvmcLoaderErrorCode) -> Result pub struct EvmcVm { handle: *mut ffi::evmc_vm, - host_context: *mut ffi::evmc_host_context, host_interface: *mut ffi::evmc_host_interface, } @@ -71,7 +70,7 @@ impl EvmcVm { pub fn execute( &self, - host_interface: Box, + ctx: Box, rev: Revision, kind: MessageKind, is_static: bool, @@ -84,15 +83,13 @@ impl EvmcVm { code: &Bytes, create2_salt: &Bytes32, ) -> (&Bytes, i64, StatusCode) { - host::set_host_interface(Some(host_interface)); - let evmc_destination = ffi::evmc_address { - bytes: *destination, - }; - let evmc_sender = ffi::evmc_address { bytes: *sender }; - let evmc_value = ffi::evmc_uint256be { bytes: *value }; - let evmc_create2_salt = ffi::evmc_bytes32 { - bytes: *create2_salt, - }; + let mut ext_ctx: host::ExtendedContext; + unsafe { + ext_ctx = host::ExtendedContext { + context: host::get_evmc_host_context(), + index: host::add_host_context(ctx), + }; + } let mut evmc_flags: u32 = 0; unsafe { if is_static { @@ -106,26 +103,29 @@ impl EvmcVm { flags: evmc_flags, depth: depth, gas: gas, - destination: evmc_destination, - sender: evmc_sender, + destination: ffi::evmc_address { + bytes: *destination, + }, + sender: ffi::evmc_address { bytes: *sender }, input_data: input.as_ptr(), input_size: input.len(), - value: evmc_value, - create2_salt: evmc_create2_salt, + value: ffi::evmc_uint256be { bytes: *value }, + create2_salt: ffi::evmc_bytes32 { + bytes: *create2_salt, + }, } })); - unsafe { let result = ((*self.handle).execute.unwrap())( self.handle, self.host_interface, - self.host_context, + &mut ext_ctx.context, rev, evmc_message, code.as_ptr(), code.len(), ); - host::set_host_interface(None); + host::remove_host_context(ext_ctx.index); return ( std::slice::from_raw_parts(result.output_data, result.output_size), result.gas_left, @@ -147,7 +147,6 @@ pub fn load(fname: &str) -> (EvmcVm, Result) ( EvmcVm { handle: instance, - host_context: Box::into_raw(Box::new(host::get_evmc_host_context())), host_interface: Box::into_raw(Box::new(host::get_evmc_host_interface())), }, error(ec), @@ -158,7 +157,6 @@ pub fn create() -> EvmcVm { unsafe { EvmcVm { handle: evmc_create(), - host_context: Box::into_raw(Box::new(host::get_evmc_host_context())), host_interface: Box::into_raw(Box::new(host::get_evmc_host_interface())), } }