Skip to content

Commit

Permalink
Implement PrecompileSet trait (#227)
Browse files Browse the repository at this point in the history
  • Loading branch information
sorpaas authored Nov 22, 2023
1 parent 0e81a49 commit b2de609
Show file tree
Hide file tree
Showing 6 changed files with 355 additions and 135 deletions.
19 changes: 10 additions & 9 deletions jsontests/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use evm::backend::in_memory::{
};
use evm::standard::{Config, Etable, Gasometer, Invoker, TransactArgs};
use evm::utils::u256_to_h256;
use evm::{Capture, GasedMachine};
use evm::Capture;
use primitive_types::U256;
use std::collections::{BTreeMap, BTreeSet};

Expand Down Expand Up @@ -59,7 +59,7 @@ pub fn run_test(_filename: &str, _test_name: &str, test: Test, debug: bool) -> R
.collect::<BTreeMap<_, _>>();

let etable = Etable::runtime();
let invoker = Invoker::<_, Gasometer, _, _, _>::new(&config, &etable);
let invoker = Invoker::<_, Gasometer, _, (), _, _>::new(&config, &(), &etable);
let args = TransactArgs::Call {
caller: test.transaction.sender,
address: test.transaction.to,
Expand Down Expand Up @@ -101,13 +101,14 @@ pub fn run_test(_filename: &str, _test_name: &str, test: Test, debug: bool) -> R
let _step_result = evm::HeapTransact::new(args, &invoker, &mut step_backend).and_then(
|mut stepper| loop {
{
let machine: &GasedMachine<_, Gasometer> = stepper.last_machine()?;
println!(
"pc: {}, opcode: {:?}, gas: 0x{:x}",
machine.machine.position(),
machine.machine.peek_opcode(),
machine.gasometer.gas(),
);
if let Some(machine) = stepper.last_machine() {
println!(
"pc: {}, opcode: {:?}, gas: 0x{:x}",
machine.machine.position(),
machine.machine.peek_opcode(),
machine.gasometer.gas(),
);
}
}
if let Err(Capture::Exit(result)) = stepper.step() {
break result;
Expand Down
237 changes: 180 additions & 57 deletions src/call_stack.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{Capture, ExitError, ExitFatal, ExitResult, Invoker};
use crate::{Capture, ExitError, ExitFatal, ExitResult, Invoker, InvokerControl};
use core::convert::Infallible;

struct Substack<M, TrD> {
Expand Down Expand Up @@ -123,6 +123,7 @@ where
.pop()
.expect("checked stack is not empty above; qed");

let machine = self.invoker.deconstruct_machine(machine);
let feedback_result = self.invoker.exit_substack(
exit,
machine,
Expand Down Expand Up @@ -153,7 +154,7 @@ where
self.backend,
self.initial_depth + self.stack.len() + 1,
) {
Capture::Exit(Ok((trap_data, sub_machine))) => {
Capture::Exit(Ok((trap_data, InvokerControl::Enter(sub_machine)))) => {
self.stack.push(Substack {
invoke: trap_data,
machine,
Expand All @@ -164,6 +165,29 @@ where
machine: sub_machine,
})
}
Capture::Exit(Ok((
trap_data,
InvokerControl::DirectExit((exit, sub_machine)),
))) => {
let feedback_result = self.invoker.exit_substack(
exit,
sub_machine,
trap_data,
&mut machine,
self.backend,
);

match feedback_result {
Ok(()) => Some(LastSubstack {
status: LastSubstackStatus::Running,
machine,
}),
Err(err) => Some(LastSubstack {
machine,
status: LastSubstackStatus::Exited(Capture::Exit(Err(err))),
}),
}
}
Capture::Exit(Err(err)) => Some(LastSubstack {
status: LastSubstackStatus::Exited(Capture::Exit(Err(err))),
machine,
Expand Down Expand Up @@ -204,7 +228,7 @@ where
Capture::Exit(exit) => return Ok((exit, machine)),
Capture::Trap(trap) => {
match invoker.enter_substack(trap, &mut machine, backend, initial_depth + 1) {
Capture::Exit(Ok((trap_data, sub_machine))) => {
Capture::Exit(Ok((trap_data, InvokerControl::Enter(sub_machine)))) => {
let (sub_result, sub_machine) = if heap_depth
.map(|hd| initial_depth + 1 >= hd)
.unwrap_or(false)
Expand All @@ -219,6 +243,23 @@ where
execute(sub_machine, initial_depth + 1, heap_depth, backend, invoker)?
};

match invoker.exit_substack(
sub_result,
invoker.deconstruct_machine(sub_machine),
trap_data,
&mut machine,
backend,
) {
Ok(()) => {
result = invoker.run_machine(&mut machine, backend);
}
Err(err) => return Ok((Err(err), machine)),
}
}
Capture::Exit(Ok((
trap_data,
InvokerControl::DirectExit((sub_result, sub_machine)),
))) => {
match invoker.exit_substack(
sub_result,
sub_machine,
Expand All @@ -240,11 +281,22 @@ where
}
}

pub struct HeapTransact<'backend, 'invoker, H, Tr, I: Invoker<H, Tr>> {
call_stack: CallStack<'backend, 'invoker, H, Tr, I>,
transact_invoke: I::TransactInvoke,
enum HeapTransactState<'backend, 'invoker, H, Tr, I: Invoker<H, Tr>> {
Created {
args: I::TransactArgs,
invoker: &'invoker I,
backend: &'backend mut H,
},
Running {
call_stack: CallStack<'backend, 'invoker, H, Tr, I>,
transact_invoke: I::TransactInvoke,
},
}

pub struct HeapTransact<'backend, 'invoker, H, Tr, I: Invoker<H, Tr>>(
Option<HeapTransactState<'backend, 'invoker, H, Tr, I>>,
);

impl<'backend, 'invoker, H, Tr, I> HeapTransact<'backend, 'invoker, H, Tr, I>
where
I: Invoker<H, Tr>,
Expand All @@ -254,13 +306,11 @@ where
invoker: &'invoker I,
backend: &'backend mut H,
) -> Result<Self, ExitError> {
let (transact_invoke, machine) = invoker.new_transact(args, backend)?;
let call_stack = CallStack::new(machine, 0, backend, invoker);

Ok(Self {
transact_invoke,
call_stack,
})
Ok(Self(Some(HeapTransactState::Created {
args,
invoker,
backend,
})))
}

fn step_with<FS>(
Expand All @@ -269,22 +319,70 @@ where
) -> Result<(), Capture<Result<I::TransactValue, ExitError>, I::Interrupt>>
where
FS: Fn(
&mut CallStack<H, Tr, I>,
&mut CallStack<'backend, 'invoker, H, Tr, I>,
) -> Result<(), Capture<Result<(ExitResult, I::Machine), ExitFatal>, I::Interrupt>>,
{
match fs(&mut self.call_stack) {
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,
self.call_stack.backend,
)))
let ret;

self.0 = match self.0.take() {
Some(HeapTransactState::Running {
mut call_stack,
transact_invoke,
}) => {
ret = match fs(&mut call_stack) {
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)))) => {
let machine = call_stack.invoker.deconstruct_machine(machine);
Err(Capture::Exit(call_stack.invoker.finalize_transact(
&transact_invoke,
ret,
machine,
call_stack.backend,
)))
}
};

Some(HeapTransactState::Running {
call_stack,
transact_invoke,
})
}
}
Some(HeapTransactState::Created {
args,
invoker,
backend,
}) => {
let (transact_invoke, control) = match invoker.new_transact(args, backend) {
Ok((transact_invoke, control)) => (transact_invoke, control),
Err(err) => return Err(Capture::Exit(Err(err))),
};

match control {
InvokerControl::Enter(machine) => {
let call_stack = CallStack::new(machine, 0, backend, invoker);

ret = Ok(());
Some(HeapTransactState::Running {
call_stack,
transact_invoke,
})
}
InvokerControl::DirectExit((exit, machine)) => {
return Err(Capture::Exit(invoker.finalize_transact(
&transact_invoke,
exit,
machine,
backend,
)));
}
}
}
None => return Err(Capture::Exit(Err(ExitFatal::AlreadyExited.into()))),
};

ret
}

pub fn step_run(
Expand All @@ -309,10 +407,13 @@ where
}
}

pub fn last_machine(&self) -> Result<&I::Machine, ExitError> {
match &self.call_stack.last {
Some(last) => Ok(&last.machine),
None => Err(ExitFatal::AlreadyExited.into()),
pub fn last_machine(&self) -> Option<&I::Machine> {
match &self.0 {
Some(HeapTransactState::Running { call_stack, .. }) => match &call_stack.last {
Some(last) => Some(&last.machine),
None => None,
},
_ => None,
}
}
}
Expand All @@ -322,34 +423,47 @@ where
I: Invoker<H, Tr>,
{
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,
);
if let Some(state) = self.0.take() {
match state {
HeapTransactState::Running {
mut call_stack,
transact_invoke,
} => {
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 _ = call_stack.invoker.exit_substack(
ExitFatal::Unfinished.into(),
last_machine,
parent.invoke,
&mut parent.machine,
call_stack.backend,
);

last = LastSubstack {
machine: parent.machine,
status: LastSubstackStatus::Exited(Capture::Exit(
ExitFatal::Unfinished.into(),
)),
};
} else {
break;
}
}

last = LastSubstack {
machine: parent.machine,
status: LastSubstackStatus::Exited(Capture::Exit(
let last_machine = call_stack.invoker.deconstruct_machine(last.machine);
let _ = call_stack.invoker.finalize_transact(
&transact_invoke,
ExitFatal::Unfinished.into(),
)),
};
} else {
break;
last_machine,
call_stack.backend,
);
}
}
_ => (),
}

let _ = self.call_stack.invoker.finalize_transact(
&self.transact_invoke,
ExitFatal::Unfinished.into(),
last.machine,
self.call_stack.backend,
);
}
}
}
Expand All @@ -363,7 +477,16 @@ pub fn transact<H, Tr, I>(
where
I: Invoker<H, Tr, Interrupt = Infallible>,
{
let (transact_invoke, machine) = invoker.new_transact(args, backend)?;
let (ret, machine) = execute(machine, 0, heap_depth, backend, invoker)?;
invoker.finalize_transact(&transact_invoke, ret, machine, backend)
let (transact_invoke, control) = invoker.new_transact(args, backend)?;

match control {
InvokerControl::Enter(machine) => {
let (ret, machine) = execute(machine, 0, heap_depth, backend, invoker)?;
let machine = invoker.deconstruct_machine(machine);
invoker.finalize_transact(&transact_invoke, ret, machine, backend)
}
InvokerControl::DirectExit((exit, machine)) => {
invoker.finalize_transact(&transact_invoke, exit, machine, backend)
}
}
}
Loading

0 comments on commit b2de609

Please sign in to comment.