diff --git a/Cargo.toml b/Cargo.toml index 7e01c456a..b26032d5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,6 @@ scale-info = { version = "2.3", default-features = false, features = ["derive"], serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } evm-interpreter = { version = "0.2.0-dev", path = "interpreter", default-features = false } -evm-gasometer = { version = "0.40", path = "gasometer", default-features = false } [dev-dependencies] criterion = "0.4" @@ -42,7 +41,6 @@ std = [ "scale-info/std", "serde/std", "evm-interpreter/std", - "evm-gasometer/std", ] with-codec = [ "scale-codec", @@ -62,5 +60,4 @@ with-serde = [ [workspace] members = [ "interpreter", - "gasometer", ] diff --git a/gasometer/Cargo.toml b/gasometer/Cargo.toml deleted file mode 100644 index 881c8a397..000000000 --- a/gasometer/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "evm-gasometer" -version = "0.40.0" -license = "Apache-2.0" -authors = ["Wei Tang ", "Parity Technologies "] -description = "Portable Ethereum Virtual Machine implementation written in pure Rust." -repository = "https://github.com/sorpaas/rust-evm" -keywords = ["no_std", "ethereum"] -edition = "2018" - -[dependencies] -primitive-types = { version = "0.12", default-features = false } - -evm-interpreter = { version = "0.2.0-dev", path = "../interpreter", default-features = false } - -[features] -default = ["std"] -std = [ - "primitive-types/std", - "evm-interpreter/std", -] diff --git a/interpreter/src/eval/system.rs b/interpreter/src/eval/system.rs index 7e95197c6..f787c0ff4 100644 --- a/interpreter/src/eval/system.rs +++ b/interpreter/src/eval/system.rs @@ -281,7 +281,7 @@ pub fn gas, H: Handler, Tr>( machine: &mut Machine, handler: &H, ) -> Control { - push_u256!(machine, handler.gas_left()); + push_u256!(machine, handler.gas()); Control::Continue } diff --git a/interpreter/src/lib.rs b/interpreter/src/lib.rs index 6ec1152b4..3a5a975d9 100644 --- a/interpreter/src/lib.rs +++ b/interpreter/src/lib.rs @@ -20,7 +20,7 @@ pub use crate::error::{Capture, ExitError, ExitException, ExitFatal, ExitResult, pub use crate::eval::{Control, Efn, Etable}; pub use crate::memory::Memory; pub use crate::opcode::Opcode; -pub use crate::runtime::{CallCreateTrap, Context, Handler, RuntimeMachine, RuntimeState}; +pub use crate::runtime::{CallCreateTrap, Context, Handler, RuntimeState}; pub use crate::stack::Stack; pub use crate::valids::Valids; diff --git a/interpreter/src/runtime.rs b/interpreter/src/runtime.rs index f1aa4d734..33c25e495 100644 --- a/interpreter/src/runtime.rs +++ b/interpreter/src/runtime.rs @@ -1,9 +1,6 @@ use crate::{ExitError, Opcode}; use primitive_types::{H160, H256, U256}; -/// Runtime machine. -pub type RuntimeMachine = crate::Machine; - /// Runtime state. #[derive(Clone, Debug)] pub struct RuntimeState { @@ -35,6 +32,29 @@ impl CallCreateTrap for Opcode { } pub trait RuntimeBackend { + /// Get environmental block hash. + fn block_hash(&self, number: U256) -> H256; + /// Get environmental block number. + fn block_number(&self) -> U256; + /// Get environmental coinbase. + fn block_coinbase(&self) -> H160; + /// Get environmental block timestamp. + fn block_timestamp(&self) -> U256; + /// Get environmental block difficulty. + fn block_difficulty(&self) -> U256; + /// Get environmental block randomness. + fn block_randomness(&self) -> Option; + /// Get environmental gas limit. + fn block_gas_limit(&self) -> U256; + /// Environmental block base fee. + fn block_base_fee_per_gas(&self) -> U256; + /// Get environmental chain ID. + fn chain_id(&self) -> U256; + /// Get the gas price value. + fn gas_price(&self) -> U256; + /// Get execution origin. + fn origin(&self) -> H160; + /// Get balance of address. fn balance(&self, address: H160) -> U256; /// Get code size of address. @@ -65,35 +85,99 @@ pub trait RuntimeBackend { fn mark_delete(&mut self, address: H160, target: H160) -> Result<(), ExitError>; } -pub trait RuntimeEnvironmentalBackend { - /// Get environmental block hash. - fn block_hash(&self, number: U256) -> H256; - /// Get environmental block number. - fn block_number(&self) -> U256; - /// Get environmental coinbase. - fn block_coinbase(&self) -> H160; - /// Get environmental block timestamp. - fn block_timestamp(&self) -> U256; - /// Get environmental block difficulty. - fn block_difficulty(&self) -> U256; - /// Get environmental block randomness. - fn block_randomness(&self) -> Option; - /// Get environmental gas limit. - fn block_gas_limit(&self) -> U256; - /// Environmental block base fee. - fn block_base_fee_per_gas(&self) -> U256; - /// Get environmental chain ID. - fn chain_id(&self) -> U256; - /// Get the gas price value. - fn gas_price(&self) -> U256; - /// Get execution origin. - fn origin(&self) -> H160; +pub trait RuntimeGasometer { + /// Get the gas left value. + fn gas(&self) -> U256; } -pub trait RuntimeGasometerBackend { - /// Get the gas left value. - fn gas_left(&self) -> U256; +/// Handler trait for runtime. +/// +/// The handler is generally expected to be a `(backend, gasometer)` tuple, with extensions added +/// to `backend`. +pub trait Handler: RuntimeBackend + RuntimeGasometer {} + +impl<'b, 'g, G: RuntimeGasometer, H: RuntimeBackend> RuntimeBackend for (&'b mut G, &'g mut H) { + fn block_hash(&self, number: U256) -> H256 { + self.1.block_hash(number) + } + fn block_number(&self) -> U256 { + self.1.block_number() + } + fn block_coinbase(&self) -> H160 { + self.1.block_coinbase() + } + fn block_timestamp(&self) -> U256 { + self.1.block_timestamp() + } + fn block_difficulty(&self) -> U256 { + self.1.block_difficulty() + } + fn block_randomness(&self) -> Option { + self.1.block_randomness() + } + fn block_gas_limit(&self) -> U256 { + self.1.block_gas_limit() + } + fn block_base_fee_per_gas(&self) -> U256 { + self.1.block_base_fee_per_gas() + } + fn chain_id(&self) -> U256 { + self.1.chain_id() + } + fn gas_price(&self) -> U256 { + self.1.gas_price() + } + fn origin(&self) -> H160 { + self.1.origin() + } + + fn balance(&self, address: H160) -> U256 { + self.1.balance(address) + } + fn code_size(&self, address: H160) -> U256 { + self.1.code_size(address) + } + fn code_hash(&self, address: H160) -> H256 { + self.1.code_hash(address) + } + fn code(&self, address: H160) -> Vec { + self.1.code(address) + } + fn storage(&self, address: H160, index: H256) -> H256 { + self.1.storage(address, index) + } + fn original_storage(&self, address: H160, index: H256) -> H256 { + self.1.original_storage(address, index) + } + + fn exists(&self, address: H160) -> bool { + self.1.exists(address) + } + fn deleted(&self, address: H160) -> bool { + self.1.deleted(address) + } + fn is_cold(&self, address: H160, index: Option) -> bool { + self.1.is_cold(address, index) + } + fn mark_hot(&mut self, address: H160, index: Option) -> Result<(), ExitError> { + self.1.mark_hot(address, index) + } + fn set_storage(&mut self, address: H160, index: H256, value: H256) -> Result<(), ExitError> { + self.1.set_storage(address, index, value) + } + + fn log(&mut self, address: H160, topics: Vec, data: Vec) -> Result<(), ExitError> { + self.1.log(address, topics, data) + } + fn mark_delete(&mut self, address: H160, target: H160) -> Result<(), ExitError> { + self.1.mark_delete(address, target) + } +} + +impl<'b, 'g, G: RuntimeGasometer, H: RuntimeBackend> RuntimeGasometer for (&'b mut G, &'g mut H) { + fn gas(&self) -> U256 { + self.0.gas() + } } -/// EVM context handler. -pub trait Handler: RuntimeBackend + RuntimeEnvironmentalBackend + RuntimeGasometerBackend {} +impl<'b, 'g, G: RuntimeGasometer, H: RuntimeBackend> Handler for (&'b mut G, &'g mut H) {} diff --git a/src/executor.rs b/src/call_stack.rs similarity index 81% rename from src/executor.rs rename to src/call_stack.rs index 1a44bc2a8..f690f89c5 100644 --- a/src/executor.rs +++ b/src/call_stack.rs @@ -1,40 +1,10 @@ use crate::{ gasometer::{run_with_gasometer, Gasometer, GasometerMergeStrategy}, - Capture, Control, Etable, ExitError, ExitResult, Machine, Opcode, TransactionalBackend, - TransactionalMergeStrategy, + Capture, Control, Etable, ExitError, ExitResult, Invoker, Machine, Opcode, + TransactionalBackend, TransactionalMergeStrategy, }; use core::convert::Infallible; -pub trait Invoker { - type Interrupt; - type TrapData; - - fn feedback_trap_data( - &self, - result: ExitResult, - child: Machine, - trap_data: Self::TrapData, - machine: &mut Machine, - gasometer: &mut G, - handler: &mut H, - ) -> Result<(), ExitError>; - - fn prepare_trap_data( - &self, - trap: Tr, - depth: usize, - machine: &mut Machine, - gasometer: &mut G, - handler: &mut H, - ) -> Capture, Self::Interrupt>; - - fn build_child_stack( - &self, - trap_data: &Self::TrapData, - handler: &mut H, - ) -> Result<(Machine, G, bool), ExitError>; -} - struct TrappedCallStackData { trap_data: TrD, machine: Machine, @@ -42,7 +12,7 @@ struct TrappedCallStackData { is_static: bool, } -enum LastCallStackData { +enum LastCallStackData { Running { machine: Machine, gasometer: G, @@ -61,26 +31,26 @@ enum LastCallStackData { }, } -pub struct CallStack<'backend, 'invoker, S, H, Tr, G, I: Invoker> { - stack: Vec>, - last: LastCallStackData, +pub struct CallStack<'backend, 'invoker, S, G, H, Tr, I: Invoker> { + stack: Vec>, + last: LastCallStackData, initial_depth: usize, backend: &'backend mut H, invoker: &'invoker I, } -impl<'backend, 'invoker, S, H, Tr, G, I> CallStack<'backend, 'invoker, S, H, Tr, G, I> +impl<'backend, 'invoker, S, G, H, Tr, I> CallStack<'backend, 'invoker, S, G, H, Tr, I> where G: Gasometer, H: TransactionalBackend, - I: Invoker, + I: Invoker, { pub fn new( machine: Machine, gasometer: G, + backend: &'backend mut H, is_static: bool, initial_depth: usize, - backend: &'backend mut H, invoker: &'invoker I, ) -> Self { let last = LastCallStackData::Running { @@ -116,30 +86,33 @@ where pub fn execute( machine: Machine, gasometer: G, + backend: &'backend mut H, is_static: bool, initial_depth: usize, - backend: &'backend mut H, invoker: &'invoker I, - etable: &Etable, + etable: &Etable, ) -> (Self, Capture<(), I::Interrupt>) where - F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, + F: Fn(&mut Machine, &mut (&mut G, &mut H), Opcode, usize) -> Control, { let call_stack = Self::new( machine, gasometer, + backend, is_static, initial_depth, - backend, invoker, ); call_stack.run(etable) } - pub fn run(mut self, etable: &Etable) -> (Self, Capture<(), I::Interrupt>) + pub fn run( + mut self, + etable: &Etable, + ) -> (Self, Capture<(), I::Interrupt>) where - F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, + F: Fn(&mut Machine, &mut (&mut G, &mut H), Opcode, usize) -> Control, { loop { let step_ret; @@ -151,9 +124,12 @@ where } } - fn step(mut self, etable: &Etable) -> (Self, Option>) + fn step( + mut self, + etable: &Etable, + ) -> (Self, Option>) where - F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, + F: Fn(&mut Machine, &mut (&mut G, &mut H), Opcode, usize) -> Control, { let mut step_ret: Option> = None; @@ -175,8 +151,8 @@ where let result = run_with_gasometer( &mut machine, &mut gasometer, - is_static, self.backend, + is_static, etable, ); LastCallStackData::Exited { @@ -256,10 +232,10 @@ where Capture::Trap(trap) => { match self.invoker.prepare_trap_data( trap, - self.initial_depth + self.stack.len() + 1, &mut machine, &mut gasometer, self.backend, + self.initial_depth + self.stack.len() + 1, ) { Capture::Exit(Ok(trap_data)) => { self.backend.push_substate(); @@ -316,36 +292,38 @@ where } } -pub fn execute( +pub fn execute( mut machine: Machine, mut gasometer: G, + backend: &mut H, is_static: bool, initial_depth: usize, heap_depth: Option, - backend: &mut H, invoker: &I, - etable: &Etable, + etable: &Etable, ) -> (Machine, G, ExitResult) where G: Gasometer, H: TransactionalBackend, - I: Invoker, - F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, + I: Invoker, + F: Fn(&mut Machine, &mut (&mut G, &mut H), Opcode, usize) -> Control, { - let mut result = run_with_gasometer(&mut machine, &mut gasometer, is_static, backend, etable); + let mut result = run_with_gasometer(&mut machine, &mut gasometer, backend, is_static, etable); loop { match result { Capture::Exit(exit) => return (machine, gasometer, exit), Capture::Trap(trap) => { - let prepared_trap_data: Capture, Infallible> = - invoker.prepare_trap_data( - trap, - initial_depth + 1, - &mut machine, - &mut gasometer, - backend, - ); + let prepared_trap_data: Capture< + Result, + Infallible, + > = invoker.prepare_trap_data( + trap, + &mut machine, + &mut gasometer, + backend, + initial_depth + 1, + ); match prepared_trap_data { Capture::Exit(Ok(trap_data)) => { @@ -360,9 +338,9 @@ where let (call_stack, _infallible) = CallStack::execute( sub_machine, sub_gasometer, + backend, sub_is_static, initial_depth + 1, - backend, invoker, etable, ); @@ -372,10 +350,10 @@ where execute( sub_machine, sub_gasometer, + backend, sub_is_static, initial_depth + 1, heap_depth, - backend, invoker, etable, ) @@ -409,8 +387,8 @@ where result = run_with_gasometer( &mut machine, &mut gasometer, - is_static, backend, + is_static, etable, ); } diff --git a/gasometer/src/lib.rs b/src/gasometer.rs similarity index 69% rename from gasometer/src/lib.rs rename to src/gasometer.rs index 549f948a9..ffc823bba 100644 --- a/gasometer/src/lib.rs +++ b/src/gasometer.rs @@ -1,16 +1,5 @@ //! EVM gasometer. -#![cfg_attr(not(feature = "std"), no_std)] - -mod config; -mod consts; -mod costs; -mod standard; -mod utils; - -pub use crate::config::Config; -pub use crate::standard::StandardGasometer; - use core::ops::{Add, AddAssign, Sub, SubAssign}; use evm_interpreter::{Capture, Control, Etable, ExitError, ExitResult, Machine, Opcode}; use primitive_types::U256; @@ -42,7 +31,7 @@ pub trait Gasometer: Sized { fn record_stepn( &mut self, machine: &Machine, - handler: &H, + backend: &H, is_static: bool, ) -> Result; fn record_codedeposit(&mut self, len: usize) -> Result<(), ExitError>; @@ -50,20 +39,22 @@ pub trait Gasometer: Sized { fn merge(&mut self, other: Self, strategy: GasometerMergeStrategy); } -pub fn run_with_gasometer( +pub fn run_with_gasometer( machine: &mut Machine, gasometer: &mut G, + backend: &mut H, is_static: bool, - handler: &mut H, - etable: &Etable, + etable: &Etable, ) -> Capture where G: Gasometer, - F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, + F: Fn(&mut Machine, &mut (&mut G, &mut H), Opcode, usize) -> Control, { + let mut handler = (gasometer, backend); + loop { - match gasometer.record_stepn(&machine, handler, is_static) { - Ok(stepn) => match machine.stepn(stepn, handler, etable) { + match handler.0.record_stepn(&machine, handler.1, is_static) { + Ok(stepn) => match machine.stepn(stepn, &mut handler, etable) { Ok(()) => (), Err(c) => return c, }, diff --git a/src/invoker.rs b/src/invoker.rs new file mode 100644 index 000000000..79b0dc197 --- /dev/null +++ b/src/invoker.rs @@ -0,0 +1,31 @@ +use crate::{Capture, ExitError, ExitResult, Machine}; + +pub trait Invoker { + type Interrupt; + type CallCreateTrapData; + + fn feedback_trap_data( + &self, + result: ExitResult, + child: Machine, + trap_data: Self::CallCreateTrapData, + machine: &mut Machine, + gasometer: &mut G, + handler: &mut H, + ) -> Result<(), ExitError>; + + fn prepare_trap_data( + &self, + trap: Tr, + machine: &mut Machine, + gasometer: &mut G, + handler: &mut H, + depth: usize, + ) -> Capture, Self::Interrupt>; + + fn build_child_stack( + &self, + trap_data: &Self::CallCreateTrapData, + handler: &mut H, + ) -> Result<(Machine, G, bool), ExitError>; +} diff --git a/src/lib.rs b/src/lib.rs index 7501ce7ed..7898aa81c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,11 +6,16 @@ extern crate alloc; +pub mod standard; + mod backend; -pub mod executor; +mod call_stack; +mod gasometer; +mod invoker; -pub use evm_gasometer as gasometer; pub use evm_interpreter::*; pub use crate::backend::{TransactionalBackend, TransactionalMergeStrategy}; -pub use crate::gasometer::Config; +pub use crate::call_stack::{execute, CallStack}; +pub use crate::gasometer::{run_with_gasometer, Gas, Gasometer, GasometerMergeStrategy}; +pub use crate::invoker::Invoker; diff --git a/gasometer/src/config.rs b/src/standard/config.rs similarity index 100% rename from gasometer/src/config.rs rename to src/standard/config.rs diff --git a/gasometer/src/consts.rs b/src/standard/gasometer/consts.rs similarity index 100% rename from gasometer/src/consts.rs rename to src/standard/gasometer/consts.rs diff --git a/gasometer/src/costs.rs b/src/standard/gasometer/costs.rs similarity index 98% rename from gasometer/src/costs.rs rename to src/standard/gasometer/costs.rs index 5dc0f15c5..dda497e66 100644 --- a/gasometer/src/costs.rs +++ b/src/standard/gasometer/costs.rs @@ -1,5 +1,6 @@ -use crate::consts::*; -use crate::Config; +use super::consts::*; +use super::utils::log2floor; +use crate::standard::Config; use evm_interpreter::ExitException; use primitive_types::{H256, U256}; @@ -86,7 +87,7 @@ pub fn exp_cost(power: U256, config: &Config) -> Result { let gas = U256::from(G_EXP) .checked_add( U256::from(config.gas_expbyte) - .checked_mul(U256::from(crate::utils::log2floor(power) / 8 + 1)) + .checked_mul(U256::from(log2floor(power) / 8 + 1)) .ok_or(ExitException::OutOfGas)?, ) .ok_or(ExitException::OutOfGas)?; diff --git a/gasometer/src/standard.rs b/src/standard/gasometer/mod.rs similarity index 99% rename from gasometer/src/standard.rs rename to src/standard/gasometer/mod.rs index d16bd1fa4..8631ec69e 100644 --- a/gasometer/src/standard.rs +++ b/src/standard/gasometer/mod.rs @@ -1,4 +1,9 @@ -use crate::{consts, costs, Config, Gasometer, GasometerMergeStrategy}; +mod consts; +mod costs; +mod utils; + +use crate::standard::Config; +use crate::{Gasometer, GasometerMergeStrategy}; use core::cmp::max; use evm_interpreter::{ExitError, ExitException, Handler, Machine, Opcode, RuntimeState, Stack}; use primitive_types::{H160, H256, U256}; diff --git a/gasometer/src/utils.rs b/src/standard/gasometer/utils.rs similarity index 100% rename from gasometer/src/utils.rs rename to src/standard/gasometer/utils.rs diff --git a/src/standard/mod.rs b/src/standard/mod.rs new file mode 100644 index 000000000..b8869bc9a --- /dev/null +++ b/src/standard/mod.rs @@ -0,0 +1,5 @@ +mod config; +mod gasometer; + +pub use self::config::Config; +pub use self::gasometer::StandardGasometer;