diff --git a/jsontests/src/run.rs b/jsontests/src/run.rs index ebcd1ad45..873956e91 100644 --- a/jsontests/src/run.rs +++ b/jsontests/src/run.rs @@ -3,10 +3,10 @@ use crate::types::*; use evm::backend::in_memory::{ InMemoryAccount, InMemoryBackend, InMemoryEnvironment, InMemoryLayer, }; -use evm::standard::{Config, Etable, Gasometer, Invoker, TransactArgs}; +use evm::standard::{Config, Etable, EtableResolver, Gasometer, Invoker, TransactArgs}; use evm::utils::u256_to_h256; use evm::Capture; -use precompiles::StandardResolver; +use precompiles::StandardPrecompileSet; use primitive_types::U256; use std::collections::{BTreeMap, BTreeSet}; @@ -60,8 +60,9 @@ pub fn run_test(_filename: &str, _test_name: &str, test: Test, debug: bool) -> R .collect::>(); let etable = Etable::runtime(); - let resolver = StandardResolver::new(&config); - let invoker = Invoker::<_, Gasometer, _, _, _, _>::new(&config, &resolver, &etable); + let precompiles = StandardPrecompileSet::new(&config); + let resolver = EtableResolver::new(&config, &precompiles, &etable); + let invoker = Invoker::<_, Gasometer, _, _, _>::new(&config, &resolver); let args = TransactArgs::Call { caller: test.transaction.sender, address: test.transaction.to, diff --git a/precompiles/src/lib.rs b/precompiles/src/lib.rs index c3faa6249..c519a0f44 100644 --- a/precompiles/src/lib.rs +++ b/precompiles/src/lib.rs @@ -26,8 +26,8 @@ pub use crate::modexp::Modexp; pub use crate::simple::{ECRecover, Identity, Ripemd160, Sha256}; use alloc::vec::Vec; -use evm::standard::{CodeResolver, Config, Precompile, ResolvedCode}; -use evm::{ExitError, ExitException, ExitResult, RuntimeBackend, RuntimeState, StaticGasometer}; +use evm::standard::{Config, PrecompileSet}; +use evm::{ExitError, ExitException, ExitResult, RuntimeState, StaticGasometer}; use primitive_types::H160; @@ -40,86 +40,51 @@ pub trait PurePrecompile { ) -> (ExitResult, Vec); } -pub enum StandardPrecompile { - ECRecover, - Sha256, - Ripemd160, - Identity, - Modexp, - Bn128Add, - Bn128Mul, - Bn128Pairing, - Blake2F, -} - -impl, G: StaticGasometer, H> Precompile for StandardPrecompile { - fn execute( - &self, - input: &[u8], - state: S, - mut gasometer: G, - _handler: &mut H, - ) -> (ExitResult, (S, G, Vec)) { - let (exit, retval) = match self { - Self::ECRecover => ECRecover.execute(input, state.as_ref(), &mut gasometer), - Self::Sha256 => Sha256.execute(input, state.as_ref(), &mut gasometer), - Self::Ripemd160 => Ripemd160.execute(input, state.as_ref(), &mut gasometer), - Self::Identity => Identity.execute(input, state.as_ref(), &mut gasometer), - Self::Modexp => Modexp.execute(input, state.as_ref(), &mut gasometer), - Self::Bn128Add => Bn128Add.execute(input, state.as_ref(), &mut gasometer), - Self::Bn128Mul => Bn128Mul.execute(input, state.as_ref(), &mut gasometer), - Self::Bn128Pairing => Bn128Pairing.execute(input, state.as_ref(), &mut gasometer), - Self::Blake2F => Blake2F.execute(input, state.as_ref(), &mut gasometer), - }; - - (exit, (state, gasometer, retval)) - } -} - -pub struct StandardResolver<'config> { +pub struct StandardPrecompileSet<'config> { _config: &'config Config, } -impl<'config> StandardResolver<'config> { +impl<'config> StandardPrecompileSet<'config> { pub fn new(config: &'config Config) -> Self { Self { _config: config } } } -impl<'config, S: AsRef, G: StaticGasometer, H: RuntimeBackend> CodeResolver - for StandardResolver<'config> +impl<'config, S: AsRef, G: StaticGasometer, H> PrecompileSet + for StandardPrecompileSet<'config> { - type Precompile = StandardPrecompile; - - fn resolve( + fn execute( &self, - addr: H160, - _gasometer: &mut G, - handler: &mut H, - ) -> Result, ExitError> { + code_address: H160, + input: &[u8], + _is_static: bool, + state: &mut S, + gasometer: &mut G, + _handler: &mut H, + ) -> Option<(ExitResult, Vec)> { // TODO: selectively disable precompiles based on config. - Ok(if addr == address(1) { - ResolvedCode::Precompile(StandardPrecompile::ECRecover) - } else if addr == address(2) { - ResolvedCode::Precompile(StandardPrecompile::Sha256) - } else if addr == address(3) { - ResolvedCode::Precompile(StandardPrecompile::Ripemd160) - } else if addr == address(4) { - ResolvedCode::Precompile(StandardPrecompile::Identity) - } else if addr == address(5) { - ResolvedCode::Precompile(StandardPrecompile::Modexp) - } else if addr == address(6) { - ResolvedCode::Precompile(StandardPrecompile::Bn128Add) - } else if addr == address(7) { - ResolvedCode::Precompile(StandardPrecompile::Bn128Mul) - } else if addr == address(8) { - ResolvedCode::Precompile(StandardPrecompile::Bn128Pairing) - } else if addr == address(9) { - ResolvedCode::Precompile(StandardPrecompile::Blake2F) + if code_address == address(1) { + Some(ECRecover.execute(input, state.as_ref(), gasometer)) + } else if code_address == address(2) { + Some(Sha256.execute(input, state.as_ref(), gasometer)) + } else if code_address == address(3) { + Some(Ripemd160.execute(input, state.as_ref(), gasometer)) + } else if code_address == address(4) { + Some(Identity.execute(input, state.as_ref(), gasometer)) + } else if code_address == address(5) { + Some(Modexp.execute(input, state.as_ref(), gasometer)) + } else if code_address == address(6) { + Some(Bn128Add.execute(input, state.as_ref(), gasometer)) + } else if code_address == address(7) { + Some(Bn128Mul.execute(input, state.as_ref(), gasometer)) + } else if code_address == address(8) { + Some(Bn128Pairing.execute(input, state.as_ref(), gasometer)) + } else if code_address == address(9) { + Some(Blake2F.execute(input, state.as_ref(), gasometer)) } else { - ResolvedCode::Normal(handler.code(addr)) - }) + None + } } } diff --git a/src/call_stack.rs b/src/call_stack.rs index 81f8267da..1dd622e46 100644 --- a/src/call_stack.rs +++ b/src/call_stack.rs @@ -1,4 +1,4 @@ -use crate::{Capture, ExitError, ExitFatal, ExitResult, Invoker, InvokerControl}; +use crate::{Capture, ExitError, ExitFatal, ExitResult, Invoker, InvokerControl, InvokerMachine}; use core::convert::Infallible; struct Substack { @@ -64,8 +64,8 @@ where pub fn step( &mut self, ) -> Result<(), Capture, I::Interrupt>> { - self.step_with(|invoker, machine, handler| { - let result = invoker.step_machine(machine, handler); + self.step_with(|machine, handler| { + let result = machine.step(handler); match result { Ok(()) => LastSubstackStatus::Running, Err(result) => LastSubstackStatus::Exited(result), @@ -76,8 +76,8 @@ where pub fn step_run( &mut self, ) -> Result<(), Capture, I::Interrupt>> { - self.step_with(|invoker, machine, handler| { - let result = invoker.run_machine(machine, handler); + self.step_with(|machine, handler| { + let result = machine.run(handler); LastSubstackStatus::Exited(result) }) } @@ -87,7 +87,7 @@ where fs: FS, ) -> Result<(), Capture, I::Interrupt>> where - FS: Fn(&I, &mut I::Machine, &mut H) -> LastSubstackStatus, + FS: Fn(&mut I::Machine, &mut H) -> LastSubstackStatus, { let mut step_ret = None; @@ -107,7 +107,7 @@ where status: LastSubstackStatus::Running, mut machine, }) => { - let status = fs(self.invoker, &mut machine, self.backend); + let status = fs(&mut machine, self.backend); Some(LastSubstack { status, machine }) } Some(LastSubstack { @@ -123,7 +123,7 @@ where .pop() .expect("checked stack is not empty above; qed"); - let machine = self.invoker.deconstruct_machine(machine); + let machine = machine.deconstruct(); let feedback_result = self.invoker.exit_substack( exit, machine, @@ -221,7 +221,7 @@ fn execute( where I: Invoker, { - let mut result = invoker.run_machine(&mut machine, backend); + let mut result = machine.run(backend); loop { match result { @@ -245,13 +245,13 @@ where match invoker.exit_substack( sub_result, - invoker.deconstruct_machine(sub_machine), + sub_machine.deconstruct(), trap_data, &mut machine, backend, ) { Ok(()) => { - result = invoker.run_machine(&mut machine, backend); + result = machine.run(backend); } Err(err) => return Ok((Err(err), machine)), } @@ -268,7 +268,7 @@ where backend, ) { Ok(()) => { - result = invoker.run_machine(&mut machine, backend); + result = machine.run(backend); } Err(err) => return Ok((Err(err), machine)), } @@ -334,7 +334,7 @@ where Err(Capture::Trap(interrupt)) => Err(Capture::Trap(interrupt)), Err(Capture::Exit(Err(fatal))) => Err(Capture::Exit(Err(fatal.into()))), Err(Capture::Exit(Ok((ret, machine)))) => { - let machine = call_stack.invoker.deconstruct_machine(machine); + let machine = machine.deconstruct(); Err(Capture::Exit(call_stack.invoker.finalize_transact( &transact_invoke, ret, @@ -432,8 +432,7 @@ where if let Some(mut last) = call_stack.last.take() { loop { if let Some(mut parent) = call_stack.stack.pop() { - let last_machine = - call_stack.invoker.deconstruct_machine(last.machine); + let last_machine = last.machine.deconstruct(); let _ = call_stack.invoker.exit_substack( ExitFatal::Unfinished.into(), last_machine, @@ -453,7 +452,7 @@ where } } - let last_machine = call_stack.invoker.deconstruct_machine(last.machine); + let last_machine = last.machine.deconstruct(); let _ = call_stack.invoker.finalize_transact( &transact_invoke, ExitFatal::Unfinished.into(), @@ -482,7 +481,7 @@ where match control { InvokerControl::Enter(machine) => { let (ret, machine) = execute(machine, 0, heap_depth, backend, invoker)?; - let machine = invoker.deconstruct_machine(machine); + let machine = machine.deconstruct(); invoker.finalize_transact(&transact_invoke, ret, machine, backend) } InvokerControl::DirectExit((exit, machine)) => { diff --git a/src/color.rs b/src/color.rs new file mode 100644 index 000000000..64206d599 --- /dev/null +++ b/src/color.rs @@ -0,0 +1,101 @@ +use crate::{ + Capture, Control, Etable, ExitResult, Gasometer, InvokerMachine, Machine, Opcode, RuntimeState, +}; + +pub struct ColoredMachine { + pub machine: Machine, + pub gasometer: G, + pub is_static: bool, + pub color: C, +} + +impl InvokerMachine for ColoredMachine +where + C: Color, +{ + type Deconstruct = (S, G, Vec); + + fn step(&mut self, handler: &mut H) -> Result<(), Capture> { + self.color.step( + &mut self.machine, + &mut self.gasometer, + self.is_static, + handler, + ) + } + + fn run(&mut self, handler: &mut H) -> Capture { + self.color.run( + &mut self.machine, + &mut self.gasometer, + self.is_static, + handler, + ) + } + + fn deconstruct(self) -> Self::Deconstruct { + (self.machine.state, self.gasometer, self.machine.retval) + } +} + +pub trait Color { + fn step( + &self, + machine: &mut Machine, + gasometer: &mut G, + is_static: bool, + handler: &mut H, + ) -> Result<(), Capture>; + + fn run( + &self, + machine: &mut Machine, + gasometer: &mut G, + is_static: bool, + handler: &mut H, + ) -> Capture; +} + +impl<'etable, S, G, H, Tr, F> Color for &'etable Etable +where + S: AsMut, + G: Gasometer, + F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, +{ + fn step( + &self, + machine: &mut Machine, + gasometer: &mut G, + is_static: bool, + handler: &mut H, + ) -> Result<(), Capture> { + match gasometer.record_step(&machine, is_static, handler) { + Ok(()) => { + machine.state.as_mut().gas = gasometer.gas().into(); + machine.step(handler, self) + } + Err(e) => return Err(Capture::Exit(Err(e))), + } + } + + fn run( + &self, + machine: &mut Machine, + gasometer: &mut G, + is_static: bool, + handler: &mut H, + ) -> Capture { + loop { + match gasometer.record_stepn(&machine, is_static, handler) { + Ok(stepn) => { + machine.state.as_mut().gas = gasometer.gas().into(); + match machine.stepn(stepn, handler, self) { + Ok(()) => (), + Err(c) => return c, + } + } + Err(e) => return Capture::Exit(Err(e)), + } + } + } +} diff --git a/src/gasometer.rs b/src/gasometer.rs index d9fed7736..95f7fe6f7 100644 --- a/src/gasometer.rs +++ b/src/gasometer.rs @@ -1,6 +1,6 @@ //! EVM gasometer. -use crate::{Capture, Control, Etable, ExitError, ExitResult, Machine, Opcode, RuntimeState}; +use crate::{ExitError, Machine}; use core::ops::{Add, AddAssign, Sub, SubAssign}; use primitive_types::U256; @@ -40,58 +40,3 @@ pub trait Gasometer: StaticGasometer { Ok(1) } } - -pub struct GasedMachine { - pub machine: Machine, - pub gasometer: G, - pub is_static: bool, -} - -impl, G> GasedMachine { - pub fn step( - &mut self, - handler: &mut H, - etable: &Etable, - ) -> Result<(), Capture> - where - F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, - G: Gasometer, - { - match self - .gasometer - .record_step(&self.machine, self.is_static, handler) - { - Ok(()) => { - self.machine.state.as_mut().gas = self.gasometer.gas().into(); - self.machine.step(handler, etable) - } - Err(e) => return Err(Capture::Exit(Err(e))), - } - } - - pub fn run( - &mut self, - handler: &mut H, - etable: &Etable, - ) -> Capture - where - F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, - G: Gasometer, - { - loop { - match self - .gasometer - .record_stepn(&self.machine, self.is_static, handler) - { - Ok(stepn) => { - self.machine.state.as_mut().gas = self.gasometer.gas().into(); - match self.machine.stepn(stepn, handler, etable) { - Ok(()) => (), - Err(c) => return c, - } - } - Err(e) => return Capture::Exit(Err(e)), - } - } - } -} diff --git a/src/invoker.rs b/src/invoker.rs index d73ad39d7..e2bde3a03 100644 --- a/src/invoker.rs +++ b/src/invoker.rs @@ -5,9 +5,16 @@ pub enum InvokerControl { DirectExit(VD), } +pub trait InvokerMachine { + type Deconstruct; + + fn step(&mut self, handler: &mut H) -> Result<(), Capture>; + fn run(&mut self, handler: &mut H) -> Capture; + fn deconstruct(self) -> Self::Deconstruct; +} + pub trait Invoker { - type Machine; - type MachineDeconstruct; + type Machine: InvokerMachine; type Interrupt; type TransactArgs; @@ -15,14 +22,6 @@ pub trait Invoker { type TransactValue; type SubstackInvoke; - fn run_machine(&self, machine: &mut Self::Machine, handler: &mut H) -> Capture; - fn step_machine( - &self, - machine: &mut Self::Machine, - handler: &mut H, - ) -> Result<(), Capture>; - fn deconstruct_machine(&self, machine: Self::Machine) -> Self::MachineDeconstruct; - fn new_transact( &self, args: Self::TransactArgs, @@ -30,7 +29,13 @@ pub trait Invoker { ) -> Result< ( Self::TransactInvoke, - InvokerControl, + InvokerControl< + Self::Machine, + ( + ExitResult, + >::Deconstruct, + ), + >, ), ExitError, >; @@ -38,7 +43,7 @@ pub trait Invoker { &self, invoke: &Self::TransactInvoke, exit: ExitResult, - machine: Self::MachineDeconstruct, + machine: >::Deconstruct, handler: &mut H, ) -> Result; @@ -52,7 +57,13 @@ pub trait Invoker { Result< ( Self::SubstackInvoke, - InvokerControl, + InvokerControl< + Self::Machine, + ( + ExitResult, + >::Deconstruct, + ), + >, ), ExitError, >, @@ -61,7 +72,7 @@ pub trait Invoker { fn exit_substack( &self, result: ExitResult, - child: Self::MachineDeconstruct, + child: >::Deconstruct, trap_data: Self::SubstackInvoke, parent: &mut Self::Machine, handler: &mut H, diff --git a/src/lib.rs b/src/lib.rs index 8321ebf20..9a761b6bc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ pub mod backend; pub mod standard; mod call_stack; +mod color; mod gasometer; mod invoker; @@ -17,8 +18,9 @@ pub use evm_interpreter::*; pub use crate::backend::TransactionalBackend; pub use crate::call_stack::{transact, HeapTransact}; -pub use crate::gasometer::{Gas, GasedMachine, Gasometer, StaticGasometer}; -pub use crate::invoker::{Invoker, InvokerControl}; +pub use crate::color::{Color, ColoredMachine}; +pub use crate::gasometer::{Gas, Gasometer, StaticGasometer}; +pub use crate::invoker::{Invoker, InvokerControl, InvokerMachine}; #[derive(Clone, Debug, Copy)] pub enum MergeStrategy { diff --git a/src/standard/invoker/mod.rs b/src/standard/invoker/mod.rs index 08a75a16e..7afceca52 100644 --- a/src/standard/invoker/mod.rs +++ b/src/standard/invoker/mod.rs @@ -1,12 +1,15 @@ +mod resolver; mod routines; +pub use resolver::{EtableResolver, PrecompileSet, Resolver}; + use super::{Config, MergeableRuntimeState, TransactGasometer}; use crate::call_create::{CallCreateTrapData, CallTrapData, CreateScheme, CreateTrapData}; use crate::{ - Capture, Context, Control, Etable, ExitError, ExitException, ExitResult, ExitSucceed, - GasedMachine, Gasometer as GasometerT, Invoker as InvokerT, InvokerControl, Machine, - MergeStrategy, Opcode, RuntimeBackend, RuntimeEnvironment, RuntimeState, TransactionContext, - TransactionalBackend, Transfer, + Capture, ColoredMachine, Context, ExitError, ExitException, ExitResult, ExitSucceed, + Gasometer as GasometerT, Invoker as InvokerT, InvokerControl, MergeStrategy, Opcode, + RuntimeBackend, RuntimeEnvironment, RuntimeState, TransactionContext, TransactionalBackend, + Transfer, }; use alloc::rc::Rc; use core::cmp::min; @@ -100,123 +103,38 @@ impl TransactArgs { } } -pub enum ResolvedCode
 {
-	Normal(Vec),
-	Precompile(Pre),
-}
-
-pub trait Precompile {
-	fn execute(
-		&self,
-		input: &[u8],
-		state: S,
-		gasometer: G,
-		handler: &mut H,
-	) -> (ExitResult, (S, G, Vec));
-}
-
-impl Precompile for Infallible {
-	fn execute(
-		&self,
-		_input: &[u8],
-		_state: S,
-		_gasometer: G,
-		_handler: &mut H,
-	) -> (ExitResult, (S, G, Vec)) {
-		match *self {}
-	}
-}
-
-pub trait CodeResolver {
-	type Precompile: Precompile;
-
-	fn resolve(
-		&self,
-		address: H160,
-		gasometer: &mut G,
-		handler: &mut H,
-	) -> Result, ExitError>;
-}
-
-impl CodeResolver for () {
-	type Precompile = Infallible;
-
-	fn resolve(
-		&self,
-		address: H160,
-		_gasometer: &mut G,
-		handler: &mut H,
-	) -> Result, ExitError> {
-		Ok(ResolvedCode::Normal(handler.code(address)))
-	}
-}
-
-pub struct Invoker<'config, 'precompile, 'etable, S, G, H, Pre, Tr, F> {
+pub struct Invoker<'config, 'resolver, S, G, H, R, Tr> {
 	config: &'config Config,
-	etable: &'etable Etable,
-	resolver: &'precompile Pre,
-	_marker: PhantomData,
+	resolver: &'resolver R,
+	_marker: PhantomData<(S, G, H, Tr)>,
 }
 
-impl<'config, 'precompile, 'etable, S, G, H, Pre, Tr, F>
-	Invoker<'config, 'precompile, 'etable, S, G, H, Pre, Tr, F>
-{
-	pub fn new(
-		config: &'config Config,
-		resolver: &'precompile Pre,
-		etable: &'etable Etable,
-	) -> Self {
+impl<'config, 'resolver, S, G, H, R, Tr> Invoker<'config, 'resolver, S, G, H, R, Tr> {
+	pub fn new(config: &'config Config, resolver: &'resolver R) -> Self {
 		Self {
 			config,
-			etable,
 			resolver,
 			_marker: PhantomData,
 		}
 	}
 }
 
-impl<'config, 'precompile, 'etable, S, G, H, Pre, Tr, F> InvokerT
-	for Invoker<'config, 'precompile, 'etable, S, G, H, Pre, Tr, F>
+impl<'config, 'resolver, S, G, H, R, Tr> InvokerT
+	for Invoker<'config, 'resolver, S, G, H, R, Tr>
 where
-	S: MergeableRuntimeState>,
+	S: MergeableRuntimeState>,
 	G: GasometerT + TransactGasometer<'config, S>,
 	H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend,
-	Pre: CodeResolver,
+	R: Resolver,
 	Tr: IntoCallCreateTrap,
-	F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control,
 {
-	type Machine = GasedMachine;
-	type MachineDeconstruct = (S, G, Vec);
+	type Machine = ColoredMachine;
 	type Interrupt = Tr::Interrupt;
 	type TransactArgs = TransactArgs;
 	type TransactInvoke = TransactInvoke;
 	type TransactValue = (ExitSucceed, Option);
 	type SubstackInvoke = SubstackInvoke;
 
-	fn run_machine(
-		&self,
-		machine: &mut GasedMachine,
-		handler: &mut H,
-	) -> Capture {
-		machine.run(handler, self.etable)
-	}
-
-	fn step_machine(
-		&self,
-		machine: &mut GasedMachine,
-		handler: &mut H,
-	) -> Result<(), Capture> {
-		machine.step(handler, self.etable)
-	}
-
-	fn deconstruct_machine(&self, machine: GasedMachine) -> (S, G, Vec) {
-		(
-			machine.machine.state,
-			machine.gasometer,
-			machine.machine.retval,
-		)
-	}
-
 	fn new_transact(
 		&self,
 		args: TransactArgs,
@@ -224,7 +142,7 @@ where
 	) -> Result<
 		(
 			TransactInvoke,
-			InvokerControl, (ExitResult, Self::MachineDeconstruct)>,
+			InvokerControl, (ExitResult, (S, G, Vec))>,
 		),
 		ExitError,
 	> {
@@ -304,13 +222,13 @@ where
 						}
 					}
 
-					let mut gasometer =
+					let gasometer =
 						G::new_transact_call(gas_limit, &data, &access_list, self.config)?;
-					let code = self.resolver.resolve(address, &mut gasometer, handler)?;
 
-					let mut machine = routines::make_enter_call_machine(
+					let machine = routines::make_enter_call_machine(
 						self.config,
-						code,
+						self.resolver,
+						address,
 						data,
 						false, // is_static
 						Some(transfer),
@@ -323,7 +241,6 @@ where
 						gasometer,
 						handler,
 					)?;
-					routines::maybe_analyse_code(&mut machine);
 
 					if self.config.increase_state_access_gas {
 						if self.config.warm_coinbase_address {
@@ -346,8 +263,9 @@ where
 					let gasometer =
 						G::new_transact_create(gas_limit, &init_code, &access_list, self.config)?;
 
-					let mut machine = routines::make_enter_create_machine(
+					let machine = routines::make_enter_create_machine(
 						self.config,
+						self.resolver,
 						caller,
 						init_code,
 						false, // is_static
@@ -361,7 +279,6 @@ where
 						gasometer,
 						handler,
 					)?;
-					routines::maybe_analyse_code(&mut machine);
 
 					Ok((invoke, machine))
 				}
@@ -431,14 +348,14 @@ where
 	fn enter_substack(
 		&self,
 		trap: Tr,
-		machine: &mut GasedMachine,
+		machine: &mut ColoredMachine,
 		handler: &mut H,
 		depth: usize,
 	) -> Capture<
 		Result<
 			(
 				SubstackInvoke,
-				InvokerControl, (ExitResult, Self::MachineDeconstruct)>,
+				InvokerControl, (ExitResult, (S, G, Vec))>,
 			),
 			ExitError,
 		>,
@@ -488,18 +405,10 @@ where
 
 		match trap_data {
 			CallCreateTrapData::Call(call_trap_data) => {
-				let mut submeter = match machine.gasometer.submeter(gas_limit, call_has_value) {
+				let submeter = match machine.gasometer.submeter(gas_limit, call_has_value) {
 					Ok(submeter) => submeter,
 					Err(err) => return Capture::Exit(Err(err)),
 				};
-				let code =
-					match self
-						.resolver
-						.resolve(call_trap_data.target, &mut submeter, handler)
-					{
-						Ok(code) => code,
-						Err(err) => return Capture::Exit(Err(err)),
-					};
 
 				let substate = machine.machine.state.substate(
 					RuntimeState {
@@ -511,10 +420,13 @@ where
 					&machine,
 				);
 
+				let target = call_trap_data.target;
+
 				Capture::Exit(routines::enter_call_substack(
 					self.config,
-					code,
+					self.resolver,
 					call_trap_data,
+					target,
 					is_static,
 					substate,
 					submeter,
@@ -546,6 +458,7 @@ where
 
 				Capture::Exit(routines::enter_create_substack(
 					self.config,
+					self.resolver,
 					code,
 					create_trap_data,
 					is_static,
@@ -562,7 +475,7 @@ where
 		result: ExitResult,
 		(substate, submeter, retval): (S, G, Vec),
 		trap_data: SubstackInvoke,
-		parent: &mut GasedMachine,
+		parent: &mut ColoredMachine,
 		handler: &mut H,
 	) -> Result<(), ExitError> {
 		let strategy = match &result {
diff --git a/src/standard/invoker/resolver.rs b/src/standard/invoker/resolver.rs
new file mode 100644
index 000000000..88c4aa24c
--- /dev/null
+++ b/src/standard/invoker/resolver.rs
@@ -0,0 +1,177 @@
+use super::routines;
+use crate::standard::{Config, TransactGasometer};
+use crate::{
+	Color, ColoredMachine, Control, Etable, ExitError, ExitResult, Gasometer, InvokerControl,
+	Machine, Opcode, RuntimeBackend, RuntimeState,
+};
+use alloc::rc::Rc;
+use primitive_types::H160;
+
+pub trait Resolver {
+	type Color: Color;
+
+	fn resolve_call(
+		&self,
+		code_address: H160,
+		input: Vec,
+		is_static: bool,
+		state: S,
+		gasometer: G,
+		handler: &mut H,
+	) -> Result<
+		InvokerControl, (ExitResult, (S, G, Vec))>,
+		ExitError,
+	>;
+
+	fn resolve_create(
+		&self,
+		init_code: Vec,
+		is_static: bool,
+		state: S,
+		gasometer: G,
+		handler: &mut H,
+	) -> Result<
+		InvokerControl, (ExitResult, (S, G, Vec))>,
+		ExitError,
+	>;
+}
+
+pub trait PrecompileSet {
+	fn execute(
+		&self,
+		code_address: H160,
+		input: &[u8],
+		is_static: bool,
+		state: &mut S,
+		gasometer: &mut G,
+		handler: &mut H,
+	) -> Option<(ExitResult, Vec)>;
+}
+
+impl PrecompileSet for () {
+	fn execute(
+		&self,
+		_code_address: H160,
+		_input: &[u8],
+		_is_static: bool,
+		_state: &mut S,
+		_gasometer: &mut G,
+		_handler: &mut H,
+	) -> Option<(ExitResult, Vec)> {
+		None
+	}
+}
+
+pub struct EtableResolver<'config, 'precompile, 'etable, S, H, Pre, Tr, F> {
+	config: &'config Config,
+	etable: &'etable Etable,
+	precompiles: &'precompile Pre,
+}
+
+impl<'config, 'precompile, 'etable, S, H, Pre, Tr, F>
+	EtableResolver<'config, 'precompile, 'etable, S, H, Pre, Tr, F>
+{
+	pub fn new(
+		config: &'config Config,
+		precompiles: &'precompile Pre,
+		etable: &'etable Etable,
+	) -> Self {
+		Self {
+			config,
+			precompiles,
+			etable,
+		}
+	}
+}
+
+impl<'config, 'precompile, 'etable, S, G, H, Pre, Tr, F> Resolver
+	for EtableResolver<'config, 'precompile, 'etable, S, H, Pre, Tr, F>
+where
+	S: AsRef + AsMut,
+	G: Gasometer + TransactGasometer<'config, S>,
+	F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control,
+	H: RuntimeBackend,
+	Pre: PrecompileSet,
+{
+	type Color = &'etable Etable;
+
+	fn resolve_call(
+		&self,
+		code_address: H160,
+		input: Vec,
+		is_static: bool,
+		mut state: S,
+		mut gasometer: G,
+		handler: &mut H,
+	) -> Result<
+		InvokerControl<
+			ColoredMachine>,
+			(ExitResult, (S, G, Vec)),
+		>,
+		ExitError,
+	> {
+		if let Some((r, retval)) = self.precompiles.execute(
+			code_address,
+			&input,
+			is_static,
+			&mut state,
+			&mut gasometer,
+			handler,
+		) {
+			return Ok(InvokerControl::DirectExit((r, (state, gasometer, retval))));
+		}
+
+		let code = handler.code(code_address);
+
+		let machine = Machine::::new(
+			Rc::new(code),
+			Rc::new(input),
+			self.config.stack_limit,
+			self.config.memory_limit,
+			state,
+		);
+
+		let mut ret = InvokerControl::Enter(ColoredMachine {
+			machine,
+			gasometer,
+			is_static,
+			color: self.etable,
+		});
+		routines::maybe_analyse_code(&mut ret);
+
+		Ok(ret)
+	}
+
+	fn resolve_create(
+		&self,
+		init_code: Vec,
+		is_static: bool,
+		state: S,
+		gasometer: G,
+		_handler: &mut H,
+	) -> Result<
+		InvokerControl<
+			ColoredMachine>,
+			(ExitResult, (S, G, Vec)),
+		>,
+		ExitError,
+	> {
+		let machine = Machine::new(
+			Rc::new(init_code),
+			Rc::new(Vec::new()),
+			self.config.stack_limit,
+			self.config.memory_limit,
+			state,
+		);
+
+		let mut ret = InvokerControl::Enter(ColoredMachine {
+			machine,
+			gasometer,
+			is_static,
+			color: self.etable,
+		});
+		routines::maybe_analyse_code(&mut ret);
+
+		Ok(ret)
+	}
+}
diff --git a/src/standard/invoker/routines.rs b/src/standard/invoker/routines.rs
index 4cf6c5767..432c1beeb 100644
--- a/src/standard/invoker/routines.rs
+++ b/src/standard/invoker/routines.rs
@@ -1,38 +1,36 @@
-use super::{
-	CallTrapData, CreateTrapData, Precompile, ResolvedCode, SubstackInvoke, TransactGasometer,
-};
+use super::{CallTrapData, CreateTrapData, Resolver, SubstackInvoke, TransactGasometer};
 use crate::standard::Config;
 use crate::{
-	ExitError, ExitException, ExitResult, GasedMachine, Gasometer as GasometerT, InvokerControl,
-	Machine, MergeStrategy, Opcode, RuntimeBackend, RuntimeEnvironment, RuntimeState,
-	StaticGasometer, TransactionalBackend, Transfer,
+	ColoredMachine, ExitError, ExitException, ExitResult, Gasometer as GasometerT, InvokerControl,
+	MergeStrategy, Opcode, RuntimeBackend, RuntimeEnvironment, RuntimeState, StaticGasometer,
+	TransactionalBackend, Transfer,
 };
-use alloc::rc::Rc;
 use primitive_types::{H160, U256};
 
-pub fn maybe_analyse_code<'config, S: AsRef, G: TransactGasometer<'config, S>>(
-	result: &mut InvokerControl, (ExitResult, (S, G, Vec))>,
+pub fn maybe_analyse_code<'config, S: AsRef, G: TransactGasometer<'config, S>, C>(
+	result: &mut InvokerControl, (ExitResult, (S, G, Vec))>,
 ) {
 	if let InvokerControl::Enter(machine) = result {
 		machine.gasometer.analyse_code(&machine.machine.code())
 	}
 }
 
-pub fn make_enter_call_machine<'config, 'precompile, S, G, H, P>(
-	config: &'config Config,
-	code: ResolvedCode

, +pub fn make_enter_call_machine<'config, 'resolver, S, G, H, R, Tr>( + _config: &'config Config, + resolver: &'resolver R, + code_address: H160, input: Vec, is_static: bool, transfer: Option, state: S, gasometer: G, handler: &mut H, -) -> Result, (ExitResult, (S, G, Vec))>, ExitError> +) -> Result, (ExitResult, (S, G, Vec))>, ExitError> where S: AsRef, G: GasometerT, H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, - P: Precompile, + R: Resolver, { handler.mark_hot(state.as_ref().context.address, None); @@ -40,30 +38,12 @@ where handler.transfer(transfer)?; } - match code { - ResolvedCode::Normal(code) => { - let machine = Machine::::new( - Rc::new(code), - Rc::new(input), - config.stack_limit, - config.memory_limit, - state, - ); - - Ok(InvokerControl::Enter(GasedMachine { - machine, - gasometer, - is_static, - })) - } - ResolvedCode::Precompile(precompile) => Ok(InvokerControl::DirectExit( - precompile.execute(&input, state, gasometer, handler), - )), - } + resolver.resolve_call(code_address, input, is_static, state, gasometer, handler) } -pub fn make_enter_create_machine<'config, S, G, H>( +pub fn make_enter_create_machine<'config, 'resolver, S, G, H, R, Tr>( config: &'config Config, + resolver: &'resolver R, caller: H160, init_code: Vec, is_static: bool, @@ -71,11 +51,12 @@ pub fn make_enter_create_machine<'config, S, G, H>( state: S, gasometer: G, handler: &mut H, -) -> Result, (ExitResult, (S, G, Vec))>, ExitError> +) -> Result, (ExitResult, (S, G, Vec))>, ExitError> where S: AsRef, G: GasometerT, H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, + R: Resolver, { if let Some(limit) = config.max_initcode_size { if init_code.len() > limit { @@ -100,25 +81,14 @@ where handler.reset_storage(state.as_ref().context.address); - let machine = Machine::new( - Rc::new(init_code), - Rc::new(Vec::new()), - config.stack_limit, - config.memory_limit, - state, - ); - - Ok(InvokerControl::Enter(GasedMachine { - machine, - gasometer, - is_static, - })) + resolver.resolve_create(init_code, is_static, state, gasometer, handler) } -pub fn enter_call_substack<'config, 'precompile, S, G, H, P>( +pub fn enter_call_substack<'config, 'resolver, S, G, H, R, Tr>( config: &'config Config, - code: ResolvedCode

, + resolver: &'resolver R, trap_data: CallTrapData, + code_address: H160, is_static: bool, state: S, gasometer: G, @@ -126,7 +96,7 @@ pub fn enter_call_substack<'config, 'precompile, S, G, H, P>( ) -> Result< ( SubstackInvoke, - InvokerControl, (ExitResult, (S, G, Vec))>, + InvokerControl, (ExitResult, (S, G, Vec))>, ), ExitError, > @@ -134,14 +104,15 @@ where S: AsRef, G: GasometerT + TransactGasometer<'config, S>, H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, - P: Precompile, + R: Resolver, { handler.push_substate(); let work = || -> Result<(SubstackInvoke, _), ExitError> { - let mut machine = make_enter_call_machine( + let machine = make_enter_call_machine( config, - code, + resolver, + code_address, trap_data.input.clone(), is_static, trap_data.transfer.clone(), @@ -149,7 +120,6 @@ where gasometer, handler, )?; - maybe_analyse_code(&mut machine); Ok((SubstackInvoke::Call { trap: trap_data }, machine)) }; @@ -163,8 +133,9 @@ where } } -pub fn enter_create_substack<'config, S, G, H>( +pub fn enter_create_substack<'config, 'resolver, S, G, H, R, Tr>( config: &'config Config, + resolver: &'resolver R, code: Vec, trap_data: CreateTrapData, is_static: bool, @@ -174,7 +145,7 @@ pub fn enter_create_substack<'config, S, G, H>( ) -> Result< ( SubstackInvoke, - InvokerControl, (ExitResult, (S, G, Vec))>, + InvokerControl, (ExitResult, (S, G, Vec))>, ), ExitError, > @@ -182,10 +153,11 @@ where S: AsRef, G: GasometerT + TransactGasometer<'config, S>, H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, + R: Resolver, { handler.push_substate(); - let work = || -> Result<(SubstackInvoke, InvokerControl, (ExitResult, (S, G, Vec))>), ExitError> { + let work = || -> Result<(SubstackInvoke, InvokerControl, (ExitResult, (S, G, Vec))>), ExitError> { let CreateTrapData { scheme, value, @@ -201,10 +173,9 @@ where value, }; - let mut machine = make_enter_create_machine( - config, caller, code, is_static, transfer, state, gasometer, handler, + let machine = make_enter_create_machine( + config, resolver, caller, code, is_static, transfer, state, gasometer, handler, )?; - maybe_analyse_code(&mut machine); Ok(( SubstackInvoke::Create { diff --git a/src/standard/mod.rs b/src/standard/mod.rs index 3fecb7d72..54496fede 100644 --- a/src/standard/mod.rs +++ b/src/standard/mod.rs @@ -4,12 +4,13 @@ mod invoker; pub use self::config::Config; pub use self::gasometer::{Gasometer, TransactGasometer}; -pub use self::invoker::{CodeResolver, Invoker, Precompile, ResolvedCode, TransactArgs}; +pub use self::invoker::{EtableResolver, Invoker, PrecompileSet, Resolver, TransactArgs}; pub type Machine = crate::Machine; pub type Efn = crate::Efn; pub type Etable> = crate::Etable; -pub type GasedMachine = crate::GasedMachine; +pub type ColoredMachine<'etable, G, H, F = Efn> = + crate::ColoredMachine>; pub trait MergeableRuntimeState: AsRef + AsMut