Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement colored machine #235

Merged
merged 2 commits into from
Nov 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions jsontests/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

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

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,
Expand Down
103 changes: 34 additions & 69 deletions precompiles/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -40,86 +40,51 @@ pub trait PurePrecompile<G> {
) -> (ExitResult, Vec<u8>);
}

pub enum StandardPrecompile {
ECRecover,
Sha256,
Ripemd160,
Identity,
Modexp,
Bn128Add,
Bn128Mul,
Bn128Pairing,
Blake2F,
}

impl<S: AsRef<RuntimeState>, G: StaticGasometer, H> Precompile<S, G, H> for StandardPrecompile {
fn execute(
&self,
input: &[u8],
state: S,
mut gasometer: G,
_handler: &mut H,
) -> (ExitResult, (S, G, Vec<u8>)) {
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<RuntimeState>, G: StaticGasometer, H: RuntimeBackend> CodeResolver<S, G, H>
for StandardResolver<'config>
impl<'config, S: AsRef<RuntimeState>, G: StaticGasometer, H> PrecompileSet<S, G, H>
for StandardPrecompileSet<'config>
{
type Precompile = StandardPrecompile;

fn resolve(
fn execute(
&self,
addr: H160,
_gasometer: &mut G,
handler: &mut H,
) -> Result<ResolvedCode<Self::Precompile>, ExitError> {
code_address: H160,
input: &[u8],
_is_static: bool,
state: &mut S,
gasometer: &mut G,
_handler: &mut H,
) -> Option<(ExitResult, Vec<u8>)> {
// 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
}
}
}

Expand Down
33 changes: 16 additions & 17 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, InvokerControl};
use crate::{Capture, ExitError, ExitFatal, ExitResult, Invoker, InvokerControl, InvokerMachine};
use core::convert::Infallible;

struct Substack<M, TrD> {
Expand Down Expand Up @@ -64,8 +64,8 @@ where
pub fn step(
&mut self,
) -> Result<(), Capture<Result<(ExitResult, I::Machine), ExitFatal>, 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),
Expand All @@ -76,8 +76,8 @@ where
pub fn step_run(
&mut self,
) -> Result<(), Capture<Result<(ExitResult, I::Machine), ExitFatal>, 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)
})
}
Expand All @@ -87,7 +87,7 @@ where
fs: FS,
) -> Result<(), Capture<Result<(ExitResult, I::Machine), ExitFatal>, I::Interrupt>>
where
FS: Fn(&I, &mut I::Machine, &mut H) -> LastSubstackStatus<Tr>,
FS: Fn(&mut I::Machine, &mut H) -> LastSubstackStatus<Tr>,
{
let mut step_ret = None;

Expand All @@ -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 {
Expand All @@ -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,
Expand Down Expand Up @@ -221,7 +221,7 @@ fn execute<H, Tr, I>(
where
I: Invoker<H, Tr, Interrupt = Infallible>,
{
let mut result = invoker.run_machine(&mut machine, backend);
let mut result = machine.run(backend);

loop {
match result {
Expand All @@ -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)),
}
Expand All @@ -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)),
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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(),
Expand Down Expand Up @@ -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)) => {
Expand Down
101 changes: 101 additions & 0 deletions src/color.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use crate::{
Capture, Control, Etable, ExitResult, Gasometer, InvokerMachine, Machine, Opcode, RuntimeState,
};

pub struct ColoredMachine<S, G, C> {
pub machine: Machine<S>,
pub gasometer: G,
pub is_static: bool,
pub color: C,
}

impl<S, G, H, C, Tr> InvokerMachine<H, Tr> for ColoredMachine<S, G, C>
where
C: Color<S, G, H, Tr>,
{
type Deconstruct = (S, G, Vec<u8>);

fn step(&mut self, handler: &mut H) -> Result<(), Capture<ExitResult, Tr>> {
self.color.step(
&mut self.machine,
&mut self.gasometer,
self.is_static,
handler,
)
}

fn run(&mut self, handler: &mut H) -> Capture<ExitResult, Tr> {
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<S, G, H, Tr> {
fn step(
&self,
machine: &mut Machine<S>,
gasometer: &mut G,
is_static: bool,
handler: &mut H,
) -> Result<(), Capture<ExitResult, Tr>>;

fn run(
&self,
machine: &mut Machine<S>,
gasometer: &mut G,
is_static: bool,
handler: &mut H,
) -> Capture<ExitResult, Tr>;
}

impl<'etable, S, G, H, Tr, F> Color<S, G, H, Tr> for &'etable Etable<S, H, Tr, F>
where
S: AsMut<RuntimeState>,
G: Gasometer<S, H>,
F: Fn(&mut Machine<S>, &mut H, Opcode, usize) -> Control<Tr>,
{
fn step(
&self,
machine: &mut Machine<S>,
gasometer: &mut G,
is_static: bool,
handler: &mut H,
) -> Result<(), Capture<ExitResult, Tr>> {
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<S>,
gasometer: &mut G,
is_static: bool,
handler: &mut H,
) -> Capture<ExitResult, Tr> {
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)),
}
}
}
}
Loading