diff --git a/jsontests/src/run.rs b/jsontests/src/run.rs index ac6a591f1..219d784c8 100644 --- a/jsontests/src/run.rs +++ b/jsontests/src/run.rs @@ -51,7 +51,19 @@ pub fn run_test(_filename: &str, _test_name: &str, test: Test) -> Result<(), Err }) .collect::>(); - let mut backend = InMemoryBackend { + let etable = Etable::runtime(); + let invoker = Invoker::new(&config); + let args = 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(), + }; + + let mut run_backend = InMemoryBackend { environment: env, layers: vec![InMemoryLayer { state, @@ -60,26 +72,35 @@ pub fn run_test(_filename: &str, _test_name: &str, test: Test) -> Result<(), Err hots: BTreeSet::new(), }], }; + let mut step_backend = run_backend.clone(); - let etable = Etable::runtime(); - let invoker = Invoker::new(&config); - 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(), - }, + // Run + + let _run_result = evm::transact::( + args.clone(), Some(4), - &mut backend, + &mut run_backend, &invoker, &etable, ); - let state_root = crate::hash::state_root(&backend); + // Step + let mut stepper = evm::HeapTransact::::new( + args, + &invoker, + &mut step_backend, + )?; + let _step_result = loop { + println!( + "opcode: {:?}", + stepper.last_machine()?.machine.peek_opcode() + ); + if let Err(result) = stepper.step(&etable) { + break result; + } + }; + + let state_root = crate::hash::state_root(&run_backend); if state_root != test.post.hash { return Err(TestError::StateMismatch.into()); diff --git a/src/call_stack.rs b/src/call_stack.rs index a03f5e46e..df0c2a1ee 100644 --- a/src/call_stack.rs +++ b/src/call_stack.rs @@ -64,9 +64,9 @@ where F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, { loop { - let step_ret = self.step(etable); + let step_ret = self.step_run(etable); - if let Some(step_ret) = step_ret { + if let Err(step_ret) = step_ret { return step_ret; } } @@ -75,9 +75,40 @@ where pub fn step( &mut self, etable: &Etable, - ) -> Option), ExitFatal>, I::Interrupt>> + ) -> Result<(), Capture), ExitFatal>, I::Interrupt>> where F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, + { + self.step_with(etable, |machine, handler, etable| { + let result = machine.step(handler, etable); + match result { + Ok(()) => LastSubstackStatus::Running, + Err(result) => LastSubstackStatus::Exited(result), + } + }) + } + + pub fn step_run( + &mut self, + etable: &Etable, + ) -> Result<(), Capture), ExitFatal>, I::Interrupt>> + where + F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, + { + self.step_with(etable, |machine, handler, etable| { + let result = machine.run(handler, etable); + LastSubstackStatus::Exited(result) + }) + } + + fn step_with( + &mut self, + etable: &Etable, + fs: FS, + ) -> Result<(), Capture), ExitFatal>, I::Interrupt>> + where + F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, + FS: Fn(&mut GasedMachine, &mut H, &Etable) -> LastSubstackStatus, { let mut step_ret = None; @@ -97,11 +128,8 @@ where status: LastSubstackStatus::Running, mut machine, }) => { - let result = machine.run(self.backend, etable); - Some(LastSubstack { - status: LastSubstackStatus::Exited(result), - machine, - }) + let status = fs(&mut machine, self.backend, etable); + Some(LastSubstack { status, machine }) } Some(LastSubstack { status: LastSubstackStatus::Exited(Capture::Exit(exit)), @@ -173,7 +201,10 @@ where } }; - step_ret + match step_ret { + Some(res) => Err(res), + None => Ok(()), + } } } @@ -274,19 +305,27 @@ where }) } - pub fn step( + fn step_with( &mut self, etable: &Etable, - ) -> Option, I::Interrupt>> + fs: FS, + ) -> Result<(), Capture, I::Interrupt>> where F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, + FS: Fn( + &mut CallStack, + &Etable, + ) -> Result< + (), + Capture), ExitFatal>, I::Interrupt>, + >, { - 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( + match fs(&mut self.call_stack, etable) { + Ok(()) => Ok(()), + 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)))) => { + Err(Capture::Exit(self.call_stack.invoker.finalize_transact( &self.transact_invoke, ret, machine, @@ -296,6 +335,26 @@ where } } + pub fn step_run( + &mut self, + etable: &Etable, + ) -> Result<(), Capture, I::Interrupt>> + where + F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, + { + self.step_with(etable, |call_stack, etable| call_stack.step_run(etable)) + } + + pub fn step( + &mut self, + etable: &Etable, + ) -> Result<(), Capture, I::Interrupt>> + where + F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, + { + self.step_with(etable, |call_stack, etable| call_stack.step(etable)) + } + pub fn run( &mut self, etable: &Etable, @@ -304,13 +363,20 @@ where F: Fn(&mut Machine, &mut H, Opcode, usize) -> Control, { loop { - let step_ret = self.step(etable); + let step_ret = self.step_run(etable); - if let Some(step_ret) = step_ret { + if let Err(step_ret) = step_ret { return step_ret; } } } + + pub fn last_machine(&self) -> Result<&GasedMachine, ExitError> { + match &self.call_stack.last { + Some(last) => Ok(&last.machine), + None => Err(ExitFatal::AlreadyExited.into()), + } + } } impl<'backend, 'invoker, S, G, H, Tr, I> Drop for HeapTransact<'backend, 'invoker, S, G, H, Tr, I> diff --git a/src/gasometer.rs b/src/gasometer.rs index 91932a891..d64203f2b 100644 --- a/src/gasometer.rs +++ b/src/gasometer.rs @@ -20,12 +20,21 @@ impl Gas for u64 {} impl Gas for U256 {} pub trait Gasometer: Sized { + fn record_step( + &mut self, + machine: &Machine, + is_static: bool, + backend: &H, + ) -> Result<(), ExitError>; fn record_stepn( &mut self, machine: &Machine, is_static: bool, backend: &H, - ) -> Result; + ) -> Result { + self.record_step(machine, is_static, backend)?; + Ok(1) + } fn record_codedeposit(&mut self, len: usize) -> Result<(), ExitError>; fn gas(&self) -> U256; fn submeter(&mut self, gas_limit: U256, code: &[u8]) -> Result; @@ -39,6 +48,27 @@ pub struct GasedMachine { } 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, diff --git a/src/standard/gasometer/mod.rs b/src/standard/gasometer/mod.rs index 5f55a0744..38b1cef31 100644 --- a/src/standard/gasometer/mod.rs +++ b/src/standard/gasometer/mod.rs @@ -128,12 +128,12 @@ impl<'config, S: AsRef> TransactGasometer<'config, S> for Gasomete } impl<'config, S: AsRef, H: RuntimeBackend> GasometerT for Gasometer<'config> { - fn record_stepn( + fn record_step( &mut self, machine: &Machine, is_static: bool, handler: &H, - ) -> Result { + ) -> Result<(), ExitError> { self.perform(|gasometer| { let opcode = machine.peek_opcode().ok_or(ExitException::OutOfGas)?; @@ -169,7 +169,7 @@ impl<'config, S: AsRef, H: RuntimeBackend> GasometerT for Ga gas.extra_check(after_gas, gasometer.config)?; } - Ok(1) + Ok(()) }) } diff --git a/src/standard/invoker/mod.rs b/src/standard/invoker/mod.rs index 617c67f48..5a0f951c8 100644 --- a/src/standard/invoker/mod.rs +++ b/src/standard/invoker/mod.rs @@ -39,6 +39,7 @@ pub struct TransactInvoke { pub caller: H160, } +#[derive(Clone, Debug)] pub enum TransactArgs { Call { caller: H160,