Skip to content

Commit

Permalink
Implement single step for GasedMachine (#217)
Browse files Browse the repository at this point in the history
* Single step for GasedMachine

* Distinguish call stack step / step_run

* Add test example for stepping
  • Loading branch information
sorpaas authored Nov 18, 2023
1 parent 5c94026 commit 539a07c
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 38 deletions.
51 changes: 36 additions & 15 deletions jsontests/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,19 @@ pub fn run_test(_filename: &str, _test_name: &str, test: Test) -> Result<(), Err
})
.collect::<BTreeMap<_, _>>();

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,
Expand All @@ -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::<RuntimeState, Gasometer, _, _, _, _>(
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::<RuntimeState, Gasometer, _, _, _, _>(
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::<RuntimeState, Gasometer, _, _, _>::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());
Expand Down
104 changes: 85 additions & 19 deletions src/call_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,9 @@ where
F: Fn(&mut Machine<S>, &mut H, Opcode, usize) -> Control<Tr>,
{
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;
}
}
Expand All @@ -75,9 +75,40 @@ where
pub fn step<F>(
&mut self,
etable: &Etable<S, H, Tr, F>,
) -> Option<Capture<Result<(ExitResult, GasedMachine<S, G>), ExitFatal>, I::Interrupt>>
) -> Result<(), Capture<Result<(ExitResult, GasedMachine<S, G>), ExitFatal>, I::Interrupt>>
where
F: Fn(&mut Machine<S>, &mut H, Opcode, usize) -> Control<Tr>,
{
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<F>(
&mut self,
etable: &Etable<S, H, Tr, F>,
) -> Result<(), Capture<Result<(ExitResult, GasedMachine<S, G>), ExitFatal>, I::Interrupt>>
where
F: Fn(&mut Machine<S>, &mut H, Opcode, usize) -> Control<Tr>,
{
self.step_with(etable, |machine, handler, etable| {
let result = machine.run(handler, etable);
LastSubstackStatus::Exited(result)
})
}

fn step_with<F, FS>(
&mut self,
etable: &Etable<S, H, Tr, F>,
fs: FS,
) -> Result<(), Capture<Result<(ExitResult, GasedMachine<S, G>), ExitFatal>, I::Interrupt>>
where
F: Fn(&mut Machine<S>, &mut H, Opcode, usize) -> Control<Tr>,
FS: Fn(&mut GasedMachine<S, G>, &mut H, &Etable<S, H, Tr, F>) -> LastSubstackStatus<Tr>,
{
let mut step_ret = None;

Expand All @@ -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)),
Expand Down Expand Up @@ -173,7 +201,10 @@ where
}
};

step_ret
match step_ret {
Some(res) => Err(res),
None => Ok(()),
}
}
}

Expand Down Expand Up @@ -274,19 +305,27 @@ where
})
}

pub fn step<F>(
fn step_with<F, FS>(
&mut self,
etable: &Etable<S, H, Tr, F>,
) -> Option<Capture<Result<I::TransactValue, ExitError>, I::Interrupt>>
fs: FS,
) -> Result<(), Capture<Result<I::TransactValue, ExitError>, I::Interrupt>>
where
F: Fn(&mut Machine<S>, &mut H, Opcode, usize) -> Control<Tr>,
FS: Fn(
&mut CallStack<S, G, H, Tr, I>,
&Etable<S, H, Tr, F>,
) -> Result<
(),
Capture<Result<(ExitResult, GasedMachine<S, G>), 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,
Expand All @@ -296,6 +335,26 @@ where
}
}

pub fn step_run<F>(
&mut self,
etable: &Etable<S, H, Tr, F>,
) -> Result<(), Capture<Result<I::TransactValue, ExitError>, I::Interrupt>>
where
F: Fn(&mut Machine<S>, &mut H, Opcode, usize) -> Control<Tr>,
{
self.step_with(etable, |call_stack, etable| call_stack.step_run(etable))
}

pub fn step<F>(
&mut self,
etable: &Etable<S, H, Tr, F>,
) -> Result<(), Capture<Result<I::TransactValue, ExitError>, I::Interrupt>>
where
F: Fn(&mut Machine<S>, &mut H, Opcode, usize) -> Control<Tr>,
{
self.step_with(etable, |call_stack, etable| call_stack.step(etable))
}

pub fn run<F>(
&mut self,
etable: &Etable<S, H, Tr, F>,
Expand All @@ -304,13 +363,20 @@ where
F: Fn(&mut Machine<S>, &mut H, Opcode, usize) -> Control<Tr>,
{
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<S, G>, 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>
Expand Down
32 changes: 31 additions & 1 deletion src/gasometer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,21 @@ impl Gas for u64 {}
impl Gas for U256 {}

pub trait Gasometer<S, H>: Sized {
fn record_step(
&mut self,
machine: &Machine<S>,
is_static: bool,
backend: &H,
) -> Result<(), ExitError>;
fn record_stepn(
&mut self,
machine: &Machine<S>,
is_static: bool,
backend: &H,
) -> Result<usize, ExitError>;
) -> Result<usize, ExitError> {
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<Self, ExitError>;
Expand All @@ -39,6 +48,27 @@ pub struct GasedMachine<S, G> {
}

impl<S: AsMut<RuntimeState>, G> GasedMachine<S, G> {
pub fn step<H, Tr, F>(
&mut self,
handler: &mut H,
etable: &Etable<S, H, Tr, F>,
) -> Result<(), Capture<ExitResult, Tr>>
where
F: Fn(&mut Machine<S>, &mut H, Opcode, usize) -> Control<Tr>,
G: Gasometer<S, H>,
{
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<H, Tr, F>(
&mut self,
handler: &mut H,
Expand Down
6 changes: 3 additions & 3 deletions src/standard/gasometer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,12 @@ impl<'config, S: AsRef<RuntimeState>> TransactGasometer<'config, S> for Gasomete
}

impl<'config, S: AsRef<RuntimeState>, H: RuntimeBackend> GasometerT<S, H> for Gasometer<'config> {
fn record_stepn(
fn record_step(
&mut self,
machine: &Machine<S>,
is_static: bool,
handler: &H,
) -> Result<usize, ExitError> {
) -> Result<(), ExitError> {
self.perform(|gasometer| {
let opcode = machine.peek_opcode().ok_or(ExitException::OutOfGas)?;

Expand Down Expand Up @@ -169,7 +169,7 @@ impl<'config, S: AsRef<RuntimeState>, H: RuntimeBackend> GasometerT<S, H> for Ga
gas.extra_check(after_gas, gasometer.config)?;
}

Ok(1)
Ok(())
})
}

Expand Down
1 change: 1 addition & 0 deletions src/standard/invoker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub struct TransactInvoke {
pub caller: H160,
}

#[derive(Clone, Debug)]
pub enum TransactArgs {
Call {
caller: H160,
Expand Down

0 comments on commit 539a07c

Please sign in to comment.