diff --git a/interpreter/src/error.rs b/interpreter/src/error.rs index 58e1baf03..cf4db0152 100644 --- a/interpreter/src/error.rs +++ b/interpreter/src/error.rs @@ -185,6 +185,10 @@ pub enum ExitFatal { UnhandledInterrupt, /// The environment explicitly set call errors as fatal error. ExceptionAsFatal(ExitException), + /// Already exited. + AlreadyExited, + /// Unfinished execution. + Unfinished, /// Other fatal errors. Other(Cow<'static, str>), diff --git a/interpreter/src/lib.rs b/interpreter/src/lib.rs index dab5971d1..cc35cf8e8 100644 --- a/interpreter/src/lib.rs +++ b/interpreter/src/lib.rs @@ -154,13 +154,13 @@ impl Machine { { let position = self.position; if position >= self.code.len() { - return Err(Capture::Exit(ExitSucceed::Stopped.into())); + return Err(Capture::Exit(ExitFatal::AlreadyExited.into())); } let opcode = Opcode(self.code[position]); let control = etable[opcode.as_usize()](self, handle, opcode, self.position); - match control { + let mut ret = match control { Control::Continue => { self.position += 1; Ok(()) @@ -181,7 +181,13 @@ impl Machine { self.position = position + 1; Err(Capture::Trap(opcode)) } + }; + + if position >= self.code.len() { + ret = Err(Capture::Exit(ExitSucceed::Stopped.into())); } + + ret } /// Pick the next opcode. diff --git a/jsontests/src/run.rs b/jsontests/src/run.rs index 4a84f47dd..ac6a591f1 100644 --- a/jsontests/src/run.rs +++ b/jsontests/src/run.rs @@ -3,8 +3,9 @@ use crate::types::*; use evm::backend::in_memory::{ InMemoryAccount, InMemoryBackend, InMemoryEnvironment, InMemoryLayer, }; -use evm::standard::{Config, Etable, Gasometer, Invoker}; +use evm::standard::{Config, Etable, Gasometer, Invoker, TransactArgs}; use evm::utils::u256_to_h256; +use evm::RuntimeState; use primitive_types::U256; use std::collections::{BTreeMap, BTreeSet}; @@ -62,15 +63,19 @@ pub fn run_test(_filename: &str, _test_name: &str, test: Test) -> Result<(), Err let etable = Etable::runtime(); let invoker = Invoker::new(&config); - let _result = invoker.transact_call::( - test.transaction.sender, - test.transaction.to, - test.transaction.value, - test.transaction.data, - test.transaction.gas_limit, - test.transaction.gas_price, - Vec::new(), + let _result = evm::transact::( + TransactArgs::Call { + caller: test.transaction.sender, + address: test.transaction.to, + value: test.transaction.value, + data: test.transaction.data, + gas_limit: test.transaction.gas_limit, + gas_price: test.transaction.gas_price, + access_list: Vec::new(), + }, + Some(4), &mut backend, + &invoker, &etable, ); diff --git a/src/backend/in_memory.rs b/src/backend/in_memory.rs index 981b6848e..535b7171c 100644 --- a/src/backend/in_memory.rs +++ b/src/backend/in_memory.rs @@ -1,6 +1,6 @@ use crate::{ - ExitError, ExitException, Log, RuntimeBackend, RuntimeBaseBackend, RuntimeEnvironment, - TransactionalBackend, TransactionalMergeStrategy, + ExitError, ExitException, Log, MergeStrategy, RuntimeBackend, RuntimeBaseBackend, + RuntimeEnvironment, TransactionalBackend, }; use alloc::collections::{BTreeMap, BTreeSet}; use primitive_types::{H160, H256, U256}; @@ -249,14 +249,14 @@ impl TransactionalBackend for InMemoryBackend { self.layers.push(layer); } - fn pop_substate(&mut self, strategy: TransactionalMergeStrategy) { + fn pop_substate(&mut self, strategy: MergeStrategy) { let layer = self.layers.pop().expect("current layer exist"); match strategy { - TransactionalMergeStrategy::Commit => { + MergeStrategy::Commit => { *self.current_layer_mut() = layer; } - TransactionalMergeStrategy::Discard => (), + MergeStrategy::Discard | MergeStrategy::Revert => (), } } } diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 359a16370..900fa7b5f 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -1,11 +1,6 @@ pub mod in_memory; -pub enum TransactionalMergeStrategy { - Commit, - Discard, -} - pub trait TransactionalBackend { fn push_substate(&mut self); - fn pop_substate(&mut self, strategy: TransactionalMergeStrategy); + fn pop_substate(&mut self, strategy: crate::MergeStrategy); } diff --git a/src/call_stack.rs b/src/call_stack.rs index de1103a74..a03f5e46e 100644 --- a/src/call_stack.rs +++ b/src/call_stack.rs @@ -1,30 +1,30 @@ use crate::{ - Capture, Control, Etable, ExitError, ExitResult, GasedMachine, Gasometer, Invoker, Machine, - Opcode, RuntimeState, + Capture, Control, Etable, ExitError, ExitFatal, ExitResult, GasedMachine, Gasometer, Invoker, + Machine, Opcode, RuntimeState, }; use core::convert::Infallible; -struct TrappedCallStackData { - trap_data: TrD, +struct Substack { + invoke: TrD, machine: GasedMachine, } -enum LastCallStackData { - Running { - machine: GasedMachine, - }, - Exited { - result: Capture, - machine: GasedMachine, - }, - ExternalTrapped { - machine: GasedMachine, - }, +struct LastSubstack { + machine: GasedMachine, + status: LastSubstackStatus, } -pub struct CallStack<'backend, 'invoker, S, G, H, Tr, I: Invoker> { - stack: Vec>, - last: LastCallStackData, +enum LastSubstackStatus { + Running, + ExternalTrapped, + Exited(Capture), +} + +// Note: this should not be exposed to public because it does not implement +// Drop. +struct CallStack<'backend, 'invoker, S, G, H, Tr, I: Invoker> { + stack: Vec>, + last: Option>, initial_depth: usize, backend: &'backend mut H, invoker: &'invoker I, @@ -38,15 +38,16 @@ where { pub fn new( machine: GasedMachine, - backend: &'backend mut H, initial_depth: usize, + backend: &'backend mut H, invoker: &'invoker I, ) -> Self { - let last = LastCallStackData::Running { machine }; - let call_stack = Self { stack: Vec::new(), - last, + last: Some(LastSubstack { + machine, + status: LastSubstackStatus::Running, + }), initial_depth, backend, invoker, @@ -55,145 +56,135 @@ where call_stack } - /// Calling `expect_exit` after `execute` returns `Capture::Exit` is safe. - pub fn expect_exit(self) -> (GasedMachine, ExitResult) { - match self.last { - LastCallStackData::Exited { - machine, - result: Capture::Exit(exit), - } => (machine, exit), - _ => panic!("expected exit"), - } - } - - pub fn execute( - machine: GasedMachine, - backend: &'backend mut H, - initial_depth: usize, - invoker: &'invoker I, + pub fn run( + &mut self, etable: &Etable, - ) -> (Self, Capture<(), I::Interrupt>) - where - F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, - { - let call_stack = Self::new(machine, backend, initial_depth, invoker); - - call_stack.run(etable) - } - - pub fn run(mut self, etable: &Etable) -> (Self, Capture<(), I::Interrupt>) + ) -> Capture), ExitFatal>, I::Interrupt> where F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, { loop { - let step_ret; - (self, step_ret) = self.step(etable); + let step_ret = self.step(etable); if let Some(step_ret) = step_ret { - return (self, step_ret); + return step_ret; } } } - fn step(mut self, etable: &Etable) -> (Self, Option>) + pub fn step( + &mut self, + etable: &Etable, + ) -> Option), ExitFatal>, I::Interrupt>> where F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, { - let mut step_ret: Option> = None; + let mut step_ret = None; - self.last = match self.last { - LastCallStackData::ExternalTrapped { machine } => { - LastCallStackData::Running { machine } + self.last = match self.last.take() { + None => { + step_ret = Some(Capture::Exit(Err(ExitFatal::AlreadyExited.into()))); + None } - LastCallStackData::Running { mut machine } => { + Some(LastSubstack { + status: LastSubstackStatus::ExternalTrapped, + machine, + }) => Some(LastSubstack { + status: LastSubstackStatus::Running, + machine, + }), + Some(LastSubstack { + status: LastSubstackStatus::Running, + mut machine, + }) => { let result = machine.run(self.backend, etable); - LastCallStackData::Exited { machine, result } + Some(LastSubstack { + status: LastSubstackStatus::Exited(result), + machine, + }) } - LastCallStackData::Exited { - mut machine, - result, - } => match result { - Capture::Exit(exit) => { - if self.stack.is_empty() { - step_ret = Some(Capture::Exit(())); + Some(LastSubstack { + status: LastSubstackStatus::Exited(Capture::Exit(exit)), + machine, + }) => { + if self.stack.is_empty() { + step_ret = Some(Capture::Exit(Ok((exit, machine)))); + None + } else { + let mut upward = self + .stack + .pop() + .expect("checked stack is not empty above; qed"); - LastCallStackData::Exited { - machine, - result: Capture::Exit(exit), - } - } else { - let mut upward = self - .stack - .pop() - .expect("checked stack is not empty above; qed"); + let feedback_result = self.invoker.exit_substack( + exit, + machine, + upward.invoke, + &mut upward.machine, + self.backend, + ); - let feedback_result = self.invoker.exit_trap_stack( - exit, + match feedback_result { + Ok(()) => Some(LastSubstack { + status: LastSubstackStatus::Running, + machine: upward.machine, + }), + Err(err) => Some(LastSubstack { + machine: upward.machine, + status: LastSubstackStatus::Exited(Capture::Exit(Err(err))), + }), + } + } + } + Some(LastSubstack { + status: LastSubstackStatus::Exited(Capture::Trap(trap)), + mut machine, + }) => { + match self.invoker.enter_substack( + trap, + &mut machine, + self.backend, + self.initial_depth + self.stack.len() + 1, + ) { + Capture::Exit(Ok((trap_data, sub_machine))) => { + self.stack.push(Substack { + invoke: trap_data, machine, - upward.trap_data, - &mut upward.machine, - self.backend, - ); + }); - match feedback_result { - Ok(()) => LastCallStackData::Running { - machine: upward.machine, - }, - Err(err) => LastCallStackData::Exited { - machine: upward.machine, - result: Capture::Exit(Err(err)), - }, - } + Some(LastSubstack { + status: LastSubstackStatus::Running, + machine: sub_machine, + }) } - } - Capture::Trap(trap) => { - match self.invoker.prepare_trap( - trap, - &mut machine, - self.backend, - self.initial_depth + self.stack.len() + 1, - ) { - Capture::Exit(Ok(trap_data)) => { - match self.invoker.enter_trap_stack(trap_data, self.backend) { - Ok((trap_data, sub_machine)) => { - self.stack.push(TrappedCallStackData { trap_data, machine }); + Capture::Exit(Err(err)) => Some(LastSubstack { + status: LastSubstackStatus::Exited(Capture::Exit(Err(err))), + machine, + }), + Capture::Trap(trap) => { + step_ret = Some(Capture::Trap(trap)); - LastCallStackData::Running { - machine: sub_machine, - } - } - Err(err) => LastCallStackData::Exited { - machine, - result: Capture::Exit(Err(err)), - }, - } - } - Capture::Exit(Err(err)) => LastCallStackData::Exited { + Some(LastSubstack { + status: LastSubstackStatus::ExternalTrapped, machine, - result: Capture::Exit(Err(err)), - }, - Capture::Trap(trap) => { - step_ret = Some(Capture::Trap(trap)); - - LastCallStackData::ExternalTrapped { machine } - } + }) } } - }, + } }; - (self, step_ret) + step_ret } } -pub fn execute( +fn execute( mut machine: GasedMachine, - backend: &mut H, initial_depth: usize, heap_depth: Option, + backend: &mut H, invoker: &I, etable: &Etable, -) -> (GasedMachine, ExitResult) +) -> Result<(ExitResult, GasedMachine), ExitFatal> where S: AsMut, G: Gasometer, @@ -204,63 +195,177 @@ where loop { match result { - Capture::Exit(exit) => return (machine, exit), + Capture::Exit(exit) => return Ok((exit, machine)), Capture::Trap(trap) => { - let prepared_trap_data: Capture< - Result, - Infallible, - > = invoker.prepare_trap(trap, &mut machine, backend, initial_depth + 1); - - match prepared_trap_data { - Capture::Exit(Ok(trap_data)) => { - match invoker.enter_trap_stack(trap_data, backend) { - Ok((trap_data, sub_machine)) => { - let (sub_machine, sub_result) = if heap_depth - .map(|hd| initial_depth + 1 >= hd) - .unwrap_or(false) - { - let (call_stack, _infallible) = CallStack::execute( - sub_machine, - backend, - initial_depth + 1, - invoker, - etable, - ); - - call_stack.expect_exit() - } else { - execute( - sub_machine, - backend, - initial_depth + 1, - heap_depth, - invoker, - etable, - ) - }; - - match invoker.exit_trap_stack( - sub_result, - sub_machine, - trap_data, - &mut machine, - backend, - ) { - Ok(()) => { - result = machine.run(backend, etable); - } - Err(err) => return (machine, Err(err)), - } + match invoker.enter_substack(trap, &mut machine, backend, initial_depth + 1) { + Capture::Exit(Ok((trap_data, sub_machine))) => { + let (sub_result, sub_machine) = if heap_depth + .map(|hd| initial_depth + 1 >= hd) + .unwrap_or(false) + { + match CallStack::new(sub_machine, initial_depth + 1, backend, invoker) + .run(etable) + { + Capture::Exit(v) => v?, + Capture::Trap(infallible) => match infallible {}, } - Err(err) => { - return (machine, Err(err)); + } else { + execute( + sub_machine, + initial_depth + 1, + heap_depth, + backend, + invoker, + etable, + )? + }; + + match invoker.exit_substack( + sub_result, + sub_machine, + trap_data, + &mut machine, + backend, + ) { + Ok(()) => { + result = machine.run(backend, etable); } + Err(err) => return Ok((Err(err), machine)), } } - Capture::Exit(Err(err)) => return (machine, Err(err)), + Capture::Exit(Err(err)) => return Ok((Err(err), machine)), Capture::Trap(infallible) => match infallible {}, } } } } } + +pub struct HeapTransact< + 'backend, + 'invoker, + S: AsMut, + G: Gasometer, + H, + Tr, + I: Invoker, +> { + call_stack: CallStack<'backend, 'invoker, S, G, H, Tr, I>, + transact_invoke: I::TransactInvoke, +} + +impl<'backend, 'invoker, S, G, H, Tr, I> HeapTransact<'backend, 'invoker, S, G, H, Tr, I> +where + S: AsMut, + G: Gasometer, + I: Invoker, +{ + pub fn new( + args: I::TransactArgs, + invoker: &'invoker I, + backend: &'backend mut H, + ) -> Result { + let (transact_invoke, machine) = invoker.new_transact(args, backend)?; + let call_stack = CallStack::new(machine, 0, backend, invoker); + + Ok(Self { + transact_invoke, + call_stack, + }) + } + + pub fn step( + &mut self, + etable: &Etable, + ) -> Option, I::Interrupt>> + where + F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, + { + match self.call_stack.step(etable) { + None => None, + Some(Capture::Trap(interrupt)) => Some(Capture::Trap(interrupt)), + Some(Capture::Exit(Err(fatal))) => Some(Capture::Exit(Err(fatal.into()))), + Some(Capture::Exit(Ok((ret, machine)))) => { + Some(Capture::Exit(self.call_stack.invoker.finalize_transact( + &self.transact_invoke, + ret, + machine, + self.call_stack.backend, + ))) + } + } + } + + pub fn run( + &mut self, + etable: &Etable, + ) -> Capture, I::Interrupt> + where + F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, + { + loop { + let step_ret = self.step(etable); + + if let Some(step_ret) = step_ret { + return step_ret; + } + } + } +} + +impl<'backend, 'invoker, S, G, H, Tr, I> Drop for HeapTransact<'backend, 'invoker, S, G, H, Tr, I> +where + S: AsMut, + G: Gasometer, + I: Invoker, +{ + fn drop(&mut self) { + if let Some(mut last) = self.call_stack.last.take() { + loop { + if let Some(mut parent) = self.call_stack.stack.pop() { + let _ = self.call_stack.invoker.exit_substack( + ExitFatal::Unfinished.into(), + last.machine, + parent.invoke, + &mut parent.machine, + self.call_stack.backend, + ); + + last = LastSubstack { + machine: parent.machine, + status: LastSubstackStatus::Exited(Capture::Exit( + ExitFatal::Unfinished.into(), + )), + }; + } else { + break; + } + } + + let _ = self.call_stack.invoker.finalize_transact( + &self.transact_invoke, + ExitFatal::Unfinished.into(), + last.machine, + self.call_stack.backend, + ); + } + } +} + +pub fn transact( + args: I::TransactArgs, + heap_depth: Option, + backend: &mut H, + invoker: &I, + etable: &Etable, +) -> Result +where + S: AsMut, + G: Gasometer, + I: Invoker, + F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, +{ + let (transact_invoke, machine) = invoker.new_transact(args, backend)?; + let (ret, machine) = execute(machine, 0, heap_depth, backend, invoker, etable)?; + invoker.finalize_transact(&transact_invoke, ret, machine, backend) +} diff --git a/src/gasometer.rs b/src/gasometer.rs index 97a065b00..91932a891 100644 --- a/src/gasometer.rs +++ b/src/gasometer.rs @@ -1,6 +1,8 @@ //! EVM gasometer. -use crate::{Capture, Control, Etable, ExitError, ExitResult, Machine, Opcode, RuntimeState}; +use crate::{ + Capture, Control, Etable, ExitError, ExitResult, Machine, MergeStrategy, Opcode, RuntimeState, +}; use core::ops::{Add, AddAssign, Sub, SubAssign}; use primitive_types::U256; @@ -17,13 +19,6 @@ pub trait Gas: impl Gas for u64 {} impl Gas for U256 {} -#[derive(Clone, Copy)] -pub enum GasometerMergeStrategy { - Commit, - Revert, - Discard, -} - pub trait Gasometer: Sized { fn record_stepn( &mut self, @@ -34,7 +29,7 @@ pub trait Gasometer: Sized { fn record_codedeposit(&mut self, len: usize) -> Result<(), ExitError>; fn gas(&self) -> U256; fn submeter(&mut self, gas_limit: U256, code: &[u8]) -> Result; - fn merge(&mut self, other: Self, strategy: GasometerMergeStrategy); + fn merge(&mut self, other: Self, strategy: MergeStrategy); } pub struct GasedMachine { diff --git a/src/invoker.rs b/src/invoker.rs index a0da37b6c..a5188e948 100644 --- a/src/invoker.rs +++ b/src/invoker.rs @@ -2,32 +2,39 @@ use crate::{Capture, ExitError, ExitResult, GasedMachine}; pub trait Invoker { type Interrupt; - type CallCreateTrapPrepareData; - type CallCreateTrapEnterData; - fn exit_trap_stack( + type TransactArgs; + type TransactInvoke; + type TransactValue; + type SubstackInvoke; + + fn new_transact( + &self, + args: Self::TransactArgs, + handler: &mut H, + ) -> Result<(Self::TransactInvoke, GasedMachine), ExitError>; + fn finalize_transact( + &self, + invoke: &Self::TransactInvoke, + exit: ExitResult, + machine: GasedMachine, + handler: &mut H, + ) -> Result; + + fn exit_substack( &self, result: ExitResult, child: GasedMachine, - trap_data: Self::CallCreateTrapEnterData, + trap_data: Self::SubstackInvoke, parent: &mut GasedMachine, handler: &mut H, ) -> Result<(), ExitError>; - /// The separation of `prepare_trap` and `enter_trap_stack` is to give an opportunity for the - /// trait to return `Self::Interrupt`. When `Self::Interrupt` is `Infallible`, there's no - /// difference whether a code is in `prepare_trap` or `enter_trap_stack`. - fn prepare_trap( + fn enter_substack( &self, trap: Tr, machine: &mut GasedMachine, handler: &mut H, depth: usize, - ) -> Capture, Self::Interrupt>; - - fn enter_trap_stack( - &self, - trap_data: Self::CallCreateTrapPrepareData, - handler: &mut H, - ) -> Result<(Self::CallCreateTrapEnterData, GasedMachine), ExitError>; + ) -> Capture), ExitError>, Self::Interrupt>; } diff --git a/src/lib.rs b/src/lib.rs index fade6a34b..acdefee0a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,14 @@ mod invoker; pub use evm_interpreter::*; -pub use crate::backend::{TransactionalBackend, TransactionalMergeStrategy}; -pub use crate::call_stack::{execute, CallStack}; -pub use crate::gasometer::{Gas, GasedMachine, Gasometer, GasometerMergeStrategy}; +pub use crate::backend::TransactionalBackend; +pub use crate::call_stack::{transact, HeapTransact}; +pub use crate::gasometer::{Gas, GasedMachine, Gasometer}; pub use crate::invoker::Invoker; + +#[derive(Clone, Debug, Copy)] +pub enum MergeStrategy { + Commit, + Revert, + Discard, +} diff --git a/src/standard/gasometer/mod.rs b/src/standard/gasometer/mod.rs index f3373ab04..5f55a0744 100644 --- a/src/standard/gasometer/mod.rs +++ b/src/standard/gasometer/mod.rs @@ -4,7 +4,7 @@ mod utils; use crate::standard::Config; use crate::{ - ExitError, ExitException, Gasometer as GasometerT, GasometerMergeStrategy, Machine, Opcode, + ExitError, ExitException, Gasometer as GasometerT, Machine, MergeStrategy, Opcode, RuntimeBackend, RuntimeState, Stack, }; use core::cmp::max; @@ -196,16 +196,16 @@ impl<'config, S: AsRef, H: RuntimeBackend> GasometerT for Ga Ok(Self::new(gas_limit, code, self.config)) } - fn merge(&mut self, other: Self, strategy: GasometerMergeStrategy) { + fn merge(&mut self, other: Self, strategy: MergeStrategy) { match strategy { - GasometerMergeStrategy::Commit => { + MergeStrategy::Commit => { self.used_gas -= other.gas(); self.refunded_gas += other.refunded_gas; } - GasometerMergeStrategy::Revert => { + MergeStrategy::Revert => { self.used_gas -= other.gas(); } - GasometerMergeStrategy::Discard => {} + MergeStrategy::Discard => {} } } } diff --git a/src/standard/invoker/mod.rs b/src/standard/invoker/mod.rs index 5b90636c2..617c67f48 100644 --- a/src/standard/invoker/mod.rs +++ b/src/standard/invoker/mod.rs @@ -1,12 +1,11 @@ mod routines; -use self::routines::try_or_oog; -use super::{Config, Etable, GasedMachine, TransactGasometer}; +use super::{Config, MergeableRuntimeState, TransactGasometer}; use crate::call_create::{CallCreateTrapData, CallTrapData, CreateScheme, CreateTrapData}; use crate::{ - Capture, Context, ExitError, ExitException, ExitResult, Gasometer as GasometerT, - GasometerMergeStrategy, Invoker as InvokerT, Opcode, RuntimeBackend, RuntimeEnvironment, - RuntimeState, TransactionContext, TransactionalBackend, TransactionalMergeStrategy, Transfer, + Capture, Context, ExitError, ExitException, ExitResult, ExitSucceed, GasedMachine, + Gasometer as GasometerT, Invoker as InvokerT, MergeStrategy, Opcode, RuntimeBackend, + RuntimeEnvironment, RuntimeState, TransactionContext, TransactionalBackend, Transfer, }; use alloc::rc::Rc; use core::cmp::min; @@ -14,41 +13,34 @@ use core::convert::Infallible; use primitive_types::{H160, H256, U256}; use sha3::{Digest, Keccak256}; -pub enum CallCreateTrapPrepareData { - Call { - gasometer: G, - code: Vec, - is_static: bool, - transaction_context: Rc, - trap: CallTrapData, - }, - Create { - gasometer: G, - code: Vec, - is_static: bool, - transaction_context: Rc, - trap: CreateTrapData, - }, +pub trait IntoCallCreateTrap { + type Interrupt; + + fn into_call_create_trap(self) -> Result; +} + +impl IntoCallCreateTrap for Opcode { + type Interrupt = Infallible; + + fn into_call_create_trap(self) -> Result { + Ok(self) + } } -pub enum CallCreateTrapEnterData { +pub enum SubstackInvoke { Call { trap: CallTrapData }, Create { trap: CreateTrapData, address: H160 }, } -const DEFAULT_HEAP_DEPTH: Option = Some(4); - -pub struct Invoker<'config> { - config: &'config Config, +pub struct TransactInvoke { + pub create_address: Option, + pub gas_fee: U256, + pub gas_price: U256, + pub caller: H160, } -impl<'config> Invoker<'config> { - pub fn new(config: &'config Config) -> Self { - Self { config } - } - - pub fn transact_call( - &self, +pub enum TransactArgs { + Call { caller: H160, address: H160, value: U256, @@ -56,255 +48,287 @@ impl<'config> Invoker<'config> { gas_limit: U256, gas_price: U256, access_list: Vec<(H160, Vec)>, - handler: &mut H, - etable: &Etable, - ) -> ExitResult - where - G: GasometerT + TransactGasometer<'config, RuntimeState>, - H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, - { - routines::transact_and_work( - self, - caller, - gas_limit, - gas_price, - handler, - |handler: &mut H| -> (ExitResult, U256) { - let context = Context { - caller, - address, - apparent_value: value, - }; - let transfer = Transfer { - source: caller, - target: address, - value, - }; - let transaction_context = TransactionContext { - origin: caller, - gas_price, - }; - - let code = handler.code(address); - - let gasometer = try_or_oog!(G::new_transact_call( - gas_limit, - &code, - &data, - &access_list, - self.config - )); + }, + Create { + caller: H160, + value: U256, + init_code: Vec, + salt: Option, // Some for CREATE2 + gas_limit: U256, + gas_price: U256, + access_list: Vec<(H160, Vec)>, + }, +} - let machine = try_or_oog!(routines::make_enter_call_machine( - self, - code, - data, - false, // is_static - Some(transfer), - context, - Rc::new(transaction_context), - gasometer, - handler - )); - - if self.config.increase_state_access_gas { - if self.config.warm_coinbase_address { - let coinbase = handler.block_coinbase(); - try_or_oog!(handler.mark_hot(coinbase, None)); - } - try_or_oog!(handler.mark_hot(caller, None)); - try_or_oog!(handler.mark_hot(address, None)); - } +impl TransactArgs { + pub fn gas_limit(&self) -> U256 { + match self { + Self::Call { gas_limit, .. } => *gas_limit, + Self::Create { gas_limit, .. } => *gas_limit, + } + } - try_or_oog!(handler.inc_nonce(caller)); + pub fn gas_price(&self) -> U256 { + match self { + Self::Call { gas_price, .. } => *gas_price, + Self::Create { gas_price, .. } => *gas_price, + } + } - let (machine, result) = - crate::execute(machine, handler, 0, DEFAULT_HEAP_DEPTH, self, etable); + pub fn access_list(&self) -> &Vec<(H160, Vec)> { + match self { + Self::Call { access_list, .. } => access_list, + Self::Create { access_list, .. } => access_list, + } + } - let refunded_gas = U256::from(machine.gasometer.gas()); - (result, refunded_gas) - }, - ) + pub fn caller(&self) -> H160 { + match self { + Self::Call { caller, .. } => *caller, + Self::Create { caller, .. } => *caller, + } + } + + pub fn value(&self) -> U256 { + match self { + Self::Call { value, .. } => *value, + Self::Create { value, .. } => *value, + } } +} + +pub struct Invoker<'config> { + config: &'config Config, +} - pub fn transact_create( +impl<'config> Invoker<'config> { + pub fn new(config: &'config Config) -> Self { + Self { config } + } +} + +impl<'config, S, G, H, Tr> InvokerT for Invoker<'config> +where + S: MergeableRuntimeState, + G: GasometerT + TransactGasometer<'config, S>, + H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, + Tr: IntoCallCreateTrap, +{ + type Interrupt = Tr::Interrupt; + type TransactArgs = TransactArgs; + type TransactInvoke = TransactInvoke; + type TransactValue = (ExitSucceed, Option); + type SubstackInvoke = SubstackInvoke; + + fn new_transact( &self, - caller: H160, - value: U256, - init_code: Vec, - gas_limit: U256, - gas_price: U256, - access_list: Vec<(H160, Vec)>, + args: TransactArgs, handler: &mut H, - etable: &Etable, - ) -> Result - where - G: GasometerT + TransactGasometer<'config, RuntimeState>, - H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, - { - routines::transact_and_work( - self, + ) -> Result<(TransactInvoke, GasedMachine), ExitError> { + let caller = args.caller(); + let gas_price = args.gas_price(); + + let gas_fee = args.gas_limit().saturating_mul(gas_price); + handler.withdrawal(caller, gas_fee)?; + + let address = match &args { + TransactArgs::Call { address, .. } => *address, + TransactArgs::Create { + caller, + salt, + init_code, + .. + } => match salt { + Some(salt) => { + let scheme = CreateScheme::Create2 { + caller: *caller, + code_hash: H256::from_slice(Keccak256::digest(&init_code).as_slice()), + salt: *salt, + }; + scheme.address(handler) + } + None => { + let scheme = CreateScheme::Legacy { caller: *caller }; + scheme.address(handler) + } + }, + }; + let value = args.value(); + + let invoke = TransactInvoke { + gas_fee, + gas_price: args.gas_price(), + caller: args.caller(), + create_address: match &args { + TransactArgs::Call { .. } => None, + TransactArgs::Create { .. } => Some(address), + }, + }; + + handler.push_substate(); + + let context = Context { caller, - gas_limit, + address, + apparent_value: value, + }; + let transaction_context = TransactionContext { + origin: caller, gas_price, - handler, - |handler| -> (Result, U256) { - let scheme = CreateScheme::Legacy { caller }; - let address = scheme.address(handler); + }; + let transfer = Transfer { + source: caller, + target: address, + value, + }; - let context = Context { + let work = || -> Result<(TransactInvoke, GasedMachine), ExitError> { + match args { + TransactArgs::Call { caller, address, - apparent_value: value, - }; - let transaction_context = TransactionContext { - origin: caller, - gas_price, - }; - let transfer = Transfer { - source: caller, - target: address, - value, - }; - - let gasometer = try_or_oog!(G::new_transact_create( + data, gas_limit, - &init_code, - &access_list, - self.config - )); + access_list, + .. + } => { + let code = handler.code(address); + + let gasometer = + G::new_transact_call(gas_limit, &code, &data, &access_list, self.config)?; + + let machine = routines::make_enter_call_machine( + self, + code, + data, + false, // is_static + Some(transfer), + S::new_transact_call(RuntimeState { + context, + transaction_context: Rc::new(transaction_context), + retbuf: Vec::new(), + gas: U256::zero(), + }), + gasometer, + handler, + )?; + + if self.config.increase_state_access_gas { + if self.config.warm_coinbase_address { + let coinbase = handler.block_coinbase(); + handler.mark_hot(coinbase, None)?; + } + handler.mark_hot(caller, None)?; + handler.mark_hot(address, None)?; + } - let machine = try_or_oog!(routines::make_enter_create_machine( - self, + handler.inc_nonce(caller)?; + + Ok((invoke, machine)) + } + TransactArgs::Create { caller, init_code, - false, // is_static - transfer, - context, - Rc::new(transaction_context), - gasometer, - handler, - )); + gas_limit, + access_list, + .. + } => { + let gasometer = + G::new_transact_create(gas_limit, &init_code, &access_list, self.config)?; + + let machine = routines::make_enter_create_machine( + self, + caller, + init_code, + false, // is_static + transfer, + S::new_transact_create(RuntimeState { + context, + transaction_context: Rc::new(transaction_context), + retbuf: Vec::new(), + gas: U256::zero(), + }), + gasometer, + handler, + )?; + + Ok((invoke, machine)) + } + } + }; - let (mut machine, result) = - crate::execute(machine, handler, 0, DEFAULT_HEAP_DEPTH, self, etable); - let retbuf = machine.machine.into_retbuf(); - let address = try_or_oog!(routines::deploy_create_code( - self, - result.map(|_| address), - &retbuf, - &mut machine.gasometer, - handler - )); - - let refunded_gas = U256::from(machine.gasometer.gas()); - (Ok(address), refunded_gas) - }, - ) + match work() { + Ok(ret) => Ok(ret), + Err(err) => { + handler.pop_substate(MergeStrategy::Discard); + Err(err) + } + } } - pub fn transact_create2( + fn finalize_transact( &self, - caller: H160, - value: U256, - init_code: Vec, - salt: H256, - gas_limit: U256, - gas_price: U256, - access_list: Vec<(H160, Vec)>, + invoke: &TransactInvoke, + result: ExitResult, + mut machine: GasedMachine, handler: &mut H, - etable: &Etable, - ) -> Result - where - G: GasometerT + TransactGasometer<'config, RuntimeState>, - H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, - { - routines::transact_and_work( - self, - caller, - gas_limit, - gas_price, - handler, - |handler| -> (Result, U256) { - let scheme = CreateScheme::Create2 { - caller, - code_hash: H256::from_slice(Keccak256::digest(&init_code).as_slice()), - salt, - }; - let address = scheme.address(handler); + ) -> Result { + let work = || -> Result { + if result.is_ok() { + if let Some(address) = invoke.create_address { + let retbuf = machine.machine.into_retbuf(); + + routines::deploy_create_code( + self, + address, + &retbuf, + &mut machine.gasometer, + handler, + )?; + } + } - let context = Context { - caller, - address, - apparent_value: value, - }; - let transaction_context = TransactionContext { - origin: caller, - gas_price, - }; - let transfer = Transfer { - source: caller, - target: address, - value, - }; - - let gasometer = try_or_oog!(G::new_transact_create( - gas_limit, - &init_code, - &access_list, - self.config - )); + let refunded_gas = match result { + Ok(_) | Err(ExitError::Reverted) => machine.gasometer.gas(), + Err(_) => U256::zero(), + }; + let refunded_fee = refunded_gas.saturating_mul(invoke.gas_price); + let coinbase_reward = invoke.gas_fee.saturating_sub(refunded_fee); - let machine = try_or_oog!(routines::make_enter_create_machine( - self, - caller, - init_code, - false, // is_static - transfer, - context, - Rc::new(transaction_context), - gasometer, - handler, - )); + handler.deposit(invoke.caller, refunded_fee); + handler.deposit(handler.block_coinbase(), coinbase_reward); - let (mut machine, result) = - crate::execute(machine, handler, 0, DEFAULT_HEAP_DEPTH, self, etable); - let retbuf = machine.machine.into_retbuf(); - let address = try_or_oog!(routines::deploy_create_code( - self, - result.map(|_| address), - &retbuf, - &mut machine.gasometer, - handler - )); - - let refunded_gas = U256::from(machine.gasometer.gas()); - (Ok(address), refunded_gas) - }, - ) - } -} + result.map(|s| (s, invoke.create_address)) + }; -impl<'config, G, H> InvokerT for Invoker<'config> -where - G: GasometerT, - H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, -{ - type Interrupt = Infallible; - type CallCreateTrapPrepareData = CallCreateTrapPrepareData; - type CallCreateTrapEnterData = CallCreateTrapEnterData; + match work() { + Ok(exit) => { + handler.pop_substate(MergeStrategy::Commit); + Ok(exit) + } + Err(err) => { + handler.pop_substate(MergeStrategy::Discard); + Err(err) + } + } + } - fn prepare_trap( + fn enter_substack( &self, - opcode: Opcode, - machine: &mut GasedMachine, + trap: Tr, + machine: &mut GasedMachine, handler: &mut H, depth: usize, - ) -> Capture, Infallible> { + ) -> Capture), ExitError>, Tr::Interrupt> { fn l64(gas: U256) -> U256 { gas - gas / U256::from(64) } + let opcode = match trap.into_call_create_trap() { + Ok(opcode) => opcode, + Err(interrupt) => return Capture::Trap(interrupt), + }; + if depth >= self.config.call_stack_limit { return Capture::Exit(Err(ExitException::CallTooDeep.into())); } @@ -346,142 +370,98 @@ where Err(err) => return Capture::Exit(Err(err)), }; - Capture::Exit(Ok(match trap_data { - CallCreateTrapData::Call(call_trap_data) => CallCreateTrapPrepareData::Call { - gasometer: submeter, - code, - is_static, - transaction_context, - trap: call_trap_data, - }, - CallCreateTrapData::Create(create_trap_data) => CallCreateTrapPrepareData::Create { - gasometer: submeter, - code, - is_static, - transaction_context, - trap: create_trap_data, - }, - })) - } - - fn enter_trap_stack( - &self, - trap_data: Self::CallCreateTrapPrepareData, - handler: &mut H, - ) -> Result<(Self::CallCreateTrapEnterData, GasedMachine), ExitError> { match trap_data { - CallCreateTrapPrepareData::Create { - gasometer, - code, - is_static, - transaction_context, - trap, - } => routines::enter_create_trap_stack( - self, - code, - trap, - is_static, - transaction_context, - gasometer, - handler, - ), - CallCreateTrapPrepareData::Call { - gasometer, - code, - is_static, - transaction_context, - trap, - } => routines::enter_call_trap_stack( - self, - code, - trap, - is_static, - transaction_context, - gasometer, - handler, - ), + CallCreateTrapData::Call(call_trap_data) => { + let substate = machine.machine.state.substate(RuntimeState { + context: call_trap_data.context.clone(), + transaction_context, + retbuf: Vec::new(), + gas: U256::zero(), + }); + + Capture::Exit(routines::enter_call_substack( + self, + code, + call_trap_data, + is_static, + substate, + submeter, + handler, + )) + } + CallCreateTrapData::Create(create_trap_data) => { + let caller = create_trap_data.scheme.caller(); + let address = create_trap_data.scheme.address(handler); + let substate = machine.machine.state.substate(RuntimeState { + context: Context { + address, + caller, + apparent_value: create_trap_data.value, + }, + transaction_context, + retbuf: Vec::new(), + gas: U256::zero(), + }); + + Capture::Exit(routines::enter_create_substack( + self, + code, + create_trap_data, + is_static, + substate, + submeter, + handler, + )) + } } } - fn exit_trap_stack( + fn exit_substack( &self, result: ExitResult, - mut child: GasedMachine, - trap_data: Self::CallCreateTrapEnterData, - parent: &mut GasedMachine, + child: GasedMachine, + trap_data: SubstackInvoke, + parent: &mut GasedMachine, handler: &mut H, ) -> Result<(), ExitError> { + let strategy = match &result { + Ok(_) => MergeStrategy::Commit, + Err(ExitError::Reverted) => MergeStrategy::Revert, + Err(_) => MergeStrategy::Discard, + }; + match trap_data { - CallCreateTrapEnterData::Create { address, trap } => { - let retbuf = child.machine.into_retbuf(); - let result = routines::deploy_create_code( - self, - result.map(|_| address), - &retbuf, - &mut child.gasometer, - handler, - ); - - match &result { - Ok(_) => { - handler.pop_substate(TransactionalMergeStrategy::Commit); - GasometerT::::merge( - &mut parent.gasometer, - child.gasometer, - GasometerMergeStrategy::Commit, - ); - } - Err(ExitError::Reverted) => { - handler.pop_substate(TransactionalMergeStrategy::Discard); - GasometerT::::merge( - &mut parent.gasometer, - child.gasometer, - GasometerMergeStrategy::Revert, - ); - } - Err(_) => { - handler.pop_substate(TransactionalMergeStrategy::Discard); - GasometerT::::merge( - &mut parent.gasometer, - child.gasometer, - GasometerMergeStrategy::Discard, - ); - } - }; + SubstackInvoke::Create { address, trap } => { + let retbuf = child.machine.memory.into_data(); + parent.machine.state.merge(child.machine.state, strategy); + + let mut child_gasometer = child.gasometer; + let result = result.and_then(|_| { + routines::deploy_create_code( + self, + address, + &retbuf, + &mut child_gasometer, + handler, + )?; + + Ok(address) + }); + + handler.pop_substate(strategy); + GasometerT::::merge(&mut parent.gasometer, child_gasometer, strategy); trap.feedback(result, retbuf, &mut parent.machine)?; Ok(()) } - CallCreateTrapEnterData::Call { trap } => { - let retbuf = child.machine.into_retbuf(); - - match &result { - Ok(_) => { - handler.pop_substate(TransactionalMergeStrategy::Commit); - GasometerT::::merge( - &mut parent.gasometer, - child.gasometer, - GasometerMergeStrategy::Commit, - ); - } - Err(ExitError::Reverted) => { - handler.pop_substate(TransactionalMergeStrategy::Discard); - GasometerT::::merge( - &mut parent.gasometer, - child.gasometer, - GasometerMergeStrategy::Revert, - ); - } - Err(_) => { - handler.pop_substate(TransactionalMergeStrategy::Discard); - GasometerT::::merge( - &mut parent.gasometer, - child.gasometer, - GasometerMergeStrategy::Discard, - ); - } - }; + SubstackInvoke::Call { trap } => { + parent.machine.state.merge(child.machine.state, strategy); + + let retbuf = child.machine.memory.into_data(); + + handler.pop_substate(strategy); + GasometerT::::merge(&mut parent.gasometer, child.gasometer, strategy); trap.feedback(result, retbuf, &mut parent.machine)?; diff --git a/src/standard/invoker/routines.rs b/src/standard/invoker/routines.rs index 6e84973f1..edea34817 100644 --- a/src/standard/invoker/routines.rs +++ b/src/standard/invoker/routines.rs @@ -1,75 +1,28 @@ -use super::{CallCreateTrapEnterData, CallTrapData, CreateTrapData, Invoker}; -use crate::standard::{Config, GasedMachine, Machine}; +use super::{CallTrapData, CreateTrapData, Invoker, SubstackInvoke}; +use crate::standard::{Config, MergeableRuntimeState}; use crate::{ - Context, ExitError, ExitException, Gasometer as GasometerT, Opcode, RuntimeBackend, - RuntimeEnvironment, RuntimeState, TransactionContext, TransactionalBackend, - TransactionalMergeStrategy, Transfer, + ExitError, ExitException, GasedMachine, Gasometer as GasometerT, Machine, MergeStrategy, + Opcode, RuntimeBackend, RuntimeEnvironment, TransactionalBackend, Transfer, }; use alloc::rc::Rc; use primitive_types::{H160, U256}; -macro_rules! try_or_oog { - ($e:expr) => { - match $e { - Ok(v) => v, - Err(e) => return (Err(e), ::primitive_types::U256::zero()), - } - } -} -pub(crate) use try_or_oog; - -pub fn transact_and_work<'config, H, R, F>( - _invoker: &Invoker<'config>, - caller: H160, - gas_limit: U256, - gas_price: U256, - handler: &mut H, - f: F, -) -> Result -where - H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, - F: FnOnce(&mut H) -> (Result, U256), -{ - let gas_fee = gas_limit.saturating_mul(gas_price); - handler.withdrawal(caller, gas_fee)?; - - handler.push_substate(); - - let (result, refunded_gas) = f(handler); - let refunded_fee = refunded_gas.saturating_mul(gas_price); - let coinbase_reward = gas_fee.saturating_sub(refunded_fee); - - handler.deposit(caller, refunded_fee); - handler.deposit(handler.block_coinbase(), coinbase_reward); - - match result { - Ok(exit) => { - handler.pop_substate(TransactionalMergeStrategy::Commit); - Ok(exit) - } - Err(err) => { - handler.pop_substate(TransactionalMergeStrategy::Discard); - Err(err) - } - } -} - -pub fn make_enter_call_machine<'config, G, H>( +pub fn make_enter_call_machine<'config, S, G, H>( invoker: &Invoker<'config>, code: Vec, input: Vec, is_static: bool, transfer: Option, - context: Context, - transaction_context: Rc, + state: S, gasometer: G, handler: &mut H, -) -> Result, ExitError> +) -> Result, ExitError> where - G: GasometerT, + S: MergeableRuntimeState, + G: GasometerT, H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, { - handler.mark_hot(context.address, None)?; + handler.mark_hot(state.as_ref().context.address, None)?; if let Some(transfer) = transfer { handler.transfer(transfer)?; @@ -77,17 +30,12 @@ where // TODO: precompile contracts. - let machine = Machine::new( + let machine = Machine::::new( Rc::new(code), Rc::new(input.clone()), invoker.config.stack_limit, invoker.config.memory_limit, - RuntimeState { - context: context.clone(), - transaction_context, - retbuf: Vec::new(), - gas: U256::zero(), - }, + state, ); Ok(GasedMachine { @@ -97,19 +45,19 @@ where }) } -pub fn make_enter_create_machine<'config, G, H>( +pub fn make_enter_create_machine<'config, S, G, H>( invoker: &Invoker<'config>, caller: H160, init_code: Vec, is_static: bool, transfer: Transfer, - context: Context, - transaction_context: Rc, + state: S, gasometer: G, handler: &mut H, -) -> Result, ExitError> +) -> Result, ExitError> where - G: GasometerT, + S: MergeableRuntimeState, + G: GasometerT, H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, { if let Some(limit) = invoker.config.max_initcode_size { @@ -119,33 +67,28 @@ where } handler.mark_hot(caller, None)?; - handler.mark_hot(context.address, None)?; + handler.mark_hot(state.as_ref().context.address, None)?; handler.transfer(transfer)?; - if handler.code_size(context.address) != U256::zero() - || handler.nonce(context.address) > U256::zero() + if handler.code_size(state.as_ref().context.address) != U256::zero() + || handler.nonce(state.as_ref().context.address) > U256::zero() { return Err(ExitException::CreateCollision.into()); } handler.inc_nonce(caller)?; if invoker.config.create_increase_nonce { - handler.inc_nonce(context.address)?; + handler.inc_nonce(state.as_ref().context.address)?; } - handler.reset_storage(context.address); + handler.reset_storage(state.as_ref().context.address); let machine = Machine::new( Rc::new(init_code), Rc::new(Vec::new()), invoker.config.stack_limit, invoker.config.memory_limit, - RuntimeState { - context: context.clone(), - transaction_context, - retbuf: Vec::new(), - gas: U256::zero(), - }, + state, ); Ok(GasedMachine { @@ -155,62 +98,63 @@ where }) } -pub fn enter_call_trap_stack<'config, G, H>( +pub fn enter_call_substack<'config, S, G, H>( invoker: &Invoker<'config>, code: Vec, trap_data: CallTrapData, is_static: bool, - transaction_context: Rc, + state: S, gasometer: G, handler: &mut H, -) -> Result<(CallCreateTrapEnterData, GasedMachine), ExitError> +) -> Result<(SubstackInvoke, GasedMachine), ExitError> where - G: GasometerT, + S: MergeableRuntimeState, + G: GasometerT, H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, { handler.push_substate(); - let work = || -> Result<(CallCreateTrapEnterData, GasedMachine), ExitError> { + let work = || -> Result<(SubstackInvoke, GasedMachine), ExitError> { let machine = make_enter_call_machine( invoker, code, trap_data.input.clone(), is_static, trap_data.transfer.clone(), - trap_data.context.clone(), - transaction_context, + state, gasometer, handler, )?; - Ok((CallCreateTrapEnterData::Call { trap: trap_data }, machine)) + Ok((SubstackInvoke::Call { trap: trap_data }, machine)) }; match work() { Ok(machine) => Ok(machine), Err(err) => { - handler.pop_substate(TransactionalMergeStrategy::Discard); + handler.pop_substate(MergeStrategy::Discard); Err(err) } } } -pub fn enter_create_trap_stack<'config, G, H>( +pub fn enter_create_substack<'config, S, G, H>( invoker: &Invoker<'config>, code: Vec, trap_data: CreateTrapData, is_static: bool, - transaction_context: Rc, + state: S, gasometer: G, handler: &mut H, -) -> Result<(CallCreateTrapEnterData, GasedMachine), ExitError> +) -> Result<(SubstackInvoke, GasedMachine), ExitError> where - G: GasometerT, + S: MergeableRuntimeState, + G: GasometerT, H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, { handler.push_substate(); - let work = || -> Result<(CallCreateTrapEnterData, GasedMachine), ExitError> { + let work = || -> Result<(SubstackInvoke, GasedMachine), ExitError> { let CreateTrapData { scheme, value, @@ -220,12 +164,6 @@ where let caller = scheme.caller(); let address = scheme.address(handler); - let context = Context { - address, - caller, - apparent_value: value, - }; - let transfer = Transfer { source: caller, target: address, @@ -233,19 +171,11 @@ where }; let machine = make_enter_create_machine( - invoker, - caller, - code, - is_static, - transfer, - context, - transaction_context, - gasometer, - handler, + invoker, caller, code, is_static, transfer, state, gasometer, handler, )?; Ok(( - CallCreateTrapEnterData::Create { + SubstackInvoke::Create { address, trap: trap_data, }, @@ -256,7 +186,7 @@ where match work() { Ok(machine) => Ok(machine), Err(err) => { - handler.pop_substate(TransactionalMergeStrategy::Discard); + handler.pop_substate(MergeStrategy::Discard); Err(err) } } @@ -269,18 +199,18 @@ fn check_first_byte(config: &Config, code: &[u8]) -> Result<(), ExitError> { Ok(()) } -pub fn deploy_create_code<'config, G, H>( +pub fn deploy_create_code<'config, S, G, H>( invoker: &Invoker<'config>, - result: Result, + address: H160, retbuf: &Vec, gasometer: &mut G, handler: &mut H, -) -> Result +) -> Result<(), ExitError> where - G: GasometerT, + S: MergeableRuntimeState, + G: GasometerT, H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, { - let address = result?; check_first_byte(invoker.config, &retbuf[..])?; if let Some(limit) = invoker.config.create_contract_limit { @@ -289,9 +219,9 @@ where } } - GasometerT::::record_codedeposit(gasometer, retbuf.len())?; + GasometerT::::record_codedeposit(gasometer, retbuf.len())?; handler.set_code(address, retbuf.clone()); - Ok(address) + Ok(()) } diff --git a/src/standard/mod.rs b/src/standard/mod.rs index f6ab311be..3ed1cb99a 100644 --- a/src/standard/mod.rs +++ b/src/standard/mod.rs @@ -4,9 +4,29 @@ mod invoker; pub use self::config::Config; pub use self::gasometer::{Gasometer, TransactGasometer}; -pub use self::invoker::Invoker; +pub use self::invoker::{Invoker, TransactArgs}; pub type Machine = crate::Machine; pub type Efn = crate::Efn; pub type Etable> = crate::Etable; pub type GasedMachine = crate::GasedMachine; + +pub trait MergeableRuntimeState: AsRef + AsMut { + fn substate(&self, runtime: crate::RuntimeState) -> Self; + fn merge(&mut self, substate: Self, strategy: crate::MergeStrategy); + fn new_transact_call(runtime: crate::RuntimeState) -> Self; + fn new_transact_create(runtime: crate::RuntimeState) -> Self; +} + +impl MergeableRuntimeState for crate::RuntimeState { + fn substate(&self, runtime: crate::RuntimeState) -> Self { + runtime + } + fn merge(&mut self, _substate: Self, _strategy: crate::MergeStrategy) {} + fn new_transact_call(runtime: crate::RuntimeState) -> Self { + runtime + } + fn new_transact_create(runtime: crate::RuntimeState) -> Self { + runtime + } +}