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 Gas, Host, InputsImpl, InstructionResult, Interpreter, InterpreterAction, InterpreterResult,
12 SharedMemory,
13 interpreter_types::{Jumps, ReturnData},
14};
15use revm_primitives::{Address, Bytes, U256, ruint};
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 pub bytecode: *const [u8],
50}
51
52const _: () = {
55 use core::mem::offset_of;
56 assert!(core::mem::size_of::<EvmContext<'_>>() == 96);
57 assert!(offset_of!(EvmContext<'_>, memory) == 0);
59 assert!(offset_of!(EvmContext<'_>, resume_at) == 72);
60};
61
62impl fmt::Debug for EvmContext<'_> {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 f.debug_struct("EvmContext").field("memory", &self.memory).finish_non_exhaustive()
65 }
66}
67
68impl<'a> EvmContext<'a> {
69 #[inline]
71 pub fn from_interpreter(interpreter: &'a mut Interpreter, host: &'a mut dyn HostExt) -> Self {
72 Self::from_interpreter_with_stack(interpreter, host).0
73 }
74
75 #[inline]
77 pub fn from_interpreter_with_stack<'b: 'a>(
78 interpreter: &'a mut Interpreter,
79 host: &'b mut dyn HostExt,
80 ) -> (Self, &'a mut EvmStack, &'a mut usize) {
81 use revm_interpreter::interpreter_types::LegacyBytecode;
82
83 let (stack, stack_len) = EvmStack::from_interpreter_stack(&mut interpreter.stack);
84 let bytecode_slice = interpreter.bytecode.bytecode_slice();
85 let resume_at = ResumeAt::load(interpreter.bytecode.pc(), bytecode_slice);
86 let bytecode = bytecode_slice as *const [u8];
87 let this = Self {
88 memory: &mut interpreter.memory,
89 input: &mut interpreter.input,
90 gas: &mut interpreter.gas,
91 host,
92 next_action: &mut interpreter.bytecode.action,
93 return_data: interpreter.return_data.buffer(),
94 is_static: interpreter.runtime_flag.is_static,
95 resume_at,
96 bytecode,
97 };
98 (this, stack, stack_len)
99 }
100}
101
102#[cfg(not(feature = "host-ext-any"))]
104pub trait HostExt: Host {}
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(not(feature = "host-ext-any"))]
116impl<T: Host> HostExt for T {}
117
118#[cfg(feature = "host-ext-any")]
119impl<T: Host + Any> HostExt for T {
120 fn as_any(&self) -> &dyn Any {
121 self
122 }
123
124 fn as_any_mut(&mut self) -> &mut dyn Any {
125 self
126 }
127}
128
129#[cfg(feature = "host-ext-any")]
130#[doc(hidden)]
131impl dyn HostExt {
132 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
134 self.as_any().downcast_ref()
135 }
136
137 pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
139 self.as_any_mut().downcast_mut()
140 }
141}
142
143#[macro_export]
158macro_rules! extern_revmc {
159 ($( $(#[$attr:meta])* $vis:vis fn $name:ident; )+) => {
160 #[allow(improper_ctypes)]
161 unsafe extern "C" {
162 $(
163 $(#[$attr])*
164 $vis fn $name(
165 gas: *mut $crate::private::revm_interpreter::Gas,
166 stack: *mut $crate::EvmStack,
167 stack_len: *mut usize,
168 input: *const $crate::private::revm_interpreter::InputsImpl,
169 ecx: *mut $crate::EvmContext<'_>,
170 ) -> $crate::private::revm_interpreter::InstructionResult;
171 )+
172 }
173 };
174}
175
176pub type RawEvmCompilerFn = unsafe extern "C" fn(
182 gas: *mut Gas,
183 stack: *mut EvmStack,
184 stack_len: *mut usize,
185 input: *const InputsImpl,
186 ecx: *mut EvmContext<'_>,
187) -> InstructionResult;
188
189#[derive(Clone, Copy, Debug, Hash)]
191pub struct EvmCompilerFn(RawEvmCompilerFn);
192
193impl From<RawEvmCompilerFn> for EvmCompilerFn {
194 #[inline]
195 fn from(f: RawEvmCompilerFn) -> Self {
196 Self::new(f)
197 }
198}
199
200impl From<EvmCompilerFn> for RawEvmCompilerFn {
201 #[inline]
202 fn from(f: EvmCompilerFn) -> Self {
203 f.into_inner()
204 }
205}
206
207impl EvmCompilerFn {
208 #[inline]
210 pub const fn new(f: RawEvmCompilerFn) -> Self {
211 Self(f)
212 }
213
214 #[inline]
216 pub const fn into_inner(self) -> RawEvmCompilerFn {
217 self.0
218 }
219
220 #[inline]
229 pub unsafe fn call_with_interpreter_and_memory(
230 self,
231 interpreter: &mut Interpreter,
232 memory: &mut SharedMemory,
233 host: &mut dyn HostExt,
234 ) -> InterpreterAction {
235 interpreter.memory = core::mem::replace(memory, SharedMemory::invalid());
236 let result = self.call_with_interpreter(interpreter, host);
237 *memory = core::mem::replace(&mut interpreter.memory, SharedMemory::invalid());
238 result
239 }
240
241 #[inline]
250 pub unsafe fn call_with_interpreter(
251 self,
252 interpreter: &mut Interpreter,
253 host: &mut dyn HostExt,
254 ) -> InterpreterAction {
255 interpreter.bytecode.action = None;
256
257 let (mut ecx, stack, stack_len) =
258 EvmContext::from_interpreter_with_stack(interpreter, host);
259 let result = self.call(Some(stack), Some(stack_len), &mut ecx);
260
261 let resume_at = ecx.resume_at;
263
264 if result == InstructionResult::OutOfGas {
267 ecx.gas.spend_all();
268 }
269
270 let return_data_is_empty = ecx.return_data.is_empty();
271
272 if return_data_is_empty {
273 interpreter.return_data.0.clear();
274 }
275
276 interpreter.bytecode.absolute_jump(resume_at);
279
280 if let Some(action) = interpreter.bytecode.action.take() {
281 action
282 } else {
283 InterpreterAction::Return(InterpreterResult {
284 result,
285 output: Bytes::new(),
286 gas: interpreter.gas,
287 })
288 }
289 }
290
291 #[inline]
307 pub unsafe fn call(
308 self,
309 stack: Option<&mut EvmStack>,
310 stack_len: Option<&mut usize>,
311 ecx: &mut EvmContext<'_>,
312 ) -> InstructionResult {
313 (self.0)(ecx.gas, option_as_mut_ptr(stack), option_as_mut_ptr(stack_len), ecx.input, ecx)
314 }
315
316 #[inline(never)]
324 pub unsafe fn call_noinline(
325 self,
326 stack: Option<&mut EvmStack>,
327 stack_len: Option<&mut usize>,
328 ecx: &mut EvmContext<'_>,
329 ) -> InstructionResult {
330 self.call(stack, stack_len, ecx)
331 }
332}
333
334#[repr(C)]
336#[allow(missing_debug_implementations)]
337pub struct EvmStack([MaybeUninit<EvmWord>; 1024]);
338
339#[allow(clippy::new_without_default)]
340impl EvmStack {
341 pub const SIZE: usize = 32 * Self::CAPACITY;
343
344 pub const CAPACITY: usize = 1024;
346
347 #[inline]
351 pub fn new() -> Self {
352 Self(unsafe { MaybeUninit::uninit().assume_init() })
353 }
354
355 #[inline]
357 pub fn new_heap() -> Vec<EvmWord> {
358 Vec::with_capacity(1024)
359 }
360
361 #[inline]
363 pub fn from_interpreter_stack(stack: &mut revm_interpreter::Stack) -> (&mut Self, &mut usize) {
364 debug_assert!(stack.data().capacity() >= Self::CAPACITY);
365 unsafe {
366 let data = Self::from_mut_ptr(stack.data_mut().as_mut_ptr().cast());
367 let len = &mut *(stack.data_mut() as *mut Vec<_>).cast::<usize>().add(2);
369 debug_assert_eq!(stack.len(), *len);
370 (data, len)
371 }
372 }
373
374 #[inline]
380 pub fn from_vec(vec: &Vec<EvmWord>) -> &Self {
381 assert!(vec.capacity() >= Self::CAPACITY);
382 unsafe { Self::from_ptr(vec.as_ptr()) }
383 }
384
385 #[inline]
391 pub fn from_mut_vec(vec: &mut Vec<EvmWord>) -> &mut Self {
392 assert!(vec.capacity() >= Self::CAPACITY);
393 unsafe { Self::from_mut_ptr(vec.as_mut_ptr()) }
394 }
395
396 #[inline]
402 pub const unsafe fn from_ptr(ptr: *const EvmWord) -> &'static Self {
403 &*ptr.cast::<Self>()
404 }
405
406 #[inline]
412 pub unsafe fn from_mut_ptr(ptr: *mut EvmWord) -> &'static mut Self {
413 &mut *ptr.cast::<Self>()
414 }
415
416 #[inline]
418 pub const fn as_ptr(&self) -> *const EvmWord {
419 self.0.as_ptr().cast()
420 }
421
422 #[inline]
424 pub fn as_mut_ptr(&mut self) -> *mut EvmWord {
425 self.0.as_mut_ptr().cast()
426 }
427
428 #[inline]
430 pub fn as_slice(&self) -> &[EvmWord] {
431 unsafe { core::slice::from_raw_parts(self.as_ptr(), Self::CAPACITY) }
433 }
434
435 #[inline]
437 pub fn as_mut_slice(&mut self) -> &mut [EvmWord] {
438 unsafe { core::slice::from_raw_parts_mut(self.as_mut_ptr(), Self::CAPACITY) }
440 }
441
442 #[inline]
444 pub fn get(&self, index: usize) -> Option<&EvmWord> {
445 self.0.get(index).map(|slot| unsafe { slot.assume_init_ref() })
446 }
447
448 #[inline]
450 pub fn get_mut(&mut self, index: usize) -> Option<&mut EvmWord> {
451 self.0.get_mut(index).map(|slot| unsafe { slot.assume_init_mut() })
452 }
453
454 #[inline]
460 pub unsafe fn get_unchecked(&self, index: usize) -> &EvmWord {
461 self.0.get_unchecked(index).assume_init_ref()
462 }
463
464 #[inline]
470 pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> &mut EvmWord {
471 self.0.get_unchecked_mut(index).assume_init_mut()
472 }
473
474 #[inline]
480 pub unsafe fn push(&mut self, value: EvmWord, len: &mut usize) {
481 self.set_unchecked(*len, value);
482 *len += 1;
483 }
484
485 #[inline]
491 pub unsafe fn top_unchecked(&self, len: usize) -> &EvmWord {
492 self.get_unchecked(len - 1)
493 }
494
495 #[inline]
501 pub unsafe fn top_unchecked_mut(&mut self, len: usize) -> &mut EvmWord {
502 self.get_unchecked_mut(len - 1)
503 }
504
505 #[inline]
511 pub unsafe fn from_top_unchecked(&self, len: usize, n: usize) -> &EvmWord {
512 self.get_unchecked(len - n - 1)
513 }
514
515 #[inline]
521 pub unsafe fn from_top_unchecked_mut(&mut self, len: usize, n: usize) -> &mut EvmWord {
522 self.get_unchecked_mut(len - n - 1)
523 }
524
525 #[inline]
531 pub unsafe fn set_unchecked(&mut self, index: usize, value: EvmWord) {
532 *self.0.get_unchecked_mut(index) = MaybeUninit::new(value);
533 }
534}
535
536#[repr(C, align(8))]
538#[derive(Clone, Copy, PartialEq, Eq)]
539#[allow(missing_debug_implementations)]
540pub struct EvmWord([u8; 32]);
541
542impl Default for EvmWord {
543 #[inline]
544 fn default() -> Self {
545 Self::ZERO
546 }
547}
548
549impl fmt::Debug for EvmWord {
550 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
551 write!(f, "0x")?;
552 for byte in &self.to_be_bytes() {
553 write!(f, "{byte:02x}")?;
554 }
555 Ok(())
556 }
557}
558
559impl TryFrom<EvmWord> for usize {
560 type Error = ruint::FromUintError<Self>;
561
562 #[inline]
563 fn try_from(w: EvmWord) -> Result<Self, Self::Error> {
564 Self::try_from(&w)
565 }
566}
567
568impl TryFrom<&EvmWord> for usize {
569 type Error = ruint::FromUintError<Self>;
570
571 #[inline]
572 fn try_from(w: &EvmWord) -> Result<Self, Self::Error> {
573 w.to_u256().try_into()
574 }
575}
576
577impl TryFrom<&mut EvmWord> for usize {
578 type Error = ruint::FromUintError<Self>;
579
580 #[inline]
581 fn try_from(w: &mut EvmWord) -> Result<Self, Self::Error> {
582 Self::try_from(&*w)
583 }
584}
585
586impl From<U256> for EvmWord {
587 #[inline]
588 fn from(u: U256) -> Self {
589 Self::from_u256(u)
590 }
591}
592
593impl EvmWord {
594 pub const ZERO: Self = Self([0; 32]);
596
597 #[inline]
599 pub fn from_be_bytes(bytes: [u8; 32]) -> Self {
600 Self::from_be(Self(bytes))
601 }
602
603 #[inline]
605 pub fn from_le_bytes(bytes: [u8; 32]) -> Self {
606 Self::from_le(Self(bytes))
607 }
608
609 #[inline]
611 pub const fn from_ne_bytes(bytes: [u8; 32]) -> Self {
612 Self(bytes)
613 }
614
615 #[inline]
617 pub const fn from_u256(u: U256) -> Self {
618 #[cfg(target_endian = "little")]
619 return unsafe { core::mem::transmute::<U256, Self>(u) };
620 #[cfg(target_endian = "big")]
621 return Self(u.to_be_bytes());
622 }
623
624 #[inline]
626 pub fn from_be(x: Self) -> Self {
627 #[cfg(target_endian = "little")]
628 return x.swap_bytes();
629 #[cfg(target_endian = "big")]
630 return x;
631 }
632
633 #[inline]
635 pub fn from_le(x: Self) -> Self {
636 #[cfg(target_endian = "little")]
637 return x;
638 #[cfg(target_endian = "big")]
639 return x.swap_bytes();
640 }
641
642 #[inline]
644 pub fn to_be_bytes(self) -> [u8; 32] {
645 self.to_be().to_ne_bytes()
646 }
647
648 #[inline]
651 pub fn to_le_bytes(self) -> [u8; 32] {
652 self.to_le().to_ne_bytes()
653 }
654
655 #[inline]
657 pub const fn to_ne_bytes(self) -> [u8; 32] {
658 self.0
659 }
660
661 #[inline]
663 pub fn to_be(self) -> Self {
664 #[cfg(target_endian = "little")]
665 return self.swap_bytes();
666 #[cfg(target_endian = "big")]
667 return self;
668 }
669
670 #[inline]
672 pub fn to_le(self) -> Self {
673 #[cfg(target_endian = "little")]
674 return self;
675 #[cfg(target_endian = "big")]
676 return self.swap_bytes();
677 }
678
679 #[inline]
681 pub fn swap_bytes(mut self) -> Self {
682 self.0.reverse();
683 self
684 }
685
686 #[cfg(target_endian = "little")]
688 #[inline]
689 pub const fn as_u256(&self) -> &U256 {
690 unsafe { &*(self as *const Self as *const U256) }
691 }
692
693 #[cfg(target_endian = "little")]
695 #[inline]
696 pub fn as_u256_mut(&mut self) -> &mut U256 {
697 unsafe { &mut *(self as *mut Self as *mut U256) }
698 }
699
700 #[inline]
702 pub const fn to_u256(&self) -> U256 {
703 #[cfg(target_endian = "little")]
704 return *self.as_u256();
705 #[cfg(target_endian = "big")]
706 return U256::from_be_bytes(self.0);
707 }
708
709 #[inline]
711 pub const fn into_u256(self) -> U256 {
712 #[cfg(target_endian = "little")]
713 return unsafe { core::mem::transmute::<Self, U256>(self) };
714 #[cfg(target_endian = "big")]
715 return U256::from_be_bytes(self.0);
716 }
717
718 #[inline]
720 pub fn to_address(self) -> Address {
721 Address::from_word(self.to_be_bytes().into())
722 }
723}
724
725struct ResumeAt;
729
730impl ResumeAt {
731 fn load(pc: usize, code: &[u8]) -> usize {
732 if pc < code.len() { 0 } else { pc }
733 }
734}
735
736#[inline(always)]
737fn option_as_mut_ptr<T>(opt: Option<&mut T>) -> *mut T {
738 match opt {
739 Some(ref_) => ref_,
740 None => ptr::null_mut(),
741 }
742}
743
744#[doc(hidden)]
747pub mod private {
748 pub use revm_interpreter;
749 pub use revm_primitives;
750}
751
752#[cfg(test)]
753mod tests {
754 use super::*;
755
756 #[test]
757 fn conversions() {
758 let mut word = EvmWord::ZERO;
759 assert_eq!(usize::try_from(word), Ok(0));
760 assert_eq!(usize::try_from(&word), Ok(0));
761 assert_eq!(usize::try_from(&mut word), Ok(0));
762 }
763
764 extern_revmc! {
765 #[link_name = "__test_fn"]
766 fn test_fn;
767 }
768
769 #[unsafe(no_mangle)]
770 extern "C" fn __test_fn(
771 _gas: *mut Gas,
772 _stack: *mut EvmStack,
773 _stack_len: *mut usize,
774 _input: *const InputsImpl,
775 _ecx: *mut EvmContext<'_>,
776 ) -> InstructionResult {
777 InstructionResult::Stop
778 }
779
780 #[test]
781 fn extern_macro() {
782 let _f1 = EvmCompilerFn::new(test_fn);
783 let _f2 = EvmCompilerFn::new(__test_fn);
784 assert_eq!(test_fn as *const () as usize, __test_fn as *const () as usize);
785 }
786}