diff --git a/interpreter/src/error.rs b/interpreter/src/error/exit.rs similarity index 89% rename from interpreter/src/error.rs rename to interpreter/src/error/exit.rs index 92ead5d0b..dcf797168 100644 --- a/interpreter/src/error.rs +++ b/interpreter/src/error/exit.rs @@ -1,32 +1,7 @@ -use crate::Opcode; use alloc::borrow::Cow; use core::fmt; -/// Capture represents the result of execution. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum Capture { - /// The machine has exited. It cannot be executed again. - Exit(E), - /// The machine has trapped. It is waiting for external information, and can - /// be executed again. - Trap(T), -} - -impl Capture { - pub fn exit(self) -> Option { - match self { - Self::Exit(e) => Some(e), - Self::Trap(_) => None, - } - } - - pub fn trap(self) -> Option { - match self { - Self::Exit(_) => None, - Self::Trap(t) => Some(t), - } - } -} +use crate::opcode::Opcode; /// Exit result. pub type ExitResult = Result; diff --git a/interpreter/src/error/mod.rs b/interpreter/src/error/mod.rs new file mode 100644 index 000000000..2473c07a0 --- /dev/null +++ b/interpreter/src/error/mod.rs @@ -0,0 +1,30 @@ +mod exit; +mod trap; + +pub use self::{exit::*, trap::*}; + +/// Capture represents the result of execution. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Capture { + /// The machine has exited. It cannot be executed again. + Exit(E), + /// The machine has trapped. It is waiting for external information, and can + /// be executed again. + Trap(T), +} + +impl Capture { + pub fn exit(self) -> Option { + match self { + Self::Exit(e) => Some(e), + Self::Trap(_) => None, + } + } + + pub fn trap(self) -> Option { + match self { + Self::Exit(_) => None, + Self::Trap(t) => Some(t), + } + } +} diff --git a/interpreter/src/trap.rs b/interpreter/src/error/trap.rs similarity index 96% rename from interpreter/src/trap.rs rename to interpreter/src/error/trap.rs index 8f2e43a65..66764b3fb 100644 --- a/interpreter/src/trap.rs +++ b/interpreter/src/error/trap.rs @@ -1,16 +1,22 @@ //! Call and create trap handler. -use crate::utils::{h256_to_u256, u256_to_usize}; -use crate::{ - interpreter::Interpreter, Context, ExitError, ExitException, ExitResult, Machine, Memory, - RuntimeBackend, RuntimeState, Transfer, -}; use alloc::vec::Vec; -use core::cmp::{max, min}; -use core::convert::Infallible; +use core::{ + cmp::{max, min}, + convert::Infallible, +}; + use primitive_types::{H160, H256, U256}; use sha3::{Digest, Keccak256}; +use crate::{ + error::{ExitError, ExitException, ExitResult}, + interpreter::Interpreter, + machine::{Machine, Memory}, + runtime::{Context, RuntimeBackend, RuntimeState, Transfer}, + utils::{h256_to_u256, u256_to_usize}, +}; + pub trait TrapConstruct { fn construct(v: T) -> Self; } @@ -21,72 +27,6 @@ pub trait TrapConsume { fn consume(self) -> Result; } -/// Create scheme. -#[derive(Clone, Copy, Eq, PartialEq, Debug)] -pub enum CreateScheme { - /// Legacy create scheme of `CREATE`. - Legacy { - /// Caller of the create. - caller: H160, - }, - /// Create scheme of `CREATE2`. - Create2 { - /// Caller of the create. - caller: H160, - /// Code hash. - code_hash: H256, - /// Salt. - salt: H256, - }, -} - -impl CreateScheme { - pub fn address(&self, handler: &H) -> H160 { - match self { - Self::Create2 { - caller, - code_hash, - salt, - } => { - let mut hasher = Keccak256::new(); - hasher.update([0xff]); - hasher.update(&caller[..]); - hasher.update(&salt[..]); - hasher.update(&code_hash[..]); - H256::from_slice(hasher.finalize().as_slice()).into() - } - Self::Legacy { caller } => { - let nonce = handler.nonce(*caller); - let mut stream = rlp::RlpStream::new_list(2); - stream.append(caller); - stream.append(&nonce); - H256::from_slice(Keccak256::digest(&stream.out()).as_slice()).into() - } - } - } - - #[must_use] - pub const fn caller(&self) -> H160 { - match self { - Self::Create2 { caller, .. } => *caller, - Self::Legacy { caller } => *caller, - } - } -} - -/// Call scheme. -#[derive(Clone, Copy, Eq, PartialEq, Debug)] -pub enum CallScheme { - /// `CALL` - Call, - /// `CALLCODE` - CallCode, - /// `DELEGATECALL` - DelegateCall, - /// `STATICCALL` - StaticCall, -} - pub enum CallCreateTrap { Create, Create2, @@ -161,6 +101,20 @@ impl CallCreateTrapData { } } +/// Call scheme. +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub enum CallScheme { + /// `CALL` + Call, + /// `CALLCODE` + CallCode, + /// `DELEGATECALL` + DelegateCall, + /// `STATICCALL` + StaticCall, +} + +#[derive(Clone, Debug)] pub struct CallTrapData { pub target: H160, pub transfer: Option, @@ -376,6 +330,59 @@ impl CallTrapData { } } +/// Create scheme. +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub enum CreateScheme { + /// Legacy create scheme of `CREATE`. + Legacy { + /// Caller of the create call. + caller: H160, + }, + /// Create scheme of `CREATE2`. + Create2 { + /// Caller of the create call. + caller: H160, + /// Code hash. + code_hash: H256, + /// Salt. + salt: H256, + }, +} + +impl CreateScheme { + pub fn address(&self, handler: &H) -> H160 { + match self { + Self::Create2 { + caller, + code_hash, + salt, + } => { + let mut hasher = Keccak256::new(); + hasher.update([0xff]); + hasher.update(&caller[..]); + hasher.update(&salt[..]); + hasher.update(&code_hash[..]); + H256::from_slice(hasher.finalize().as_slice()).into() + } + Self::Legacy { caller } => { + let nonce = handler.nonce(*caller); + let mut stream = rlp::RlpStream::new_list(2); + stream.append(caller); + stream.append(&nonce); + H256::from_slice(Keccak256::digest(&stream.out()).as_slice()).into() + } + } + } + + #[must_use] + pub const fn caller(&self) -> H160 { + match self { + Self::Create2 { caller, .. } => *caller, + Self::Legacy { caller } => *caller, + } + } +} + #[derive(Clone, Debug)] pub struct CreateTrapData { pub scheme: CreateScheme, diff --git a/interpreter/src/etable.rs b/interpreter/src/etable.rs index 515897176..a11c2bdea 100644 --- a/interpreter/src/etable.rs +++ b/interpreter/src/etable.rs @@ -1,9 +1,15 @@ +use core::{ + marker::PhantomData, + ops::{Deref, DerefMut}, +}; + use crate::{ - eval::*, trap::CallCreateTrap, ExitResult, GasState, Machine, Opcode, RuntimeBackend, - RuntimeEnvironment, RuntimeState, TrapConstruct, + error::{CallCreateTrap, ExitResult, TrapConstruct}, + eval::*, + machine::Machine, + opcode::Opcode, + runtime::{GasState, RuntimeBackend, RuntimeEnvironment, RuntimeState}, }; -use core::marker::PhantomData; -use core::ops::{Deref, DerefMut}; pub trait EtableSet { type State; diff --git a/interpreter/src/eval/arithmetic.rs b/interpreter/src/eval/arithmetic.rs index ae6e9a15c..07045d003 100644 --- a/interpreter/src/eval/arithmetic.rs +++ b/interpreter/src/eval/arithmetic.rs @@ -1,8 +1,9 @@ -use crate::utils::I256; -use core::convert::TryInto; use core::ops::Rem; + use primitive_types::{U256, U512}; +use crate::utils::I256; + #[inline] pub fn div(op1: U256, op2: U256) -> U256 { if op2 == U256::zero() { diff --git a/interpreter/src/eval/bitwise.rs b/interpreter/src/eval/bitwise.rs index 49883fd1c..23bb5dd3d 100644 --- a/interpreter/src/eval/bitwise.rs +++ b/interpreter/src/eval/bitwise.rs @@ -1,6 +1,7 @@ -use crate::utils::{Sign, I256}; use primitive_types::U256; +use crate::utils::{Sign, I256}; + #[inline] pub fn slt(op1: U256, op2: U256) -> U256 { let op1: I256 = op1.into(); diff --git a/interpreter/src/eval/misc.rs b/interpreter/src/eval/misc.rs index 0a9b9c5a3..657751fa0 100644 --- a/interpreter/src/eval/misc.rs +++ b/interpreter/src/eval/misc.rs @@ -1,9 +1,14 @@ -use super::Control; -use crate::utils::u256_to_h256; -use crate::{ExitError, ExitException, ExitFatal, ExitSucceed, Machine}; use core::cmp::min; + use primitive_types::{H256, U256}; +use crate::{ + error::{ExitError, ExitException, ExitFatal, ExitSucceed}, + etable::Control, + machine::Machine, + utils::u256_to_h256, +}; + #[inline] pub fn codesize(state: &mut Machine) -> Control { let stack = &mut state.stack; diff --git a/interpreter/src/eval/mod.rs b/interpreter/src/eval/mod.rs index ba578aec8..238f572e6 100644 --- a/interpreter/src/eval/mod.rs +++ b/interpreter/src/eval/mod.rs @@ -5,13 +5,18 @@ mod bitwise; mod misc; mod system; -use crate::{ - trap::CallCreateTrap, Control, ExitException, ExitSucceed, GasState, Machine, Opcode, - RuntimeBackend, RuntimeEnvironment, RuntimeState, TrapConstruct, -}; use core::ops::{BitAnd, BitOr, BitXor}; + use primitive_types::{H256, U256}; +use crate::{ + error::{CallCreateTrap, ExitException, ExitSucceed, TrapConstruct}, + etable::Control, + machine::Machine, + opcode::Opcode, + runtime::{GasState, RuntimeBackend, RuntimeEnvironment, RuntimeState}, +}; + pub fn eval_pass( _machine: &mut Machine, _handle: &mut H, diff --git a/interpreter/src/eval/system.rs b/interpreter/src/eval/system.rs index 88256632a..4a30b9075 100644 --- a/interpreter/src/eval/system.rs +++ b/interpreter/src/eval/system.rs @@ -1,12 +1,15 @@ -use super::Control; -use crate::{ - ExitException, ExitFatal, ExitSucceed, GasState, Log, Machine, RuntimeBackend, - RuntimeEnvironment, RuntimeState, Transfer, -}; use alloc::vec::Vec; + use primitive_types::{H256, U256}; use sha3::{Digest, Keccak256}; +use crate::{ + error::{ExitException, ExitFatal, ExitSucceed}, + etable::Control, + machine::Machine, + runtime::{GasState, Log, RuntimeBackend, RuntimeEnvironment, RuntimeState, Transfer}, +}; + pub fn sha3, Tr>(machine: &mut Machine) -> Control { pop_u256!(machine, from, len); diff --git a/interpreter/src/interpreter/etable.rs b/interpreter/src/interpreter/etable.rs index ea0df5833..83ecf1577 100644 --- a/interpreter/src/interpreter/etable.rs +++ b/interpreter/src/interpreter/etable.rs @@ -1,11 +1,14 @@ -use crate::interpreter::{Interpreter, RunInterpreter, StepInterpreter}; -use crate::{ - Capture, Control, EtableSet, ExitError, ExitException, ExitFatal, ExitResult, ExitSucceed, - Machine, Opcode, Stack, Valids, -}; use alloc::vec::Vec; use core::ops::{Deref, DerefMut}; +use crate::{ + error::{Capture, ExitError, ExitException, ExitFatal, ExitResult, ExitSucceed}, + etable::{Control, EtableSet}, + interpreter::{valids::Valids, Interpreter, RunInterpreter, StepInterpreter}, + machine::{Machine, Stack}, + opcode::Opcode, +}; + pub struct EtableInterpreter<'etable, ES: EtableSet> { valids: Valids, position: usize, diff --git a/interpreter/src/interpreter/mod.rs b/interpreter/src/interpreter/mod.rs index 37f66a83a..4d0788869 100644 --- a/interpreter/src/interpreter/mod.rs +++ b/interpreter/src/interpreter/mod.rs @@ -1,10 +1,14 @@ mod etable; +mod valids; -pub use self::etable::EtableInterpreter; - -use crate::{Capture, ExitResult, Machine}; use alloc::vec::Vec; +pub use self::etable::EtableInterpreter; +use crate::{ + error::{Capture, ExitResult}, + machine::Machine, +}; + pub trait Interpreter { type State; diff --git a/interpreter/src/valids.rs b/interpreter/src/interpreter/valids.rs similarity index 66% rename from interpreter/src/valids.rs rename to interpreter/src/interpreter/valids.rs index e9bc3613a..f9bba082d 100644 --- a/interpreter/src/valids.rs +++ b/interpreter/src/interpreter/valids.rs @@ -1,6 +1,7 @@ -use crate::Opcode; use alloc::vec::Vec; +use crate::opcode::Opcode; + /// Mapping of valid jump destination from code. #[derive(Clone, Debug, Eq, PartialEq)] pub struct Valids(Vec); @@ -25,36 +26,17 @@ impl Valids { } } - Valids(valids) - } - - /// Get the length of the valid mapping. This is the same as the - /// code bytes. - #[inline] - #[must_use] - pub fn len(&self) -> usize { - self.0.len() - } - - /// Returns true if the valids list is empty - #[inline] - #[must_use] - pub fn is_empty(&self) -> bool { - self.len() == 0 + Self(valids) } - /// Returns `true` if the position is a valid jump destination. If - /// not, returns `false`. + /// Returns `true` if the position is a valid jump destination. + /// If not, returns `false`. #[must_use] pub fn is_valid(&self, position: usize) -> bool { if position >= self.0.len() { return false; } - if !self.0[position] { - return false; - } - - true + self.0[position] } } diff --git a/interpreter/src/lib.rs b/interpreter/src/lib.rs index 0e6693bef..f29887abb 100644 --- a/interpreter/src/lib.rs +++ b/interpreter/src/lib.rs @@ -6,78 +6,13 @@ extern crate alloc; -mod error; -mod etable; +pub mod error; +pub mod etable; pub mod eval; -pub mod interpreter; -mod memory; -mod opcode; -mod runtime; -mod stack; -pub mod trap; +mod interpreter; +pub mod machine; +pub mod opcode; +pub mod runtime; pub mod utils; -mod valids; -pub use crate::error::{Capture, ExitError, ExitException, ExitFatal, ExitResult, ExitSucceed}; -pub use crate::etable::{Control, Efn, Etable, EtableSet}; -pub use crate::memory::Memory; -pub use crate::opcode::Opcode; -pub use crate::runtime::{ - Context, GasState, Log, RuntimeBackend, RuntimeBaseBackend, RuntimeEnvironment, RuntimeState, - TransactionContext, Transfer, -}; -pub use crate::stack::Stack; -pub use crate::trap::{TrapConstruct, TrapConsume}; -pub use crate::valids::Valids; - -use alloc::rc::Rc; -use alloc::vec::Vec; - -/// Core execution layer for EVM. -pub struct Machine { - /// Program data. - data: Rc>, - /// Program code. - code: Rc>, - /// Return value. Note the difference between `retbuf`. - /// A `retval` holds what's returned by the current machine, with `RETURN` or `REVERT` opcode. - /// A `retbuf` holds the buffer of returned value by sub-calls. - pub retval: Vec, - /// Memory. - pub memory: Memory, - /// Stack. - pub stack: Stack, - /// Extra state, - pub state: S, -} - -impl Machine { - /// Machine code. - pub fn code(&self) -> &[u8] { - &self.code - } - - /// Create a new machine with given code and data. - pub fn new( - code: Rc>, - data: Rc>, - stack_limit: usize, - memory_limit: usize, - state: S, - ) -> Self { - Self { - data, - code, - retval: Vec::new(), - memory: Memory::new(memory_limit), - stack: Stack::new(stack_limit), - state, - } - } - - /// Whether the machine has empty code. - #[must_use] - pub fn is_empty(&self) -> bool { - self.code.is_empty() - } -} +pub use self::interpreter::{EtableInterpreter, Interpreter, RunInterpreter, StepInterpreter}; diff --git a/interpreter/src/memory.rs b/interpreter/src/machine/memory.rs similarity index 97% rename from interpreter/src/memory.rs rename to interpreter/src/machine/memory.rs index 0c6c92c5a..98abcc707 100644 --- a/interpreter/src/memory.rs +++ b/interpreter/src/machine/memory.rs @@ -1,10 +1,14 @@ -use crate::{ExitException, ExitFatal}; -use alloc::vec; -use alloc::vec::Vec; -use core::ops::{BitAnd, Not, Range}; -use core::{cmp::min, mem}; +use alloc::{vec, vec::Vec}; +use core::{ + cmp::min, + mem, + ops::{BitAnd, Not, Range}, +}; + use primitive_types::U256; +use crate::error::{ExitException, ExitFatal}; + /// A sequencial memory. It uses Rust's `Vec` for internal /// representation. #[derive(Clone, Debug)] diff --git a/interpreter/src/machine/mod.rs b/interpreter/src/machine/mod.rs new file mode 100644 index 000000000..94f224f67 --- /dev/null +++ b/interpreter/src/machine/mod.rs @@ -0,0 +1,55 @@ +mod memory; +mod stack; + +use alloc::{rc::Rc, vec::Vec}; + +pub use self::{memory::Memory, stack::Stack}; + +/// Core execution layer for EVM. +pub struct Machine { + /// Program data. + pub(crate) data: Rc>, + /// Program code. + pub(crate) code: Rc>, + /// Return value. Note the difference between `retbuf`. + /// A `retval` holds what's returned by the current machine, with `RETURN` or `REVERT` opcode. + /// A `retbuf` holds the buffer of returned value by sub-calls. + pub retval: Vec, + /// Memory. + pub memory: Memory, + /// Stack. + pub stack: Stack, + /// Extra state, + pub state: S, +} + +impl Machine { + /// Create a new machine with given code and data. + pub fn new( + code: Rc>, + data: Rc>, + stack_limit: usize, + memory_limit: usize, + state: S, + ) -> Self { + Self { + data, + code, + retval: Vec::new(), + memory: Memory::new(memory_limit), + stack: Stack::new(stack_limit), + state, + } + } + + /// Machine code. + pub fn code(&self) -> &[u8] { + &self.code + } + + /// Whether the machine has empty code. + #[must_use] + pub fn is_empty(&self) -> bool { + self.code.is_empty() + } +} diff --git a/interpreter/src/stack.rs b/interpreter/src/machine/stack.rs similarity index 93% rename from interpreter/src/stack.rs rename to interpreter/src/machine/stack.rs index 68b8c3fe7..8798d5897 100644 --- a/interpreter/src/stack.rs +++ b/interpreter/src/machine/stack.rs @@ -1,7 +1,9 @@ -use crate::{ExitError, ExitException}; use alloc::vec::Vec; + use primitive_types::H256; +use crate::error::{ExitError, ExitException}; + /// EVM stack. #[derive(Clone, Debug)] pub struct Stack { @@ -56,15 +58,15 @@ impl Stack { } } - #[inline] /// Stack limit. + #[inline] #[must_use] pub const fn limit(&self) -> usize { self.limit } - #[inline] /// Stack length. + #[inline] #[must_use] pub fn len(&self) -> usize { self.data.len() @@ -77,8 +79,8 @@ impl Stack { self.data.is_empty() } - #[inline] /// Stack data. + #[inline] #[must_use] pub const fn data(&self) -> &Vec { &self.data @@ -89,16 +91,17 @@ impl Stack { self.data.clear(); } + /// Pop a value from the stack. + /// If the stack is already empty, returns the `StackUnderflow` error. #[inline] - /// Pop a value from the stack. If the stack is already empty, returns the - /// `StackUnderflow` error. pub fn pop(&mut self) -> Result { self.data.pop().ok_or(ExitException::StackUnderflow) } + /// Push a new value into the stack. + /// If it exceeds the stack limit, returns `StackOverflow` error and + /// leaves the stack unchanged. #[inline] - /// Push a new value into the stack. If it will exceed the stack limit, - /// returns `StackOverflow` error and leaves the stack unchanged. pub fn push(&mut self, value: H256) -> Result<(), ExitException> { if self.data.len() + 1 > self.limit { return Err(ExitException::StackOverflow); @@ -135,10 +138,10 @@ impl Stack { } } - #[inline] /// Peek a value at given index for the stack, where the top of /// the stack is at index `0`. If the index is too large, /// `StackError::Underflow` is returned. + #[inline] pub fn peek(&self, no_from_top: usize) -> Result { if self.data.len() > no_from_top { Ok(self.data[self.data.len() - no_from_top - 1]) @@ -147,10 +150,10 @@ impl Stack { } } - #[inline] /// Set a value at given index for the stack, where the top of the /// stack is at index `0`. If the index is too large, /// `StackError::Underflow` is returned. + #[inline] pub fn set(&mut self, no_from_top: usize, val: H256) -> Result<(), ExitException> { if self.data.len() > no_from_top { let len = self.data.len(); diff --git a/interpreter/src/runtime.rs b/interpreter/src/runtime.rs index 7dbce8a49..ed9056cbf 100644 --- a/interpreter/src/runtime.rs +++ b/interpreter/src/runtime.rs @@ -1,9 +1,10 @@ -use crate::ExitError; -use alloc::rc::Rc; -use alloc::vec::Vec; +use alloc::{rc::Rc, vec::Vec}; + use primitive_types::{H160, H256, U256}; use sha3::{Digest, Keccak256}; +use crate::error::ExitError; + /// Gas state. pub trait GasState { fn gas(&self) -> U256; @@ -14,6 +15,7 @@ pub trait GasState { pub struct RuntimeState { /// Runtime context. pub context: Context, + /// Transaction context. pub transaction_context: Rc, /// Return data buffer. pub retbuf: Vec, diff --git a/interpreter/src/utils.rs b/interpreter/src/utils.rs index a32cc07eb..9809a2774 100644 --- a/interpreter/src/utils.rs +++ b/interpreter/src/utils.rs @@ -1,10 +1,14 @@ //! Small utilities. -use crate::{ExitError, ExitFatal}; -use core::cmp::Ordering; -use core::ops::{Div, Rem}; +use core::{ + cmp::Ordering, + ops::{Div, Rem}, +}; + use primitive_types::{H256, U256}; +use crate::error::{ExitError, ExitFatal}; + /// Convert [U256] into [H256]. #[must_use] pub fn u256_to_h256(v: U256) -> H256 { @@ -160,10 +164,10 @@ impl Rem for I256 { #[cfg(test)] mod tests { - use crate::utils::{Sign, I256}; - use primitive_types::U256; use std::num::Wrapping; + use super::*; + #[test] fn div_i256() { // Sanity checks based on i8. Notice that we need to use `Wrapping` here because diff --git a/interpreter/tests/performance.rs b/interpreter/tests/performance.rs index 1e9d255f2..65d0ce64b 100644 --- a/interpreter/tests/performance.rs +++ b/interpreter/tests/performance.rs @@ -1,7 +1,12 @@ -use evm_interpreter::interpreter::{EtableInterpreter, RunInterpreter}; -use evm_interpreter::{Capture, Etable, ExitSucceed, Machine}; use std::rc::Rc; +use evm_interpreter::{ + error::{Capture, ExitSucceed}, + etable::Etable, + machine::Machine, + EtableInterpreter, RunInterpreter, +}; + static ETABLE: Etable<(), (), ()> = Etable::core(); macro_rules! ret_test { diff --git a/interpreter/tests/usability.rs b/interpreter/tests/usability.rs index 02421a987..5a8f5e4ad 100644 --- a/interpreter/tests/usability.rs +++ b/interpreter/tests/usability.rs @@ -1,11 +1,17 @@ -use evm_interpreter::interpreter::{EtableInterpreter, RunInterpreter}; +use std::rc::Rc; + use evm_interpreter::{ - trap::CallCreateTrap, Capture, Context, Control, Etable, ExitError, ExitSucceed, Log, Machine, - Opcode, RuntimeBackend, RuntimeBaseBackend, RuntimeEnvironment, RuntimeState, - TransactionContext, + error::{CallCreateTrap, Capture, ExitError, ExitSucceed}, + etable::{Control, Etable}, + machine::Machine, + opcode::Opcode, + runtime::{ + Context, Log, RuntimeBackend, RuntimeBaseBackend, RuntimeEnvironment, RuntimeState, + TransactionContext, + }, + EtableInterpreter, RunInterpreter, }; use primitive_types::{H160, H256, U256}; -use std::rc::Rc; const CODE1: &str = "60e060020a6000350480632839e92814601e57806361047ff414603457005b602a6004356024356047565b8060005260206000f35b603d6004356099565b8060005260206000f35b600082600014605457605e565b8160010190506093565b81600014606957607b565b60756001840360016047565b90506093565b609060018403608c85600186036047565b6047565b90505b92915050565b6000816000148060a95750816001145b60b05760b7565b81905060cf565b60c1600283036099565b60cb600184036099565b0190505b91905056"; const DATA1: &str = "2839e92800000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001"; diff --git a/jsontests/src/error.rs b/jsontests/src/error.rs index b492a1e04..75df2b289 100644 --- a/jsontests/src/error.rs +++ b/jsontests/src/error.rs @@ -1,7 +1,4 @@ -#![allow(clippy::upper_case_acronyms)] -use thiserror::Error; - -#[derive(Error, Debug)] +#[derive(Debug, thiserror::Error)] #[allow(dead_code)] pub enum TestError { #[error("state root is different")] @@ -10,14 +7,15 @@ pub enum TestError { ExpectException, } -#[derive(Error, Debug)] +#[allow(clippy::upper_case_acronyms)] +#[derive(Debug, thiserror::Error)] pub enum Error { #[error("io error")] IO(#[from] std::io::Error), #[error("json error")] JSON(#[from] serde_json::Error), #[error("evm error")] - EVM(#[from] evm::ExitError), + EVM(#[from] evm::interpreter::error::ExitError), #[error("unsupported fork")] UnsupportedFork, #[error("non-utf8 filename")] diff --git a/jsontests/src/hash.rs b/jsontests/src/hash.rs index 7a7e91e52..a804ce9c0 100644 --- a/jsontests/src/hash.rs +++ b/jsontests/src/hash.rs @@ -1,8 +1,9 @@ -use crate::in_memory::InMemoryBackend; -use evm::utils::h256_to_u256; +use evm::interpreter::utils::h256_to_u256; use primitive_types::{H256, U256}; use sha3::{Digest, Keccak256}; +use crate::in_memory::InMemoryBackend; + /// Basic account type. #[derive(Debug, Clone, PartialEq, Eq)] pub struct TrieAccount { diff --git a/jsontests/src/in_memory.rs b/jsontests/src/in_memory.rs index 05fc87e69..f25c60a88 100644 --- a/jsontests/src/in_memory.rs +++ b/jsontests/src/in_memory.rs @@ -1,7 +1,11 @@ -use evm::{backend::OverlayedChangeSet, RuntimeBaseBackend, RuntimeEnvironment}; -use primitive_types::{H160, H256, U256}; use std::collections::BTreeMap; +use evm::{ + backend::OverlayedChangeSet, + interpreter::runtime::{RuntimeBaseBackend, RuntimeEnvironment}, +}; +use primitive_types::{H160, H256, U256}; + #[derive(Clone, Debug)] pub struct InMemoryEnvironment { pub block_hashes: BTreeMap, diff --git a/jsontests/src/main.rs b/jsontests/src/main.rs index 390571365..c21ee0a62 100644 --- a/jsontests/src/main.rs +++ b/jsontests/src/main.rs @@ -4,10 +4,10 @@ mod in_memory; mod run; mod types; -use crate::error::Error; -use crate::types::*; use clap::Parser; +use crate::{error::Error, types::*}; + #[derive(Parser)] #[command(author, version, about, long_about = None)] struct Cli { diff --git a/jsontests/src/run.rs b/jsontests/src/run.rs index 5fa6e8c6a..68080cf03 100644 --- a/jsontests/src/run.rs +++ b/jsontests/src/run.rs @@ -1,16 +1,22 @@ -use crate::error::{Error, TestError}; -use crate::in_memory::{InMemoryAccount, InMemoryBackend, InMemoryEnvironment}; -use crate::types::{Fork, TestCompletionStatus, TestData, TestExpectException, TestMulti}; -use evm::backend::OverlayedBackend; -use evm::standard::{Config, Etable, EtableResolver, Invoker, TransactArgs}; -use evm::utils::u256_to_h256; -use evm::Capture; -use evm::{interpreter::Interpreter, GasState}; +use std::{ + collections::{BTreeMap, BTreeSet}, + fs::{self, File}, + io::BufReader, +}; + +use evm::{ + backend::OverlayedBackend, + interpreter::{error::Capture, runtime::GasState, utils::u256_to_h256, Interpreter}, + standard::{Config, Etable, EtableResolver, Invoker, TransactArgs}, +}; use evm_precompile::StandardPrecompileSet; use primitive_types::U256; -use std::collections::{BTreeMap, BTreeSet}; -use std::fs::{self, File}; -use std::io::BufReader; + +use crate::{ + error::{Error, TestError}, + in_memory::{InMemoryAccount, InMemoryBackend, InMemoryEnvironment}, + types::{Fork, TestCompletionStatus, TestData, TestExpectException, TestMulti}, +}; const BASIC_FILE_PATH_TO_TRIM: [&str; 2] = [ "jsontests/res/ethtests/GeneralStateTests/", diff --git a/jsontests/src/types.rs b/jsontests/src/types.rs index 82b6be9f4..9e93a29a2 100644 --- a/jsontests/src/types.rs +++ b/jsontests/src/types.rs @@ -1,11 +1,11 @@ +use std::{collections::BTreeMap, fmt}; + use hex::FromHex; use primitive_types::{H160, H256, U256}; use serde::{ de::{Error, Visitor}, Deserialize, Deserializer, }; -use std::collections::BTreeMap; -use std::fmt; /// Statistic type to gather tests pass completion status #[derive(Default, Clone, Debug, Eq, PartialEq)] diff --git a/precompile/src/blake2/mod.rs b/precompile/src/blake2/mod.rs index 81144c5f4..f94a64b00 100644 --- a/precompile/src/blake2/mod.rs +++ b/precompile/src/blake2/mod.rs @@ -1,7 +1,11 @@ mod eip152; +use evm::{ + interpreter::error::{ExitException, ExitResult, ExitSucceed}, + GasMutState, +}; + use crate::PurePrecompile; -use evm::{ExitException, ExitResult, ExitSucceed, GasMutState}; pub struct Blake2F; diff --git a/precompile/src/bn128.rs b/precompile/src/bn128.rs index 5b8c5793b..44d90597a 100644 --- a/precompile/src/bn128.rs +++ b/precompile/src/bn128.rs @@ -1,8 +1,13 @@ -use crate::PurePrecompile; use alloc::vec::Vec; -use evm::{ExitError, ExitException, ExitResult, ExitSucceed, GasMutState}; + +use evm::{ + interpreter::error::{ExitError, ExitException, ExitResult, ExitSucceed}, + GasMutState, +}; use primitive_types::U256; +use crate::PurePrecompile; + /// Copy bytes from input to target. fn read_input(source: &[u8], target: &mut [u8], offset: usize) { // Out of bounds, nothing to copy. diff --git a/precompile/src/lib.rs b/precompile/src/lib.rs index 6042bdb52..00cc02829 100644 --- a/precompile/src/lib.rs +++ b/precompile/src/lib.rs @@ -20,17 +20,25 @@ mod bn128; mod modexp; mod simple; -pub use crate::blake2::Blake2F; -pub use crate::bn128::{Bn128Add, Bn128Mul, Bn128Pairing}; -pub use crate::modexp::Modexp; -pub use crate::simple::{ECRecover, Identity, Ripemd160, Sha256}; - use alloc::vec::Vec; -use evm::standard::{Config, PrecompileSet}; -use evm::{ExitError, ExitException, ExitResult, GasMutState, RuntimeState}; +use evm::{ + interpreter::{ + error::{ExitError, ExitException, ExitResult}, + runtime::RuntimeState, + }, + standard::{Config, PrecompileSet}, + GasMutState, +}; use primitive_types::H160; +pub use crate::{ + blake2::Blake2F, + bn128::{Bn128Add, Bn128Mul, Bn128Pairing}, + modexp::Modexp, + simple::{ECRecover, Identity, Ripemd160, Sha256}, +}; + pub trait PurePrecompile { fn execute(&self, input: &[u8], gasometer: &mut G) -> (ExitResult, Vec); } diff --git a/precompile/src/modexp.rs b/precompile/src/modexp.rs index 39d86d5fa..a67676114 100644 --- a/precompile/src/modexp.rs +++ b/precompile/src/modexp.rs @@ -1,9 +1,14 @@ -use crate::PurePrecompile; use alloc::{vec, vec::Vec}; use core::cmp::max; -use evm::{ExitException, ExitResult, ExitSucceed, GasMutState}; + +use evm::{ + interpreter::error::{ExitException, ExitResult, ExitSucceed}, + GasMutState, +}; use num::{BigUint, FromPrimitive, Integer, One, ToPrimitive, Zero}; +use crate::PurePrecompile; + pub struct Modexp; const MIN_GAS_COST: u64 = 200; diff --git a/precompile/src/simple.rs b/precompile/src/simple.rs index 58a2912be..c14043abe 100644 --- a/precompile/src/simple.rs +++ b/precompile/src/simple.rs @@ -1,10 +1,15 @@ -use crate::{linear_cost, PurePrecompile}; use core::cmp::min; -use evm::{ExitException, ExitResult, ExitSucceed, GasMutState}; + +use evm::{ + interpreter::error::{ExitException, ExitResult, ExitSucceed}, + GasMutState, +}; use k256::ecdsa::{RecoveryId, Signature, VerifyingKey}; use primitive_types::{H256, U256}; use sha3::{Digest, Keccak256}; +use crate::{linear_cost, PurePrecompile}; + pub struct ECRecover; impl PurePrecompile for ECRecover { diff --git a/rustfmt.toml b/rustfmt.toml index 218e20321..eb74f05bb 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1 +1,3 @@ hard_tabs = true +imports_granularity="Crate" +group_imports = "StdExternalCrate" diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 96436d450..e68e3b5ff 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -13,8 +13,9 @@ mod overlayed; +pub use evm_interpreter::runtime::{RuntimeBackend, RuntimeBaseBackend, RuntimeEnvironment}; + pub use self::overlayed::{OverlayedBackend, OverlayedChangeSet}; -pub use evm_interpreter::{RuntimeBackend, RuntimeBaseBackend, RuntimeEnvironment}; /// Backend with layers that can transactionally be committed or discarded. pub trait TransactionalBackend { diff --git a/src/backend/overlayed.rs b/src/backend/overlayed.rs index 7ffd43df9..20bf960f6 100644 --- a/src/backend/overlayed.rs +++ b/src/backend/overlayed.rs @@ -1,15 +1,18 @@ -use crate::{ - ExitError, ExitException, Log, MergeStrategy, RuntimeBackend, RuntimeBaseBackend, - RuntimeEnvironment, TransactionalBackend, -}; use alloc::{ boxed::Box, collections::{BTreeMap, BTreeSet}, vec::Vec, }; use core::mem; + +use evm_interpreter::{ + error::{ExitError, ExitException}, + runtime::{Log, RuntimeBackend, RuntimeBaseBackend, RuntimeEnvironment}, +}; use primitive_types::{H160, H256, U256}; +use crate::{backend::TransactionalBackend, MergeStrategy}; + #[derive(Clone, Debug)] pub struct OverlayedChangeSet { pub logs: Vec, diff --git a/src/call_stack.rs b/src/call_stack.rs index a615acb0e..09a28f847 100644 --- a/src/call_stack.rs +++ b/src/call_stack.rs @@ -1,8 +1,13 @@ -use crate::interpreter::{Interpreter, RunInterpreter, StepInterpreter}; -use crate::{Capture, ExitError, ExitFatal, ExitResult, Invoker, InvokerControl}; use alloc::vec::Vec; use core::convert::Infallible; +use evm_interpreter::{ + error::{Capture, ExitError, ExitFatal, ExitResult}, + Interpreter, RunInterpreter, StepInterpreter, +}; + +use crate::invoker::{Invoker, InvokerControl}; + struct Substack { invoke: TrD, machine: M, diff --git a/src/gasometer.rs b/src/gasometer.rs index 7114c4369..ce3b75ae8 100644 --- a/src/gasometer.rs +++ b/src/gasometer.rs @@ -1,6 +1,6 @@ //! EVM gasometer. -use crate::{ExitError, GasState}; +use evm_interpreter::{error::ExitError, runtime::GasState}; use primitive_types::U256; pub trait GasMutState: GasState { diff --git a/src/invoker.rs b/src/invoker.rs index 755834763..9d8b76b61 100644 --- a/src/invoker.rs +++ b/src/invoker.rs @@ -1,6 +1,10 @@ -use crate::{interpreter::Interpreter, Capture, ExitError, ExitResult}; use alloc::vec::Vec; +use evm_interpreter::{ + error::{Capture, ExitError, ExitResult}, + Interpreter, +}; + /// Control for an invoker. pub enum InvokerControl { /// Pushing the call stack. diff --git a/src/lib.rs b/src/lib.rs index 12857e99f..70fd5c25e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,12 +72,14 @@ mod call_stack; mod gasometer; mod invoker; -pub use evm_interpreter::*; +pub use evm_interpreter as interpreter; -pub use crate::backend::TransactionalBackend; -pub use crate::call_stack::{transact, HeapTransact}; -pub use crate::gasometer::GasMutState; -pub use crate::invoker::{Invoker, InvokerControl}; +pub use crate::{ + backend::TransactionalBackend, + call_stack::{transact, HeapTransact}, + gasometer::GasMutState, + invoker::{Invoker, InvokerControl}, +}; /// Merge strategy of a backend substate layer or a call stack gasometer layer. #[derive(Clone, Debug, Copy)] diff --git a/src/standard/gasometer/consts.rs b/src/standard/gasometer/consts.rs index f51085577..115fe5c19 100644 --- a/src/standard/gasometer/consts.rs +++ b/src/standard/gasometer/consts.rs @@ -1,4 +1,4 @@ -use evm_interpreter::Opcode; +use evm_interpreter::opcode::Opcode; pub const G_ZERO: u64 = 0; pub const G_BASE: u64 = 2; diff --git a/src/standard/gasometer/costs.rs b/src/standard/gasometer/costs.rs index dda497e66..cbf611ff0 100644 --- a/src/standard/gasometer/costs.rs +++ b/src/standard/gasometer/costs.rs @@ -1,9 +1,9 @@ -use super::consts::*; -use super::utils::log2floor; -use crate::standard::Config; -use evm_interpreter::ExitException; +use evm_interpreter::error::ExitException; use primitive_types::{H256, U256}; +use super::{consts::*, utils::log2floor}; +use crate::standard::Config; + pub fn call_extra_check(gas: U256, after_gas: u64, config: &Config) -> Result<(), ExitException> { if config.err_on_call_with_more_gas && U256::from(after_gas) < gas { Err(ExitException::OutOfGas) diff --git a/src/standard/gasometer/mod.rs b/src/standard/gasometer/mod.rs index a526de53b..2b09bda0f 100644 --- a/src/standard/gasometer/mod.rs +++ b/src/standard/gasometer/mod.rs @@ -2,15 +2,20 @@ mod consts; mod costs; mod utils; -use crate::standard::Config; -use crate::{ - Control, ExitError, ExitException, Machine, MergeStrategy, Opcode, RuntimeBackend, - RuntimeState, Stack, -}; use alloc::vec::Vec; use core::cmp::{max, min}; + +use evm_interpreter::{ + error::{ExitError, ExitException}, + etable::Control, + machine::{Machine, Stack}, + opcode::Opcode, + runtime::{RuntimeBackend, RuntimeState}, +}; use primitive_types::{H160, H256, U256}; +use crate::{standard::Config, MergeStrategy}; + pub struct GasometerState<'config> { gas_limit: u64, memory_gas: u64, diff --git a/src/standard/gasometer/utils.rs b/src/standard/gasometer/utils.rs index 9630b9ab9..b2d7880f1 100644 --- a/src/standard/gasometer/utils.rs +++ b/src/standard/gasometer/utils.rs @@ -1,7 +1,7 @@ use primitive_types::U256; pub fn log2floor(value: U256) -> u64 { - assert!(value != U256::zero()); + assert_ne!(value, U256::zero()); let mut l: u64 = 256; for i in 0..4 { let i = 3 - i; diff --git a/src/standard/invoker/mod.rs b/src/standard/invoker/mod.rs index e7e6576e6..70bf27454 100644 --- a/src/standard/invoker/mod.rs +++ b/src/standard/invoker/mod.rs @@ -2,24 +2,35 @@ mod resolver; pub mod routines; mod state; -pub use self::resolver::{EtableResolver, PrecompileSet, Resolver}; -pub use self::state::InvokerState; +use alloc::{rc::Rc, vec::Vec}; +use core::{cmp::min, convert::Infallible}; -use super::Config; -use crate::trap::{CallCreateTrap, CallCreateTrapData, CallTrapData, CreateScheme, CreateTrapData}; -use crate::{ - interpreter::Interpreter, Capture, Context, ExitError, ExitException, ExitResult, ExitSucceed, - GasState, Invoker as InvokerT, InvokerControl, MergeStrategy, Opcode, RuntimeBackend, - RuntimeEnvironment, RuntimeState, TransactionContext, TransactionalBackend, Transfer, - TrapConsume, +use evm_interpreter::{ + error::{ + CallCreateTrap, CallCreateTrapData, CallTrapData, Capture, CreateScheme, CreateTrapData, + ExitError, ExitException, ExitResult, ExitSucceed, TrapConsume, + }, + opcode::Opcode, + runtime::{ + Context, GasState, RuntimeBackend, RuntimeEnvironment, RuntimeState, TransactionContext, + Transfer, + }, + Interpreter, }; -use alloc::rc::Rc; -use alloc::vec::Vec; -use core::cmp::min; -use core::convert::Infallible; use primitive_types::{H160, H256, U256}; use sha3::{Digest, Keccak256}; +pub use self::{ + resolver::{EtableResolver, PrecompileSet, Resolver}, + state::InvokerState, +}; +use crate::{ + backend::TransactionalBackend, + invoker::{Invoker as InvokerT, InvokerControl}, + standard::Config, + MergeStrategy, +}; + /// A trap that can be turned into either a call/create trap (where we push new /// call stack), or an interrupt (an external signal). pub trait IntoCallCreateTrap { diff --git a/src/standard/invoker/resolver.rs b/src/standard/invoker/resolver.rs index 4c46534c0..348afd958 100644 --- a/src/standard/invoker/resolver.rs +++ b/src/standard/invoker/resolver.rs @@ -1,11 +1,16 @@ -use crate::interpreter::{EtableInterpreter, Interpreter}; -use crate::{ - standard::Config, EtableSet, ExitError, ExitResult, InvokerControl, Machine, RuntimeBackend, - RuntimeState, -}; use alloc::{rc::Rc, vec::Vec}; + +use evm_interpreter::{ + error::{ExitError, ExitResult}, + etable::EtableSet, + machine::Machine, + runtime::{RuntimeBackend, RuntimeState}, + EtableInterpreter, Interpreter, +}; use primitive_types::H160; +use crate::{invoker::InvokerControl, standard::Config}; + /// A code resolver. /// /// The resolver handles how a call (with the target code address) or create diff --git a/src/standard/invoker/routines.rs b/src/standard/invoker/routines.rs index fbc0ff8a2..9bd3d3fce 100644 --- a/src/standard/invoker/routines.rs +++ b/src/standard/invoker/routines.rs @@ -1,12 +1,19 @@ -use super::{CallTrapData, CreateTrapData, InvokerState, Resolver, SubstackInvoke}; -use crate::standard::Config; -use crate::{ - ExitError, ExitException, ExitResult, InvokerControl, MergeStrategy, Opcode, RuntimeBackend, - RuntimeEnvironment, RuntimeState, TransactionalBackend, Transfer, -}; use alloc::vec::Vec; + +use evm_interpreter::{ + error::{CallTrapData, CreateTrapData, ExitError, ExitException, ExitResult}, + opcode::Opcode, + runtime::{RuntimeBackend, RuntimeEnvironment, RuntimeState, Transfer}, +}; use primitive_types::{H160, U256}; +use crate::{ + backend::TransactionalBackend, + invoker::InvokerControl, + standard::{Config, InvokerState, Resolver, SubstackInvoke}, + MergeStrategy, +}; + #[allow(clippy::too_many_arguments, clippy::type_complexity)] pub fn make_enter_call_machine( _config: &Config, diff --git a/src/standard/invoker/state.rs b/src/standard/invoker/state.rs index eef276a28..3957329f2 100644 --- a/src/standard/invoker/state.rs +++ b/src/standard/invoker/state.rs @@ -1,7 +1,13 @@ -use crate::{standard::Config, ExitError, GasState, MergeStrategy, RuntimeState}; use alloc::vec::Vec; + +use evm_interpreter::{ + error::ExitError, + runtime::{GasState, RuntimeState}, +}; use primitive_types::{H160, H256, U256}; +use crate::{standard::Config, MergeStrategy}; + pub trait InvokerState<'config>: GasState + Sized { fn new_transact_call( runtime: RuntimeState, diff --git a/src/standard/mod.rs b/src/standard/mod.rs index e364d723d..7b9b1a9f3 100644 --- a/src/standard/mod.rs +++ b/src/standard/mod.rs @@ -8,26 +8,34 @@ mod config; mod gasometer; mod invoker; -pub use self::config::Config; -pub use self::gasometer::{eval as eval_gasometer, GasometerState}; -pub use self::invoker::{ - routines, EtableResolver, Invoker, InvokerState, PrecompileSet, Resolver, SubstackInvoke, - TransactArgs, TransactInvoke, TransactValue, -}; - -use crate::{ExitError, GasMutState, GasState, MergeStrategy, RuntimeState}; use alloc::vec::Vec; + +use evm_interpreter::{ + error::{CallCreateTrap, ExitError}, + etable, machine, + runtime::{GasState, RuntimeState}, +}; use primitive_types::{H160, H256, U256}; +pub use self::{ + config::Config, + gasometer::{eval as eval_gasometer, GasometerState}, + invoker::{ + routines, EtableResolver, Invoker, InvokerState, PrecompileSet, Resolver, SubstackInvoke, + TransactArgs, TransactInvoke, TransactValue, + }, +}; +use crate::{gasometer::GasMutState, MergeStrategy}; + /// Standard machine. -pub type Machine<'config> = crate::Machine>; +pub type Machine<'config> = machine::Machine>; /// Standard Etable opcode handle function. -pub type Efn<'config, H> = crate::Efn, H, crate::trap::CallCreateTrap>; +pub type Efn<'config, H> = etable::Efn, H, CallCreateTrap>; /// Standard Etable. pub type Etable<'config, H, F = Efn<'config, H>> = - crate::Etable, H, crate::trap::CallCreateTrap, F>; + etable::Etable, H, CallCreateTrap, F>; pub struct State<'config> { pub runtime: RuntimeState, diff --git a/tracer/src/lib.rs b/tracer/src/lib.rs index 7b0b01f81..fb8daf698 100644 --- a/tracer/src/lib.rs +++ b/tracer/src/lib.rs @@ -1,6 +1,6 @@ mod standard; -use evm::{Machine, Opcode}; +use evm::interpreter::{machine::Machine, opcode::Opcode}; pub trait EvalTracer { fn on_eval(&mut self, machine: &Machine, handle: &H, opcode: Opcode, position: usize); diff --git a/tracer/src/standard.rs b/tracer/src/standard.rs index 1177cf0f7..73f9fabef 100644 --- a/tracer/src/standard.rs +++ b/tracer/src/standard.rs @@ -1,5 +1,7 @@ -use evm::standard::{Machine, State}; -use evm::Opcode; +use evm::{ + interpreter::opcode::Opcode, + standard::{Machine, State}, +}; pub trait EvalTracer { fn on_eval(&mut self, machine: &Machine, handle: &H, opcode: Opcode, position: usize);