evmc_vm/
lib.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
6//! Rust bindings for EVMC (Ethereum Client-VM Connector API).
7//!
8//! Have a look at evmc-declare to declare an EVMC compatible VM.
9//! This crate documents how to use certain data types.
10
11mod container;
12mod types;
13
14pub use container::EvmcContainer;
15pub use evmc_sys as ffi;
16pub use types::*;
17
18/// Trait EVMC VMs have to implement.
19pub trait EvmcVm {
20    /// This is called once at initialisation time.
21    fn init() -> Self;
22    /// This is called for every incoming message.
23    fn execute<'a>(
24        &self,
25        revision: Revision,
26        code: &'a [u8],
27        message: &'a ExecutionMessage,
28        context: Option<&'a mut ExecutionContext<'a>>,
29    ) -> ExecutionResult;
30}
31
32/// EVMC result structure.
33#[derive(Debug)]
34pub struct ExecutionResult {
35    status_code: StatusCode,
36    gas_left: i64,
37    output: Option<Vec<u8>>,
38    create_address: Option<Address>,
39}
40
41/// EVMC execution message structure.
42#[derive(Debug)]
43pub struct ExecutionMessage {
44    kind: MessageKind,
45    flags: u32,
46    depth: i32,
47    gas: i64,
48    destination: Address,
49    sender: Address,
50    input: Option<Vec<u8>>,
51    value: Uint256,
52    create2_salt: Bytes32,
53}
54
55/// EVMC transaction context structure.
56pub type ExecutionTxContext = ffi::evmc_tx_context;
57
58/// EVMC context structure. Exposes the EVMC host functions, message data, and transaction context
59/// to the executing VM.
60pub struct ExecutionContext<'a> {
61    host: &'a ffi::evmc_host_interface,
62    context: *mut ffi::evmc_host_context,
63    tx_context: ExecutionTxContext,
64}
65
66impl ExecutionResult {
67    /// Manually create a result.
68    pub fn new(_status_code: StatusCode, _gas_left: i64, _output: Option<&[u8]>) -> Self {
69        ExecutionResult {
70            status_code: _status_code,
71            gas_left: _gas_left,
72            output: if let Some(output) = _output {
73                Some(output.to_vec())
74            } else {
75                None
76            },
77            create_address: None,
78        }
79    }
80
81    /// Create failure result.
82    pub fn failure() -> Self {
83        ExecutionResult::new(StatusCode::EVMC_FAILURE, 0, None)
84    }
85
86    /// Create a revert result.
87    pub fn revert(_gas_left: i64, _output: Option<&[u8]>) -> Self {
88        ExecutionResult::new(StatusCode::EVMC_REVERT, _gas_left, _output)
89    }
90
91    /// Create a successful result.
92    pub fn success(_gas_left: i64, _output: Option<&[u8]>) -> Self {
93        ExecutionResult::new(StatusCode::EVMC_SUCCESS, _gas_left, _output)
94    }
95
96    /// Read the status code.
97    pub fn status_code(&self) -> StatusCode {
98        self.status_code
99    }
100
101    /// Read the amount of gas left.
102    pub fn gas_left(&self) -> i64 {
103        self.gas_left
104    }
105
106    /// Read the output returned.
107    pub fn output(&self) -> Option<&Vec<u8>> {
108        self.output.as_ref()
109    }
110
111    /// Read the address of the created account. This will likely be set when
112    /// returned from a CREATE/CREATE2.
113    pub fn create_address(&self) -> Option<&Address> {
114        self.create_address.as_ref()
115    }
116}
117
118impl ExecutionMessage {
119    pub fn new(
120        kind: MessageKind,
121        flags: u32,
122        depth: i32,
123        gas: i64,
124        destination: Address,
125        sender: Address,
126        input: Option<&[u8]>,
127        value: Uint256,
128        create2_salt: Bytes32,
129    ) -> Self {
130        ExecutionMessage {
131            kind,
132            flags,
133            depth,
134            gas,
135            destination,
136            sender,
137            input: if let Some(input) = input {
138                Some(input.to_vec())
139            } else {
140                None
141            },
142            value,
143            create2_salt,
144        }
145    }
146
147    /// Read the message kind.
148    pub fn kind(&self) -> MessageKind {
149        self.kind
150    }
151
152    /// Read the message flags.
153    pub fn flags(&self) -> u32 {
154        self.flags
155    }
156
157    /// Read the call depth.
158    pub fn depth(&self) -> i32 {
159        self.depth
160    }
161
162    /// Read the gas limit supplied with the message.
163    pub fn gas(&self) -> i64 {
164        self.gas
165    }
166
167    /// Read the destination address of the message.
168    pub fn destination(&self) -> &Address {
169        &self.destination
170    }
171
172    /// Read the sender address of the message.
173    pub fn sender(&self) -> &Address {
174        &self.sender
175    }
176
177    /// Read the optional input message.
178    pub fn input(&self) -> Option<&Vec<u8>> {
179        self.input.as_ref()
180    }
181
182    /// Read the value of the message.
183    pub fn value(&self) -> &Uint256 {
184        &self.value
185    }
186
187    /// Read the salt for CREATE2. Only valid if the message kind is CREATE2.
188    pub fn create2_salt(&self) -> &Bytes32 {
189        &self.create2_salt
190    }
191}
192
193impl<'a> ExecutionContext<'a> {
194    pub fn new(host: &'a ffi::evmc_host_interface, _context: *mut ffi::evmc_host_context) -> Self {
195        let _tx_context = unsafe {
196            assert!((*host).get_tx_context.is_some());
197            (*host).get_tx_context.unwrap()(_context)
198        };
199
200        ExecutionContext {
201            host: host,
202            context: _context,
203            tx_context: _tx_context,
204        }
205    }
206
207    /// Retrieve the transaction context.
208    pub fn get_tx_context(&self) -> &ExecutionTxContext {
209        &self.tx_context
210    }
211
212    /// Check if an account exists.
213    pub fn account_exists(&self, address: &Address) -> bool {
214        unsafe {
215            assert!((*self.host).account_exists.is_some());
216            (*self.host).account_exists.unwrap()(self.context, address as *const Address)
217        }
218    }
219
220    /// Read from a storage key.
221    pub fn get_storage(&self, address: &Address, key: &Bytes32) -> Bytes32 {
222        unsafe {
223            assert!((*self.host).get_storage.is_some());
224            (*self.host).get_storage.unwrap()(
225                self.context,
226                address as *const Address,
227                key as *const Bytes32,
228            )
229        }
230    }
231
232    /// Set value of a storage key.
233    pub fn set_storage(
234        &mut self,
235        address: &Address,
236        key: &Bytes32,
237        value: &Bytes32,
238    ) -> StorageStatus {
239        unsafe {
240            assert!((*self.host).set_storage.is_some());
241            (*self.host).set_storage.unwrap()(
242                self.context,
243                address as *const Address,
244                key as *const Bytes32,
245                value as *const Bytes32,
246            )
247        }
248    }
249
250    /// Get balance of an account.
251    pub fn get_balance(&self, address: &Address) -> Uint256 {
252        unsafe {
253            assert!((*self.host).get_balance.is_some());
254            (*self.host).get_balance.unwrap()(self.context, address as *const Address)
255        }
256    }
257
258    /// Get code size of an account.
259    pub fn get_code_size(&self, address: &Address) -> usize {
260        unsafe {
261            assert!((*self.host).get_code_size.is_some());
262            (*self.host).get_code_size.unwrap()(self.context, address as *const Address)
263        }
264    }
265
266    /// Get code hash of an account.
267    pub fn get_code_hash(&self, address: &Address) -> Bytes32 {
268        unsafe {
269            assert!((*self.host).get_code_size.is_some());
270            (*self.host).get_code_hash.unwrap()(self.context, address as *const Address)
271        }
272    }
273
274    /// Copy code of an account.
275    pub fn copy_code(&self, address: &Address, code_offset: usize, buffer: &mut [u8]) -> usize {
276        unsafe {
277            assert!((*self.host).copy_code.is_some());
278            (*self.host).copy_code.unwrap()(
279                self.context,
280                address as *const Address,
281                code_offset,
282                // FIXME: ensure that alignment of the array elements is OK
283                buffer.as_mut_ptr(),
284                buffer.len(),
285            )
286        }
287    }
288
289    /// Self-destruct the current account.
290    pub fn selfdestruct(&mut self, address: &Address, beneficiary: &Address) {
291        unsafe {
292            assert!((*self.host).selfdestruct.is_some());
293            (*self.host).selfdestruct.unwrap()(
294                self.context,
295                address as *const Address,
296                beneficiary as *const Address,
297            )
298        }
299    }
300
301    /// Call to another account.
302    pub fn call(&mut self, message: &ExecutionMessage) -> ExecutionResult {
303        // There is no need to make any kind of copies here, because the caller
304        // won't go out of scope and ensures these pointers remain valid.
305        let input = message.input();
306        let input_size = if let Some(input) = input {
307            input.len()
308        } else {
309            0
310        };
311        let input_data = if let Some(input) = input {
312            input.as_ptr()
313        } else {
314            std::ptr::null() as *const u8
315        };
316        // Cannot use a nice from trait here because that complicates memory management,
317        // evmc_message doesn't have a release() method we could abstract it with.
318        let message = ffi::evmc_message {
319            kind: message.kind(),
320            flags: message.flags(),
321            depth: message.depth(),
322            gas: message.gas(),
323            destination: *message.destination(),
324            sender: *message.sender(),
325            input_data: input_data,
326            input_size: input_size,
327            value: *message.value(),
328            create2_salt: *message.create2_salt(),
329        };
330        unsafe {
331            assert!((*self.host).call.is_some());
332            (*self.host).call.unwrap()(self.context, &message as *const ffi::evmc_message).into()
333        }
334    }
335
336    /// Get block hash of an account.
337    pub fn get_block_hash(&self, num: i64) -> Bytes32 {
338        unsafe {
339            assert!((*self.host).get_block_hash.is_some());
340            (*self.host).get_block_hash.unwrap()(self.context, num)
341        }
342    }
343
344    /// Emit a log.
345    pub fn emit_log(&mut self, address: &Address, data: &[u8], topics: &[Bytes32]) {
346        unsafe {
347            assert!((*self.host).emit_log.is_some());
348            (*self.host).emit_log.unwrap()(
349                self.context,
350                address as *const Address,
351                // FIXME: ensure that alignment of the array elements is OK
352                data.as_ptr(),
353                data.len(),
354                topics.as_ptr(),
355                topics.len(),
356            )
357        }
358    }
359
360    /// Access an account.
361    pub fn access_account(&mut self, address: &Address) -> AccessStatus {
362        unsafe {
363            assert!((*self.host).access_account.is_some());
364            (*self.host).access_account.unwrap()(self.context, address as *const Address)
365        }
366    }
367
368    /// Access a storage key.
369    pub fn access_storage(&mut self, address: &Address, key: &Bytes32) -> AccessStatus {
370        unsafe {
371            assert!((*self.host).access_storage.is_some());
372            (*self.host).access_storage.unwrap()(
373                self.context,
374                address as *const Address,
375                key as *const Bytes32,
376            )
377        }
378    }
379}
380
381impl From<ffi::evmc_result> for ExecutionResult {
382    fn from(result: ffi::evmc_result) -> Self {
383        let ret = ExecutionResult {
384            status_code: result.status_code,
385            gas_left: result.gas_left,
386            output: if result.output_data.is_null() {
387                assert_eq!(result.output_size, 0);
388                None
389            } else if result.output_size == 0 {
390                None
391            } else {
392                Some(from_buf_raw::<u8>(result.output_data, result.output_size))
393            },
394            // Consider it is always valid.
395            create_address: Some(result.create_address),
396        };
397
398        // Release allocated ffi struct.
399        if result.release.is_some() {
400            unsafe {
401                result.release.unwrap()(&result as *const ffi::evmc_result);
402            }
403        }
404
405        ret
406    }
407}
408
409fn allocate_output_data(output: Option<&Vec<u8>>) -> (*const u8, usize) {
410    if let Some(buf) = output {
411        let buf_len = buf.len();
412
413        // Manually allocate heap memory for the new home of the output buffer.
414        let memlayout = std::alloc::Layout::from_size_align(buf_len, 1).expect("Bad layout");
415        let new_buf = unsafe { std::alloc::alloc(memlayout) };
416        unsafe {
417            // Copy the data into the allocated buffer.
418            std::ptr::copy(buf.as_ptr(), new_buf, buf_len);
419        }
420
421        (new_buf as *const u8, buf_len)
422    } else {
423        (std::ptr::null(), 0)
424    }
425}
426
427unsafe fn deallocate_output_data(ptr: *const u8, size: usize) {
428    if !ptr.is_null() {
429        let buf_layout = std::alloc::Layout::from_size_align(size, 1).expect("Bad layout");
430        std::alloc::dealloc(ptr as *mut u8, buf_layout);
431    }
432}
433
434/// Returns a pointer to a heap-allocated evmc_result.
435impl Into<*const ffi::evmc_result> for ExecutionResult {
436    fn into(self) -> *const ffi::evmc_result {
437        let mut result: ffi::evmc_result = self.into();
438        result.release = Some(release_heap_result);
439        Box::into_raw(Box::new(result))
440    }
441}
442
443/// Callback to pass across FFI, de-allocating the optional output_data.
444extern "C" fn release_heap_result(result: *const ffi::evmc_result) {
445    unsafe {
446        let tmp = Box::from_raw(result as *mut ffi::evmc_result);
447        deallocate_output_data(tmp.output_data, tmp.output_size);
448    }
449}
450
451/// Returns a pointer to a stack-allocated evmc_result.
452impl Into<ffi::evmc_result> for ExecutionResult {
453    fn into(self) -> ffi::evmc_result {
454        let (buffer, len) = allocate_output_data(self.output.as_ref());
455        ffi::evmc_result {
456            status_code: self.status_code,
457            gas_left: self.gas_left,
458            output_data: buffer,
459            output_size: len,
460            release: Some(release_stack_result),
461            create_address: if self.create_address.is_some() {
462                self.create_address.unwrap()
463            } else {
464                Address { bytes: [0u8; 20] }
465            },
466            padding: [0u8; 4],
467        }
468    }
469}
470
471/// Callback to pass across FFI, de-allocating the optional output_data.
472extern "C" fn release_stack_result(result: *const ffi::evmc_result) {
473    unsafe {
474        let tmp = *result;
475        deallocate_output_data(tmp.output_data, tmp.output_size);
476    }
477}
478
479impl From<&ffi::evmc_message> for ExecutionMessage {
480    fn from(message: &ffi::evmc_message) -> Self {
481        ExecutionMessage {
482            kind: message.kind,
483            flags: message.flags,
484            depth: message.depth,
485            gas: message.gas,
486            destination: message.destination,
487            sender: message.sender,
488            input: if message.input_data.is_null() {
489                assert_eq!(message.input_size, 0);
490                None
491            } else if message.input_size == 0 {
492                None
493            } else {
494                Some(from_buf_raw::<u8>(message.input_data, message.input_size))
495            },
496            value: message.value,
497            create2_salt: message.create2_salt,
498        }
499    }
500}
501
502fn from_buf_raw<T>(ptr: *const T, size: usize) -> Vec<T> {
503    // Pre-allocate a vector.
504    let mut buf = Vec::with_capacity(size);
505    unsafe {
506        // Set the len of the vec manually.
507        buf.set_len(size);
508        // Copy from the C buffer to the vec's buffer.
509        std::ptr::copy(ptr, buf.as_mut_ptr(), size);
510    }
511    buf
512}
513
514#[cfg(test)]
515mod tests {
516    use super::*;
517
518    #[test]
519    fn result_new() {
520        let r = ExecutionResult::new(StatusCode::EVMC_FAILURE, 420, None);
521
522        assert_eq!(r.status_code(), StatusCode::EVMC_FAILURE);
523        assert_eq!(r.gas_left(), 420);
524        assert!(r.output().is_none());
525        assert!(r.create_address().is_none());
526    }
527
528    // Test-specific helper to dispose of execution results in unit tests
529    extern "C" fn test_result_dispose(result: *const ffi::evmc_result) {
530        unsafe {
531            if !result.is_null() {
532                let owned = *result;
533                Vec::from_raw_parts(
534                    owned.output_data as *mut u8,
535                    owned.output_size,
536                    owned.output_size,
537                );
538            }
539        }
540    }
541
542    #[test]
543    fn result_from_ffi() {
544        let f = ffi::evmc_result {
545            status_code: StatusCode::EVMC_SUCCESS,
546            gas_left: 1337,
547            output_data: Box::into_raw(Box::new([0xde, 0xad, 0xbe, 0xef])) as *const u8,
548            output_size: 4,
549            release: Some(test_result_dispose),
550            create_address: Address { bytes: [0u8; 20] },
551            padding: [0u8; 4],
552        };
553
554        let r: ExecutionResult = f.into();
555
556        assert_eq!(r.status_code(), StatusCode::EVMC_SUCCESS);
557        assert_eq!(r.gas_left(), 1337);
558        assert!(r.output().is_some());
559        assert_eq!(r.output().unwrap().len(), 4);
560        assert!(r.create_address().is_some());
561    }
562
563    #[test]
564    fn result_into_heap_ffi() {
565        let r = ExecutionResult::new(
566            StatusCode::EVMC_FAILURE,
567            420,
568            Some(&[0xc0, 0xff, 0xee, 0x71, 0x75]),
569        );
570
571        let f: *const ffi::evmc_result = r.into();
572        assert!(!f.is_null());
573        unsafe {
574            assert_eq!((*f).status_code, StatusCode::EVMC_FAILURE);
575            assert_eq!((*f).gas_left, 420);
576            assert!(!(*f).output_data.is_null());
577            assert_eq!((*f).output_size, 5);
578            assert_eq!(
579                std::slice::from_raw_parts((*f).output_data, 5) as &[u8],
580                &[0xc0, 0xff, 0xee, 0x71, 0x75]
581            );
582            assert_eq!((*f).create_address.bytes, [0u8; 20]);
583            if (*f).release.is_some() {
584                (*f).release.unwrap()(f);
585            }
586        }
587    }
588
589    #[test]
590    fn result_into_heap_ffi_empty_data() {
591        let r = ExecutionResult::new(StatusCode::EVMC_FAILURE, 420, None);
592
593        let f: *const ffi::evmc_result = r.into();
594        assert!(!f.is_null());
595        unsafe {
596            assert_eq!((*f).status_code, StatusCode::EVMC_FAILURE);
597            assert_eq!((*f).gas_left, 420);
598            assert!((*f).output_data.is_null());
599            assert_eq!((*f).output_size, 0);
600            assert_eq!((*f).create_address.bytes, [0u8; 20]);
601            if (*f).release.is_some() {
602                (*f).release.unwrap()(f);
603            }
604        }
605    }
606
607    #[test]
608    fn result_into_stack_ffi() {
609        let r = ExecutionResult::new(
610            StatusCode::EVMC_FAILURE,
611            420,
612            Some(&[0xc0, 0xff, 0xee, 0x71, 0x75]),
613        );
614
615        let f: ffi::evmc_result = r.into();
616        unsafe {
617            assert_eq!(f.status_code, StatusCode::EVMC_FAILURE);
618            assert_eq!(f.gas_left, 420);
619            assert!(!f.output_data.is_null());
620            assert_eq!(f.output_size, 5);
621            assert_eq!(
622                std::slice::from_raw_parts(f.output_data, 5) as &[u8],
623                &[0xc0, 0xff, 0xee, 0x71, 0x75]
624            );
625            assert_eq!(f.create_address.bytes, [0u8; 20]);
626            if f.release.is_some() {
627                f.release.unwrap()(&f);
628            }
629        }
630    }
631
632    #[test]
633    fn result_into_stack_ffi_empty_data() {
634        let r = ExecutionResult::new(StatusCode::EVMC_FAILURE, 420, None);
635
636        let f: ffi::evmc_result = r.into();
637        unsafe {
638            assert_eq!(f.status_code, StatusCode::EVMC_FAILURE);
639            assert_eq!(f.gas_left, 420);
640            assert!(f.output_data.is_null());
641            assert_eq!(f.output_size, 0);
642            assert_eq!(f.create_address.bytes, [0u8; 20]);
643            if f.release.is_some() {
644                f.release.unwrap()(&f);
645            }
646        }
647    }
648
649    #[test]
650    fn message_new_with_input() {
651        let input = vec![0xc0, 0xff, 0xee];
652        let destination = Address { bytes: [32u8; 20] };
653        let sender = Address { bytes: [128u8; 20] };
654        let value = Uint256 { bytes: [0u8; 32] };
655        let create2_salt = Bytes32 { bytes: [255u8; 32] };
656
657        let ret = ExecutionMessage::new(
658            MessageKind::EVMC_CALL,
659            44,
660            66,
661            4466,
662            destination,
663            sender,
664            Some(&input),
665            value,
666            create2_salt,
667        );
668
669        assert_eq!(ret.kind(), MessageKind::EVMC_CALL);
670        assert_eq!(ret.flags(), 44);
671        assert_eq!(ret.depth(), 66);
672        assert_eq!(ret.gas(), 4466);
673        assert_eq!(*ret.destination(), destination);
674        assert_eq!(*ret.sender(), sender);
675        assert!(ret.input().is_some());
676        assert_eq!(*ret.input().unwrap(), input);
677        assert_eq!(*ret.value(), value);
678        assert_eq!(*ret.create2_salt(), create2_salt);
679    }
680
681    #[test]
682    fn message_from_ffi() {
683        let destination = Address { bytes: [32u8; 20] };
684        let sender = Address { bytes: [128u8; 20] };
685        let value = Uint256 { bytes: [0u8; 32] };
686        let create2_salt = Bytes32 { bytes: [255u8; 32] };
687
688        let msg = ffi::evmc_message {
689            kind: MessageKind::EVMC_CALL,
690            flags: 44,
691            depth: 66,
692            gas: 4466,
693            destination: destination,
694            sender: sender,
695            input_data: std::ptr::null(),
696            input_size: 0,
697            value: value,
698            create2_salt: create2_salt,
699        };
700
701        let ret: ExecutionMessage = (&msg).into();
702
703        assert_eq!(ret.kind(), msg.kind);
704        assert_eq!(ret.flags(), msg.flags);
705        assert_eq!(ret.depth(), msg.depth);
706        assert_eq!(ret.gas(), msg.gas);
707        assert_eq!(*ret.destination(), msg.destination);
708        assert_eq!(*ret.sender(), msg.sender);
709        assert!(ret.input().is_none());
710        assert_eq!(*ret.value(), msg.value);
711        assert_eq!(*ret.create2_salt(), msg.create2_salt);
712    }
713
714    #[test]
715    fn message_from_ffi_with_input() {
716        let input = vec![0xc0, 0xff, 0xee];
717        let destination = Address { bytes: [32u8; 20] };
718        let sender = Address { bytes: [128u8; 20] };
719        let value = Uint256 { bytes: [0u8; 32] };
720        let create2_salt = Bytes32 { bytes: [255u8; 32] };
721
722        let msg = ffi::evmc_message {
723            kind: MessageKind::EVMC_CALL,
724            flags: 44,
725            depth: 66,
726            gas: 4466,
727            destination: destination,
728            sender: sender,
729            input_data: input.as_ptr(),
730            input_size: input.len(),
731            value: value,
732            create2_salt: create2_salt,
733        };
734
735        let ret: ExecutionMessage = (&msg).into();
736
737        assert_eq!(ret.kind(), msg.kind);
738        assert_eq!(ret.flags(), msg.flags);
739        assert_eq!(ret.depth(), msg.depth);
740        assert_eq!(ret.gas(), msg.gas);
741        assert_eq!(*ret.destination(), msg.destination);
742        assert_eq!(*ret.sender(), msg.sender);
743        assert!(ret.input().is_some());
744        assert_eq!(*ret.input().unwrap(), input);
745        assert_eq!(*ret.value(), msg.value);
746        assert_eq!(*ret.create2_salt(), msg.create2_salt);
747    }
748
749    unsafe extern "C" fn get_dummy_tx_context(
750        _context: *mut ffi::evmc_host_context,
751    ) -> ffi::evmc_tx_context {
752        ffi::evmc_tx_context {
753            tx_gas_price: Uint256 { bytes: [0u8; 32] },
754            tx_origin: Address { bytes: [0u8; 20] },
755            block_coinbase: Address { bytes: [0u8; 20] },
756            block_number: 42,
757            block_timestamp: 235117,
758            block_gas_limit: 105023,
759            block_difficulty: Uint256 { bytes: [0xaa; 32] },
760            chain_id: Uint256::default(),
761            block_base_fee: Uint256::default(),
762        }
763    }
764
765    unsafe extern "C" fn get_dummy_code_size(
766        _context: *mut ffi::evmc_host_context,
767        _addr: *const Address,
768    ) -> usize {
769        105023 as usize
770    }
771
772    unsafe extern "C" fn execute_call(
773        _context: *mut ffi::evmc_host_context,
774        _msg: *const ffi::evmc_message,
775    ) -> ffi::evmc_result {
776        // Some dumb validation for testing.
777        let msg = *_msg;
778        let success = if msg.input_size != 0 && msg.input_data == std::ptr::null() {
779            false
780        } else if msg.input_size == 0 && msg.input_data != std::ptr::null() {
781            false
782        } else {
783            true
784        };
785
786        ffi::evmc_result {
787            status_code: if success {
788                StatusCode::EVMC_SUCCESS
789            } else {
790                StatusCode::EVMC_INTERNAL_ERROR
791            },
792            gas_left: 2,
793            // NOTE: we are passing the input pointer here, but for testing the lifetime is ok
794            output_data: msg.input_data,
795            output_size: msg.input_size,
796            release: None,
797            create_address: Address::default(),
798            padding: [0u8; 4],
799        }
800    }
801
802    // Update these when needed for tests
803    fn get_dummy_host_interface() -> ffi::evmc_host_interface {
804        ffi::evmc_host_interface {
805            account_exists: None,
806            get_storage: None,
807            set_storage: None,
808            get_balance: None,
809            get_code_size: Some(get_dummy_code_size),
810            get_code_hash: None,
811            copy_code: None,
812            selfdestruct: None,
813            call: Some(execute_call),
814            get_tx_context: Some(get_dummy_tx_context),
815            get_block_hash: None,
816            emit_log: None,
817            access_account: None,
818            access_storage: None,
819        }
820    }
821
822    #[test]
823    fn execution_context() {
824        let host_context = std::ptr::null_mut();
825        let host_interface = get_dummy_host_interface();
826        let exe_context = ExecutionContext::new(&host_interface, host_context);
827        let a = exe_context.get_tx_context();
828
829        let b = unsafe { get_dummy_tx_context(host_context) };
830
831        assert_eq!(a.block_gas_limit, b.block_gas_limit);
832        assert_eq!(a.block_timestamp, b.block_timestamp);
833        assert_eq!(a.block_number, b.block_number);
834    }
835
836    #[test]
837    fn get_code_size() {
838        // This address is useless. Just a dummy parameter for the interface function.
839        let test_addr = Address { bytes: [0u8; 20] };
840        let host = get_dummy_host_interface();
841        let host_context = std::ptr::null_mut();
842
843        let mut exe_context = ExecutionContext::new(&host, host_context);
844
845        let a: usize = 105023;
846        let b = exe_context.get_code_size(&test_addr);
847
848        assert_eq!(a, b);
849    }
850
851    #[test]
852    fn test_call_empty_data() {
853        // This address is useless. Just a dummy parameter for the interface function.
854        let test_addr = Address::default();
855        let host = get_dummy_host_interface();
856        let host_context = std::ptr::null_mut();
857        let mut exe_context = ExecutionContext::new(&host, host_context);
858
859        let message = ExecutionMessage::new(
860            MessageKind::EVMC_CALL,
861            0,
862            0,
863            6566,
864            test_addr,
865            test_addr,
866            None,
867            Uint256::default(),
868            Bytes32::default(),
869        );
870
871        let b = exe_context.call(&message);
872
873        assert_eq!(b.status_code(), StatusCode::EVMC_SUCCESS);
874        assert_eq!(b.gas_left(), 2);
875        assert!(b.output().is_none());
876        assert!(b.create_address().is_some());
877        assert_eq!(b.create_address().unwrap(), &Address::default());
878    }
879
880    #[test]
881    fn test_call_with_data() {
882        // This address is useless. Just a dummy parameter for the interface function.
883        let test_addr = Address::default();
884        let host = get_dummy_host_interface();
885        let host_context = std::ptr::null_mut();
886        let mut exe_context = ExecutionContext::new(&host, host_context);
887
888        let data = vec![0xc0, 0xff, 0xfe];
889
890        let message = ExecutionMessage::new(
891            MessageKind::EVMC_CALL,
892            0,
893            0,
894            6566,
895            test_addr,
896            test_addr,
897            Some(&data),
898            Uint256::default(),
899            Bytes32::default(),
900        );
901
902        let b = exe_context.call(&message);
903
904        assert_eq!(b.status_code(), StatusCode::EVMC_SUCCESS);
905        assert_eq!(b.gas_left(), 2);
906        assert!(b.output().is_some());
907        assert_eq!(b.output().unwrap(), &data);
908        assert!(b.create_address().is_some());
909        assert_eq!(b.create_address().unwrap(), &Address::default());
910    }
911}