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

feat: tracing in Rethnet using JS callbacks #3593

Merged
merged 35 commits into from
Feb 21, 2023
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
8c1ea6f
Boilerplate for rethnet tracing callbacks
fvictorio Dec 28, 2022
f5d6b77
feat: tracing with js callbacks
Wodann Jan 12, 2023
16cd70e
fix: incorrect return type
Wodann Jan 16, 2023
67ff7b9
fix: use data from start of step
Wodann Jan 17, 2023
3357996
Use correct callback in unsafe block
fvictorio Jan 17, 2023
797de52
Temporary fix in inspector
fvictorio Jan 17, 2023
79a9370
Move vm tracer inside vm adapter
fvictorio Jan 17, 2023
2fdcde2
Merge branch 'rethnet/main' into rethnet/ts-tracing
fvictorio Jan 18, 2023
14244b5
improvement: fix napi creation and validate traces
Wodann Jan 18, 2023
dffdcf6
Add console.logs showing rethnet results discrepancy
fvictorio Jan 19, 2023
e590912
fix: handle multiple layers of calls in traces
Wodann Jan 20, 2023
b40d009
improvement: update to latest revm
Wodann Jan 18, 2023
6881a18
improvement: throw error when using forking with Rethnet
Wodann Jan 25, 2023
5956096
fix: bug fix in revm
Wodann Jan 25, 2023
fd03cc9
Use proper block number when mining a tx
fvictorio Jan 25, 2023
fdd09cb
Add CREATE_COLLISION and STATIC_STATE_CHANGE exit codes
fvictorio Jan 25, 2023
6b8bf9d
Merge remote-tracking branch 'upstream/rethnet/main' into rethnet/ts-…
Wodann Jan 26, 2023
e3fcbeb
bump: revm to incorporate bug fixes
Wodann Jan 26, 2023
3491291
Fix stack traces tests setup
fvictorio Jan 26, 2023
b4c23ad
Remove ethJsOnly logic
fvictorio Jan 26, 2023
2496df2
Get contract code in message trace
fvictorio Jan 26, 2023
757e72d
Merge remote-tracking branch 'upstream/rethnet/ts-tracing' into rethn…
Wodann Jan 28, 2023
8df8ed0
chore: split rethnet_evm_napi into separate files
Wodann Jan 28, 2023
be2eb49
docs: add documentation to blockchain, runtime, and state NAPI bindings
Wodann Jan 28, 2023
9fdcc02
Merge remote-tracking branch 'upstream/rethnet/ts-tracing' into rethn…
Wodann Feb 1, 2023
18c275c
WIP: fix stack traces
Wodann Feb 7, 2023
faf7e5d
fix: allow stack traces with no steps
Wodann Feb 7, 2023
e6690e8
fix: revert supposed fix
Wodann Feb 7, 2023
f79c3cc
fix: miscellaneous
Wodann Feb 8, 2023
71b599e
fix: remaining rethnet test failure
Wodann Feb 8, 2023
ee7f8ac
test: skip pre-byzantium test
Wodann Feb 8, 2023
6132136
fix: returned InstructionResult in JsTracer
Wodann Feb 8, 2023
0d36449
fix: revert ExitCode changes
Wodann Feb 8, 2023
114a951
fix: discrepancy between trace and execution exit codes
Wodann Feb 10, 2023
6ddf132
bump: upgrade to latest revm
Wodann Feb 14, 2023
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
2 changes: 1 addition & 1 deletion crates/rethnet_eth/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ hex-literal = { version = "0.3", default-features = false }
open-fastrlp = { version = "0.1.2", default-features = false, features = ["derive"], optional = true }
primitive-types = { version = "0.11.1", default-features = false, features = ["rlp"] }
reqwest = { version = "0.11", features = ["blocking", "json"] }
revm = { git = "https://github.com/wodann/revm", rev = "7c28358", version = "2.3", default-features = false, features = ["k256"] }
revm = { git = "https://github.com/wodann/revm", rev = "d7286a1", version = "2.3", default-features = false, features = ["dev", "serde"] }
rlp = { version = "0.5.2", default-features = false, features = ["derive"] }
ruint = { version = "1.7.0", default-features = false }
secp256k1 = { version = "0.24.0", default-features = false, features = ["alloc", "recovery"] }
Expand Down
2 changes: 1 addition & 1 deletion crates/rethnet_evm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ hashbrown = { version = "0.13", default-features = false, features = ["ahash", "
log = { version = "0.4.17", default-features = false }
parking_lot = { version = "0.12.1", default-features = false }
rethnet_eth = { version = "0.1.0-dev", path = "../rethnet_eth" }
revm = { git = "https://github.com/wodann/revm", rev = "7c28358", version = "2.3", default-features = false, features = ["dev", "k256", "with-serde"] }
revm = { git = "https://github.com/wodann/revm", rev = "d7286a1", version = "2.3", default-features = false, features = ["dev", "serde", "std"] }
secp256k1 = { version = "0.24.1", default-features = false, features = ["alloc"] }
sha3 = { version = "0.10.4", default-features = false }
signature = { version = "1.6.4", default-features = false, features = ["std"] }
Expand Down
8 changes: 4 additions & 4 deletions crates/rethnet_evm/src/block/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use revm::{BlockEnv, CfgEnv, ExecutionResult, SpecId, TxEnv};
use tokio::runtime::Runtime;

use crate::{
blockchain::AsyncBlockchain, db::AsyncDatabase, evm::build_evm, inspector::RethnetInspector,
blockchain::AsyncBlockchain, evm::build_evm, inspector::RethnetInspector, state::AsyncState,
trace::Trace, HeaderData,
};

Expand All @@ -19,7 +19,7 @@ where
E: Debug + Send + 'static,
{
blockchain: Arc<AsyncBlockchain<E>>,
state: Arc<AsyncDatabase<E>>,
state: Arc<AsyncState<E>>,
header: PartialHeader,
transactions: Vec<TxEnv>,
cfg: CfgEnv,
Expand All @@ -32,7 +32,7 @@ where
/// Creates an intance of [`BlockBuilder`], creating a checkpoint in the process.
pub async fn new(
blockchain: Arc<AsyncBlockchain<E>>,
db: Arc<AsyncDatabase<E>>,
db: Arc<AsyncState<E>>,
cfg: CfgEnv,
parent: Header,
header: HeaderData,
Expand Down Expand Up @@ -113,7 +113,7 @@ where
.state
.runtime()
.spawn(async move {
let mut evm = build_evm(&blockchain, &db, cfg, transaction, block);
let mut evm = build_evm(blockchain, db, cfg, transaction, block);

let mut inspector = RethnetInspector::default();
let (result, state) = evm.inspect(&mut inspector);
Expand Down
4 changes: 2 additions & 2 deletions crates/rethnet_evm/src/blockchain/request.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::fmt::Debug;

use rethnet_eth::{B256, U256};
use revm::blockchain::Blockchain;
use revm::BlockHash;
use tokio::sync::oneshot;

/// The request type used internally by a [`SyncDatabase`].
Expand All @@ -28,7 +28,7 @@ where
{
pub fn handle<D>(self, db: &mut D) -> bool
where
D: Blockchain<Error = E>,
D: BlockHash<Error = E>,
{
match self {
Request::BlockHashByNumber { number, sender } => {
Expand Down
10 changes: 5 additions & 5 deletions crates/rethnet_evm/src/blockchain/sync.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{fmt::Debug, io};

use rethnet_eth::{B256, U256};
use revm::blockchain::Blockchain;
use revm::{BlockHash, BlockHashRef};
use tokio::{
runtime::{Builder, Runtime},
sync::{
Expand All @@ -14,15 +14,15 @@ use tokio::{
use super::request::Request;

/// Trait that meets all requirements for a synchronous database that can be used by [`AsyncBlockchain`].
pub trait SyncBlockchain<E>: Blockchain<Error = E> + Send + Sync + 'static
pub trait SyncBlockchain<E>: BlockHash<Error = E> + Send + Sync + 'static
where
E: Debug + Send,
{
}

impl<B, E> SyncBlockchain<E> for B
where
B: Blockchain<Error = E> + Send + Sync + 'static,
B: BlockHash<Error = E> + Send + Sync + 'static,
E: Debug + Send,
{
}
Expand Down Expand Up @@ -111,13 +111,13 @@ where
}
}

impl<'b, E> Blockchain for &'b AsyncBlockchain<E>
impl<E> BlockHashRef for AsyncBlockchain<E>
where
E: Debug + Send + 'static,
{
type Error = E;

fn block_hash(&mut self, number: U256) -> Result<B256, Self::Error> {
fn block_hash(&self, number: U256) -> Result<B256, Self::Error> {
task::block_in_place(move || self.runtime.block_on(self.block_hash_by_number(number)))
}
}
17 changes: 8 additions & 9 deletions crates/rethnet_evm/src/evm.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
use std::fmt::Debug;
use std::{fmt::Debug, sync::Arc};

use revm::{BlockEnv, CfgEnv, TxEnv};
use revm::{db::DatabaseComponents, BlockEnv, CfgEnv, TxEnv};

use crate::{blockchain::AsyncBlockchain, db::AsyncDatabase};
use crate::{blockchain::AsyncBlockchain, state::AsyncState};

/// Creates an evm from the provided database, config, transaction, and block.
#[allow(clippy::type_complexity)]
pub fn build_evm<'b, 'd, E>(
blockchain: &'b AsyncBlockchain<E>,
db: &'d AsyncDatabase<E>,
pub fn build_evm<E>(
block_hash: Arc<AsyncBlockchain<E>>,
state: Arc<AsyncState<E>>,
cfg: CfgEnv,
transaction: TxEnv,
block: BlockEnv,
) -> revm::EVM<&'d AsyncDatabase<E>, &'b AsyncBlockchain<E>>
) -> revm::EVM<DatabaseComponents<Arc<AsyncBlockchain<E>>, Arc<AsyncState<E>>>>
where
E: Debug + Send + 'static,
{
let mut evm = revm::EVM::new();
evm.set_blockchain(blockchain);
evm.database(db);
evm.database(DatabaseComponents { block_hash, state });
evm.env.cfg = cfg;
evm.env.block = block;
evm.env.tx = transaction;
Expand Down
9 changes: 4 additions & 5 deletions crates/rethnet_evm/src/inspector.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use revm::{blockchain::Blockchain, opcode, Database, EVMData, Inspector, Interpreter, Return};
use revm::{opcode, Database, EVMData, Inspector, Interpreter, Return};

use crate::trace::Trace;

Expand All @@ -15,15 +15,14 @@ impl RethnetInspector {
}
}

impl<D, BC> Inspector<D, BC> for RethnetInspector
impl<D> Inspector<D> for RethnetInspector
where
D: Database,
BC: Blockchain<Error = D::Error>,
{
fn step(
&mut self,
interp: &mut Interpreter,
_data: &mut EVMData<'_, D, BC>,
_data: &mut EVMData<'_, D>,
_is_static: bool,
) -> Return {
self.opcode_stack.push(interp.current_opcode());
Expand All @@ -34,7 +33,7 @@ where
fn step_end(
&mut self,
interp: &mut Interpreter,
_data: &mut EVMData<'_, D, BC>,
_data: &mut EVMData<'_, D>,
_is_static: bool,
exit_code: Return,
) -> Return {
Expand Down
12 changes: 6 additions & 6 deletions crates/rethnet_evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ use rethnet_eth::Address;

pub use hashbrown::HashMap;
pub use revm::{
blockchain::{Blockchain, BlockchainRef},
db::EmptyDB,
Account, AccountInfo, BlockEnv, Bytecode, CfgEnv, CreateScheme, Database, DatabaseCommit,
ExecutionResult, Log, Return, SpecId, TransactOut, TransactTo, TxEnv, EVM,
db::DatabaseComponents, Account, AccountInfo, BlockEnv, BlockHash, BlockHashRef, Bytecode,
CallInputs, CfgEnv, CreateInputs, CreateScheme, Database, EVMData, ExecutionResult, Gas,
Inspector, Interpreter, Log, Return, SpecId, State as StateMut, StateCommit, StateRef,
TransactOut, TransactTo, TxEnv, EVM, OPCODE_JUMPMAP,
};

pub use crate::{
block::{BlockBuilder, HeaderData},
debug::DatabaseDebug,
runtime::Rethnet,
runtime::{AsyncDatabase, Rethnet},
transaction::PendingTransaction,
};

Expand All @@ -28,7 +28,7 @@ pub type State = HashMap<Address, Account>;
pub mod blockchain;

/// Database types for managing Ethereum state
pub mod db;
pub mod state;

/// Types used for tracing EVM calls
pub mod trace;
Expand Down
48 changes: 31 additions & 17 deletions crates/rethnet_evm/src/runtime.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
use std::{fmt::Debug, sync::Arc};

use revm::{BlockEnv, CfgEnv, ExecutionResult, SpecId, TxEnv};
use revm::{db::DatabaseComponents, BlockEnv, CfgEnv, ExecutionResult, Inspector, SpecId, TxEnv};

use crate::{
blockchain::AsyncBlockchain, db::AsyncDatabase, evm::build_evm, inspector::RethnetInspector,
blockchain::AsyncBlockchain, evm::build_evm, inspector::RethnetInspector, state::AsyncState,
trace::Trace, transaction::TransactionError, State,
};

/// Asynchronous implementation of the Database super-trait
pub type AsyncDatabase<E> = DatabaseComponents<Arc<AsyncBlockchain<E>>, Arc<AsyncState<E>>>;

/// The asynchronous Rethnet runtime.
pub struct Rethnet<E>
where
E: Debug + Send + 'static,
{
blockchain: Arc<AsyncBlockchain<E>>,
db: Arc<AsyncDatabase<E>>,
db: Arc<AsyncState<E>>,
cfg: CfgEnv,
}

Expand All @@ -22,11 +25,7 @@ where
E: Debug + Send + 'static,
{
/// Constructs a new [`Rethnet`] instance.
pub fn new(
blockchain: Arc<AsyncBlockchain<E>>,
db: Arc<AsyncDatabase<E>>,
cfg: CfgEnv,
) -> Self {
pub fn new(blockchain: Arc<AsyncBlockchain<E>>, db: Arc<AsyncState<E>>, cfg: CfgEnv) -> Self {
Self {
blockchain,
db,
Expand All @@ -39,6 +38,7 @@ where
&self,
transaction: TxEnv,
block: BlockEnv,
inspector: Option<Box<dyn Inspector<AsyncDatabase<E>> + Send>>,
) -> Result<(ExecutionResult, State, Trace), TransactionError> {
if self.cfg.spec_id > SpecId::MERGE && block.prevrandao.is_none() {
return Err(TransactionError::MissingPrevrandao);
Expand All @@ -52,11 +52,17 @@ where
.db
.runtime()
.spawn(async move {
let mut evm = build_evm(&blockchain, &db, cfg, transaction, block);
let mut evm = build_evm(blockchain, db, cfg, transaction, block);

if let Some(mut inspector) = inspector {
let (result, state) = evm.inspect(&mut inspector);
(result, state, Trace::default())
} else {
let mut inspector = RethnetInspector::default();
let (result, state) = evm.inspect(&mut inspector);

let mut inspector = RethnetInspector::default();
let (result, state) = evm.inspect(&mut inspector);
(result, state, inspector.into_trace())
(result, state, inspector.into_trace())
}
})
.await
.unwrap())
Expand All @@ -67,6 +73,7 @@ where
&self,
transaction: TxEnv,
block: BlockEnv,
inspector: Option<Box<dyn Inspector<AsyncDatabase<E>> + Send>>,
) -> Result<(ExecutionResult, State, Trace), TransactionError> {
if self.cfg.spec_id > SpecId::MERGE && block.prevrandao.is_none() {
return Err(TransactionError::MissingPrevrandao);
Expand All @@ -82,11 +89,17 @@ where
.db
.runtime()
.spawn(async move {
let mut evm = build_evm(&blockchain, &db, cfg, transaction, block);
let mut evm = build_evm(blockchain, db, cfg, transaction, block);

if let Some(mut inspector) = inspector {
let (result, state) = evm.inspect(&mut inspector);
(result, state, Trace::default())
} else {
let mut inspector = RethnetInspector::default();
let (result, state) = evm.inspect(&mut inspector);

let mut inspector = RethnetInspector::default();
let (result, state) = evm.inspect(&mut inspector);
(result, state, inspector.into_trace())
(result, state, inspector.into_trace())
}
})
.await
.unwrap())
Expand All @@ -97,8 +110,9 @@ where
&self,
transaction: TxEnv,
block: BlockEnv,
inspector: Option<Box<dyn Inspector<AsyncDatabase<E>> + Send>>,
) -> Result<(ExecutionResult, Trace), TransactionError> {
let (result, changes, trace) = self.dry_run(transaction, block).await?;
let (result, changes, trace) = self.dry_run(transaction, block, inspector).await?;

self.db.apply(changes).await;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ mod layered_db;
mod request;
mod sync;

pub use sync::{AsyncDatabase, SyncDatabase};
pub use sync::{AsyncState, SyncState};

pub use layered_db::{LayeredDatabase, RethnetLayer};
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use rethnet_eth::{
trie::KECCAK_NULL_RLP,
Address, B256, U256,
};
use revm::{Account, AccountInfo, Bytecode, Database, DatabaseCommit, KECCAK_EMPTY};
use revm::{Account, AccountInfo, Bytecode, State, StateCommit, KECCAK_EMPTY};

use crate::DatabaseDebug;

Expand Down Expand Up @@ -237,7 +237,7 @@ impl LayeredDatabase<RethnetLayer> {
}
}

impl Database for LayeredDatabase<RethnetLayer> {
impl State for LayeredDatabase<RethnetLayer> {
type Error = anyhow::Error;

fn basic(&mut self, address: Address) -> anyhow::Result<Option<AccountInfo>> {
Expand Down Expand Up @@ -284,7 +284,7 @@ impl Database for LayeredDatabase<RethnetLayer> {
}
}

impl DatabaseCommit for LayeredDatabase<RethnetLayer> {
impl StateCommit for LayeredDatabase<RethnetLayer> {
fn commit(&mut self, changes: HashMap<Address, Account>) {
changes.into_iter().for_each(|(address, account)| {
if account.is_empty() || account.is_destroyed {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::fmt::Debug;

use hashbrown::HashMap;
use rethnet_eth::{Address, B256, U256};
use revm::{Account, AccountInfo, Bytecode, Database, DatabaseCommit};
use revm::{Account, AccountInfo, Bytecode, State, StateCommit};
use tokio::sync::oneshot;

use crate::{debug::ModifierFn, DatabaseDebug};
Expand Down Expand Up @@ -82,7 +82,7 @@ where
{
pub fn handle<D>(self, db: &mut D) -> bool
where
D: Database<Error = E> + DatabaseCommit + DatabaseDebug<Error = E>,
D: State<Error = E> + StateCommit + DatabaseDebug<Error = E>,
{
match self {
Request::AccountByAddress { address, sender } => {
Expand Down
Loading