evmc_vm/
container.rs

1/* EVMC: Ethereum Client-VM Connector API.
2 * Copyright 2019 The EVMC Authors.
3 * Licensed under the Apache License, Version 2.0.
4 */
5
6use crate::EvmcVm;
7
8use std::ops::Deref;
9
10/// Container struct for EVMC instances and user-defined data.
11pub 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    /// Basic constructor.
25    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    /// Take ownership of the given pointer and return a box.
33    ///
34    /// # Safety
35    /// This function expects a valid instance to be passed.
36    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    /// Convert boxed self into an FFI pointer, surrendering ownership of the heap data.
42    ///
43    /// # Safety
44    /// This function will return a valid instance pointer.
45    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}