diff --git a/bindings/rust/evmc-client/Cargo.toml b/bindings/rust/evmc-client/Cargo.toml index 7e252a227..63e7abae3 100644 --- a/bindings/rust/evmc-client/Cargo.toml +++ b/bindings/rust/evmc-client/Cargo.toml @@ -15,3 +15,4 @@ edition = "2018" evmc-sys = { path = "../evmc-sys", version = "7.4.0" } evmc-vm = { path = "../evmc-vm", version = "7.4.0" } libloading = "0.5" +lazy_static = "1.4.0" diff --git a/bindings/rust/evmc-client/src/host.rs b/bindings/rust/evmc-client/src/host.rs index 728525348..464445fca 100644 --- a/bindings/rust/evmc-client/src/host.rs +++ b/bindings/rust/evmc-client/src/host.rs @@ -5,9 +5,37 @@ 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 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 +66,7 @@ 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 { - 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 +84,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 +247,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..c1f895805 100644 --- a/bindings/rust/evmc-client/src/lib.rs +++ b/bindings/rust/evmc-client/src/lib.rs @@ -7,7 +7,6 @@ pub mod host; mod loader; pub mod types; pub use self::loader::EvmcLoaderErrorCode; - use crate::loader::evmc_load_and_create; use crate::types::*; use evmc_sys as ffi; @@ -39,7 +38,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 +69,7 @@ impl EvmcVm { pub fn execute( &self, - host_interface: Box, + ctx: Box, rev: Revision, kind: MessageKind, is_static: bool, @@ -84,15 +82,12 @@ 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 ext_ctx: *mut host::ExtendedContext; + unsafe { + ext_ctx = Box::into_raw(Box::new(host::ExtendedContext { + index: host::add_host_context(ctx), + })); + } let mut evmc_flags: u32 = 0; unsafe { if is_static { @@ -106,26 +101,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, + ext_ctx as *mut ffi::evmc_host_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 +145,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 +155,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())), } }