1use crate::EvmcVm;
7
8use std::ops::Deref;
9
10pub struct EvmcContainer<T>
12where
13 T: EvmcVm + Sized,
14{
15 #[allow(dead_code)]
16 instance: ::evmc_sys::evmc_vm,
17 vm: T,
18}
19
20impl<T> EvmcContainer<T>
21where
22 T: EvmcVm + Sized,
23{
24 pub fn new(_instance: ::evmc_sys::evmc_vm) -> Box<Self> {
26 Box::new(Self {
27 instance: _instance,
28 vm: T::init(),
29 })
30 }
31
32 pub unsafe fn from_ffi_pointer(instance: *mut ::evmc_sys::evmc_vm) -> Box<Self> {
37 assert!(!instance.is_null(), "from_ffi_pointer received NULL");
38 Box::from_raw(instance as *mut EvmcContainer<T>)
39 }
40
41 pub unsafe fn into_ffi_pointer(boxed: Box<Self>) -> *mut ::evmc_sys::evmc_vm {
46 Box::into_raw(boxed) as *mut ::evmc_sys::evmc_vm
47 }
48}
49
50impl<T> Deref for EvmcContainer<T>
51where
52 T: EvmcVm,
53{
54 type Target = T;
55
56 fn deref(&self) -> &Self::Target {
57 &self.vm
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64 use crate::types::*;
65 use crate::{ExecutionContext, ExecutionMessage, ExecutionResult};
66
67 struct TestVm {}
68
69 impl EvmcVm for TestVm {
70 fn init() -> Self {
71 TestVm {}
72 }
73 fn execute(
74 &self,
75 _revision: evmc_sys::evmc_revision,
76 _code: &[u8],
77 _message: &ExecutionMessage,
78 _context: Option<&mut ExecutionContext>,
79 ) -> ExecutionResult {
80 ExecutionResult::failure()
81 }
82 }
83
84 unsafe extern "C" fn get_dummy_tx_context(
85 _context: *mut evmc_sys::evmc_host_context,
86 ) -> evmc_sys::evmc_tx_context {
87 evmc_sys::evmc_tx_context {
88 tx_gas_price: Uint256::default(),
89 tx_origin: Address::default(),
90 block_coinbase: Address::default(),
91 block_number: 0,
92 block_timestamp: 0,
93 block_gas_limit: 0,
94 block_difficulty: Uint256::default(),
95 chain_id: Uint256::default(),
96 block_base_fee: Uint256::default(),
97 }
98 }
99
100 #[test]
101 fn container_new() {
102 let instance = ::evmc_sys::evmc_vm {
103 abi_version: ::evmc_sys::EVMC_ABI_VERSION as i32,
104 name: std::ptr::null(),
105 version: std::ptr::null(),
106 destroy: None,
107 execute: None,
108 get_capabilities: None,
109 set_option: None,
110 };
111
112 let code = [0u8; 0];
113
114 let message = ::evmc_sys::evmc_message {
115 kind: ::evmc_sys::evmc_call_kind::EVMC_CALL,
116 flags: 0,
117 depth: 0,
118 gas: 0,
119 destination: ::evmc_sys::evmc_address::default(),
120 sender: ::evmc_sys::evmc_address::default(),
121 input_data: std::ptr::null(),
122 input_size: 0,
123 value: ::evmc_sys::evmc_uint256be::default(),
124 create2_salt: ::evmc_sys::evmc_bytes32::default(),
125 };
126 let message: ExecutionMessage = (&message).into();
127
128 let host = ::evmc_sys::evmc_host_interface {
129 account_exists: None,
130 get_storage: None,
131 set_storage: None,
132 get_balance: None,
133 get_code_size: None,
134 get_code_hash: None,
135 copy_code: None,
136 selfdestruct: None,
137 call: None,
138 get_tx_context: Some(get_dummy_tx_context),
139 get_block_hash: None,
140 emit_log: None,
141 access_account: None,
142 access_storage: None,
143 };
144 let host_context = std::ptr::null_mut();
145
146 let mut context = ExecutionContext::new(&host, host_context);
147 let container = EvmcContainer::<TestVm>::new(instance);
148 assert_eq!(
149 container
150 .execute(
151 evmc_sys::evmc_revision::EVMC_PETERSBURG,
152 &code,
153 &message,
154 Some(&mut context)
155 )
156 .status_code(),
157 ::evmc_sys::evmc_status_code::EVMC_FAILURE
158 );
159
160 let ptr = unsafe { EvmcContainer::into_ffi_pointer(container) };
161
162 let mut context = ExecutionContext::new(&host, host_context);
163 let container = unsafe { EvmcContainer::<TestVm>::from_ffi_pointer(ptr) };
164 assert_eq!(
165 container
166 .execute(
167 evmc_sys::evmc_revision::EVMC_PETERSBURG,
168 &code,
169 &message,
170 Some(&mut context)
171 )
172 .status_code(),
173 ::evmc_sys::evmc_status_code::EVMC_FAILURE
174 );
175 }
176}