1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(test), warn(unused_extern_crates))]
3#![cfg_attr(docsrs, feature(doc_cfg))]
4#![cfg_attr(not(feature = "std"), no_std)]
5
6extern crate alloc;
7
8use alloc::vec::Vec;
9use core::{fmt, mem::MaybeUninit, ptr};
10use revm_interpreter::{
11 interpreter_types::{Jumps, ReturnData},
12 Gas, Host, InputsImpl, InstructionResult, Interpreter, InterpreterAction, InterpreterResult,
13 SharedMemory,
14};
15use revm_primitives::{ruint, Address, Bytes, U256};
16
17#[cfg(feature = "host-ext-any")]
18use core::any::Any;
19
20#[repr(C)]
29pub struct EvmContext<'a> {
30 pub memory: &'a mut SharedMemory,
32 pub input: &'a mut InputsImpl,
34 pub gas: &'a mut Gas,
36 pub host: &'a mut dyn HostExt,
38 pub next_action: &'a mut Option<InterpreterAction>,
40 pub return_data: &'a [u8],
42 pub is_static: bool,
44 #[doc(hidden)]
47 pub resume_at: usize,
48}
49
50const _: () = {
53 use core::mem::offset_of;
54 assert!(core::mem::size_of::<EvmContext<'_>>() == 80);
56 assert!(offset_of!(EvmContext<'_>, memory) == 0);
58 assert!(offset_of!(EvmContext<'_>, resume_at) == 72);
59};
60
61impl fmt::Debug for EvmContext<'_> {
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 f.debug_struct("EvmContext").field("memory", &self.memory).finish_non_exhaustive()
64 }
65}
66
67impl<'a> EvmContext<'a> {
68 #[inline]
70 pub fn from_interpreter(interpreter: &'a mut Interpreter, host: &'a mut dyn HostExt) -> Self {
71 Self::from_interpreter_with_stack(interpreter, host).0
72 }
73
74 #[inline]
76 pub fn from_interpreter_with_stack<'b: 'a>(
77 interpreter: &'a mut Interpreter,
78 host: &'b mut dyn HostExt,
79 ) -> (Self, &'a mut EvmStack, &'a mut usize) {
80 use revm_interpreter::interpreter_types::LegacyBytecode;
81
82 let (stack, stack_len) = EvmStack::from_interpreter_stack(&mut interpreter.stack);
83 let bytecode_slice = interpreter.bytecode.bytecode_slice();
84 let resume_at = ResumeAt::load(interpreter.bytecode.pc(), bytecode_slice);
85 let this = Self {
86 memory: &mut interpreter.memory,
87 input: &mut interpreter.input,
88 gas: &mut interpreter.gas,
89 host,
90 next_action: &mut interpreter.bytecode.action,
91 return_data: interpreter.return_data.buffer(),
92 is_static: interpreter.runtime_flag.is_static,
93 resume_at,
94 };
95 (this, stack, stack_len)
96 }
97}
98
99#[cfg(not(feature = "host-ext-any"))]
101pub trait HostExt: Host {}
102
103#[cfg(not(feature = "host-ext-any"))]
104impl<T: Host> HostExt for T {}
105
106#[cfg(feature = "host-ext-any")]
108pub trait HostExt: Host + Any {
109 #[doc(hidden)]
110 fn as_any(&self) -> &dyn Any;
111 #[doc(hidden)]
112 fn as_any_mut(&mut self) -> &mut dyn Any;
113}
114
115#[cfg(feature = "host-ext-any")]
116impl<T: Host + Any> HostExt for T {
117 fn as_any(&self) -> &dyn Any {
118 self
119 }
120
121 fn as_any_mut(&mut self) -> &mut dyn Any {
122 self
123 }
124}
125
126#[cfg(feature = "host-ext-any")]
127#[doc(hidden)]
128impl dyn HostExt {
129 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
131 self.as_any().downcast_ref()
132 }
133
134 pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
136 self.as_any_mut().downcast_mut()
137 }
138}
139
140#[macro_export]
155macro_rules! extern_revmc {
156 ($( $(#[$attr:meta])* $vis:vis fn $name:ident; )+) => {
157 #[allow(improper_ctypes)]
158 extern "C" {
159 $(
160 $(#[$attr])*
161 $vis fn $name(
162 gas: *mut $crate::private::revm_interpreter::Gas,
163 stack: *mut $crate::EvmStack,
164 stack_len: *mut usize,
165 input: *const $crate::private::revm_interpreter::InputsImpl,
166 ecx: *mut $crate::EvmContext<'_>,
167 ) -> $crate::private::revm_interpreter::InstructionResult;
168 )+
169 }
170 };
171}
172
173pub type RawEvmCompilerFn = unsafe extern "C" fn(
179 gas: *mut Gas,
180 stack: *mut EvmStack,
181 stack_len: *mut usize,
182 input: *const InputsImpl,
183 ecx: *mut EvmContext<'_>,
184) -> InstructionResult;
185
186#[derive(Clone, Copy, Debug, Hash)]
188pub struct EvmCompilerFn(RawEvmCompilerFn);
189
190impl From<RawEvmCompilerFn> for EvmCompilerFn {
191 #[inline]
192 fn from(f: RawEvmCompilerFn) -> Self {
193 Self::new(f)
194 }
195}
196
197impl From<EvmCompilerFn> for RawEvmCompilerFn {
198 #[inline]
199 fn from(f: EvmCompilerFn) -> Self {
200 f.into_inner()
201 }
202}
203
204impl EvmCompilerFn {
205 #[inline]
207 pub const fn new(f: RawEvmCompilerFn) -> Self {
208 Self(f)
209 }
210
211 #[inline]
213 pub const fn into_inner(self) -> RawEvmCompilerFn {
214 self.0
215 }
216
217 #[inline]
226 pub unsafe fn call_with_interpreter_and_memory(
227 self,
228 interpreter: &mut Interpreter,
229 memory: &mut SharedMemory,
230 host: &mut dyn HostExt,
231 ) -> InterpreterAction {
232 interpreter.memory = core::mem::replace(memory, SharedMemory::invalid());
233 let result = self.call_with_interpreter(interpreter, host);
234 *memory = core::mem::replace(&mut interpreter.memory, SharedMemory::invalid());
235 result
236 }
237
238 #[inline]
247 pub unsafe fn call_with_interpreter(
248 self,
249 interpreter: &mut Interpreter,
250 host: &mut dyn HostExt,
251 ) -> InterpreterAction {
252 interpreter.bytecode.action = None;
253
254 let (mut ecx, stack, stack_len) =
255 EvmContext::from_interpreter_with_stack(interpreter, host);
256 let result = self.call(Some(stack), Some(stack_len), &mut ecx);
257
258 if result == InstructionResult::OutOfGas {
261 ecx.gas.spend_all();
262 }
263
264 let return_data_is_empty = ecx.return_data.is_empty();
265
266 if return_data_is_empty {
267 interpreter.return_data.0.clear();
268 }
269
270 if let Some(action) = interpreter.bytecode.action.take() {
271 action
272 } else {
273 InterpreterAction::Return(InterpreterResult {
274 result,
275 output: Bytes::new(),
276 gas: interpreter.gas,
277 })
278 }
279 }
280
281 #[inline]
297 pub unsafe fn call(
298 self,
299 stack: Option<&mut EvmStack>,
300 stack_len: Option<&mut usize>,
301 ecx: &mut EvmContext<'_>,
302 ) -> InstructionResult {
303 (self.0)(ecx.gas, option_as_mut_ptr(stack), option_as_mut_ptr(stack_len), ecx.input, ecx)
304 }
305
306 #[inline(never)]
314 pub unsafe fn call_noinline(
315 self,
316 stack: Option<&mut EvmStack>,
317 stack_len: Option<&mut usize>,
318 ecx: &mut EvmContext<'_>,
319 ) -> InstructionResult {
320 self.call(stack, stack_len, ecx)
321 }
322}
323
324#[repr(C)]
326#[allow(missing_debug_implementations)]
327pub struct EvmStack([MaybeUninit<EvmWord>; 1024]);
328
329#[allow(clippy::new_without_default)]
330impl EvmStack {
331 pub const SIZE: usize = 32 * Self::CAPACITY;
333
334 pub const CAPACITY: usize = 1024;
336
337 #[inline]
341 pub fn new() -> Self {
342 Self(unsafe { MaybeUninit::uninit().assume_init() })
343 }
344
345 #[inline]
347 pub fn new_heap() -> Vec<EvmWord> {
348 Vec::with_capacity(1024)
349 }
350
351 #[inline]
353 pub fn from_interpreter_stack(stack: &mut revm_interpreter::Stack) -> (&mut Self, &mut usize) {
354 debug_assert!(stack.data().capacity() >= Self::CAPACITY);
355 unsafe {
356 let data = Self::from_mut_ptr(stack.data_mut().as_mut_ptr().cast());
357 let len = &mut *(stack.data_mut() as *mut Vec<_>).cast::<usize>().add(2);
359 debug_assert_eq!(stack.len(), *len);
360 (data, len)
361 }
362 }
363
364 #[inline]
370 pub fn from_vec(vec: &Vec<EvmWord>) -> &Self {
371 assert!(vec.capacity() >= Self::CAPACITY);
372 unsafe { Self::from_ptr(vec.as_ptr()) }
373 }
374
375 #[inline]
381 pub fn from_mut_vec(vec: &mut Vec<EvmWord>) -> &mut Self {
382 assert!(vec.capacity() >= Self::CAPACITY);
383 unsafe { Self::from_mut_ptr(vec.as_mut_ptr()) }
384 }
385
386 #[inline]
392 pub const unsafe fn from_ptr(ptr: *const EvmWord) -> &'static Self {
393 &*ptr.cast::<Self>()
394 }
395
396 #[inline]
402 pub unsafe fn from_mut_ptr(ptr: *mut EvmWord) -> &'static mut Self {
403 &mut *ptr.cast::<Self>()
404 }
405
406 #[inline]
408 pub const fn as_ptr(&self) -> *const EvmWord {
409 self.0.as_ptr().cast()
410 }
411
412 #[inline]
414 pub fn as_mut_ptr(&mut self) -> *mut EvmWord {
415 self.0.as_mut_ptr().cast()
416 }
417
418 #[inline]
420 pub fn as_slice(&self) -> &[EvmWord] {
421 unsafe { core::slice::from_raw_parts(self.as_ptr(), Self::CAPACITY) }
423 }
424
425 #[inline]
427 pub fn as_mut_slice(&mut self) -> &mut [EvmWord] {
428 unsafe { core::slice::from_raw_parts_mut(self.as_mut_ptr(), Self::CAPACITY) }
430 }
431
432 #[inline]
434 pub fn get(&self, index: usize) -> Option<&EvmWord> {
435 self.0.get(index).map(|slot| unsafe { slot.assume_init_ref() })
436 }
437
438 #[inline]
440 pub fn get_mut(&mut self, index: usize) -> Option<&mut EvmWord> {
441 self.0.get_mut(index).map(|slot| unsafe { slot.assume_init_mut() })
442 }
443
444 #[inline]
450 pub unsafe fn get_unchecked(&self, index: usize) -> &EvmWord {
451 self.0.get_unchecked(index).assume_init_ref()
452 }
453
454 #[inline]
460 pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut EvmWord {
461 self.0.get_unchecked_mut(index).assume_init_mut()
462 }
463
464 #[inline]
470 pub unsafe fn push(&mut self, value: EvmWord, len: &mut usize) {
471 self.set_unchecked(*len, value);
472 *len += 1;
473 }
474
475 #[inline]
481 pub unsafe fn top_unchecked(&self, len: usize) -> &EvmWord {
482 self.get_unchecked(len - 1)
483 }
484
485 #[inline]
491 pub unsafe fn top_unchecked_mut(&mut self, len: usize) -> &mut EvmWord {
492 self.get_unchecked_mut(len - 1)
493 }
494
495 #[inline]
501 pub unsafe fn from_top_unchecked(&self, len: usize, n: usize) -> &EvmWord {
502 self.get_unchecked(len - n - 1)
503 }
504
505 #[inline]
511 pub unsafe fn from_top_unchecked_mut(&mut self, len: usize, n: usize) -> &mut EvmWord {
512 self.get_unchecked_mut(len - n - 1)
513 }
514
515 #[inline]
521 pub unsafe fn set_unchecked(&mut self, index: usize, value: EvmWord) {
522 *self.0.get_unchecked_mut(index) = MaybeUninit::new(value);
523 }
524}
525
526#[repr(C, align(8))]
528#[derive(Clone, Copy, PartialEq, Eq)]
529#[allow(missing_debug_implementations)]
530pub struct EvmWord([u8; 32]);
531
532impl Default for EvmWord {
533 #[inline]
534 fn default() -> Self {
535 Self::ZERO
536 }
537}
538
539impl fmt::Debug for EvmWord {
540 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
541 write!(f, "0x")?;
542 for byte in &self.to_be_bytes() {
543 write!(f, "{byte:02x}")?;
544 }
545 Ok(())
546 }
547}
548
549impl TryFrom<EvmWord> for usize {
550 type Error = ruint::FromUintError<Self>;
551
552 #[inline]
553 fn try_from(w: EvmWord) -> Result<Self, Self::Error> {
554 Self::try_from(&w)
555 }
556}
557
558impl TryFrom<&EvmWord> for usize {
559 type Error = ruint::FromUintError<Self>;
560
561 #[inline]
562 fn try_from(w: &EvmWord) -> Result<Self, Self::Error> {
563 w.to_u256().try_into()
564 }
565}
566
567impl TryFrom<&mut EvmWord> for usize {
568 type Error = ruint::FromUintError<Self>;
569
570 #[inline]
571 fn try_from(w: &mut EvmWord) -> Result<Self, Self::Error> {
572 Self::try_from(&*w)
573 }
574}
575
576impl From<U256> for EvmWord {
577 #[inline]
578 fn from(u: U256) -> Self {
579 Self::from_u256(u)
580 }
581}
582
583impl EvmWord {
584 pub const ZERO: Self = Self([0; 32]);
586
587 #[inline]
589 pub fn from_be_bytes(bytes: [u8; 32]) -> Self {
590 Self::from_be(Self(bytes))
591 }
592
593 #[inline]
595 pub fn from_le_bytes(bytes: [u8; 32]) -> Self {
596 Self::from_le(Self(bytes))
597 }
598
599 #[inline]
601 pub const fn from_ne_bytes(bytes: [u8; 32]) -> Self {
602 Self(bytes)
603 }
604
605 #[inline]
607 pub const fn from_u256(u: U256) -> Self {
608 #[cfg(target_endian = "little")]
609 return unsafe { core::mem::transmute::<U256, Self>(u) };
610 #[cfg(target_endian = "big")]
611 return Self(u.to_be_bytes());
612 }
613
614 #[inline]
616 pub fn from_be(x: Self) -> Self {
617 #[cfg(target_endian = "little")]
618 return x.swap_bytes();
619 #[cfg(target_endian = "big")]
620 return x;
621 }
622
623 #[inline]
625 pub fn from_le(x: Self) -> Self {
626 #[cfg(target_endian = "little")]
627 return x;
628 #[cfg(target_endian = "big")]
629 return x.swap_bytes();
630 }
631
632 #[inline]
634 pub fn to_be_bytes(self) -> [u8; 32] {
635 self.to_be().to_ne_bytes()
636 }
637
638 #[inline]
641 pub fn to_le_bytes(self) -> [u8; 32] {
642 self.to_le().to_ne_bytes()
643 }
644
645 #[inline]
647 pub const fn to_ne_bytes(self) -> [u8; 32] {
648 self.0
649 }
650
651 #[inline]
653 pub fn to_be(self) -> Self {
654 #[cfg(target_endian = "little")]
655 return self.swap_bytes();
656 #[cfg(target_endian = "big")]
657 return self;
658 }
659
660 #[inline]
662 pub fn to_le(self) -> Self {
663 #[cfg(target_endian = "little")]
664 return self;
665 #[cfg(target_endian = "big")]
666 return self.swap_bytes();
667 }
668
669 #[inline]
671 pub fn swap_bytes(mut self) -> Self {
672 self.0.reverse();
673 self
674 }
675
676 #[cfg(target_endian = "little")]
678 #[inline]
679 pub const fn as_u256(&self) -> &U256 {
680 unsafe { &*(self as *const Self as *const U256) }
681 }
682
683 #[cfg(target_endian = "little")]
685 #[inline]
686 pub fn as_u256_mut(&mut self) -> &mut U256 {
687 unsafe { &mut *(self as *mut Self as *mut U256) }
688 }
689
690 #[inline]
692 pub const fn to_u256(&self) -> U256 {
693 #[cfg(target_endian = "little")]
694 return *self.as_u256();
695 #[cfg(target_endian = "big")]
696 return U256::from_be_bytes(self.0);
697 }
698
699 #[inline]
701 pub const fn into_u256(self) -> U256 {
702 #[cfg(target_endian = "little")]
703 return unsafe { core::mem::transmute::<Self, U256>(self) };
704 #[cfg(target_endian = "big")]
705 return U256::from_be_bytes(self.0);
706 }
707
708 #[inline]
710 pub fn to_address(self) -> Address {
711 Address::from_word(self.to_be_bytes().into())
712 }
713}
714
715struct ResumeAt;
719
720impl ResumeAt {
721 fn load(pc: usize, code: &[u8]) -> usize {
722 if pc < code.len() {
723 0
724 } else {
725 pc
726 }
727 }
728}
729
730#[inline(always)]
731fn option_as_mut_ptr<T>(opt: Option<&mut T>) -> *mut T {
732 match opt {
733 Some(ref_) => ref_,
734 None => ptr::null_mut(),
735 }
736}
737
738#[doc(hidden)]
741pub mod private {
742 pub use revm_interpreter;
743 pub use revm_primitives;
744}
745
746#[cfg(test)]
747mod tests {
748 use super::*;
749
750 #[test]
751 fn conversions() {
752 let mut word = EvmWord::ZERO;
753 assert_eq!(usize::try_from(word), Ok(0));
754 assert_eq!(usize::try_from(&word), Ok(0));
755 assert_eq!(usize::try_from(&mut word), Ok(0));
756 }
757
758 extern_revmc! {
759 #[link_name = "__test_fn"]
760 fn test_fn;
761 }
762
763 #[no_mangle]
764 extern "C" fn __test_fn(
765 _gas: *mut Gas,
766 _stack: *mut EvmStack,
767 _stack_len: *mut usize,
768 _input: *const InputsImpl,
769 _ecx: *mut EvmContext<'_>,
770 ) -> InstructionResult {
771 InstructionResult::Stop
772 }
773
774 #[test]
775 fn extern_macro() {
776 let _f1 = EvmCompilerFn::new(test_fn);
777 let _f2 = EvmCompilerFn::new(__test_fn);
778 assert_eq!(test_fn as *const () as usize, __test_fn as *const () as usize);
779 }
780}