Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into breaking-changes
Browse files Browse the repository at this point in the history
  • Loading branch information
shekhirin committed Feb 29, 2024
2 parents d2f9c4f + 7d6fb37 commit d47171b
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 19 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ members = [
"examples/rpc-db/",
"examples/trace-transaction-cli/",
"examples/polygon-p2p/",
"examples/custom-inspector/",
"testing/ef-tests/",
]
default-members = ["bin/reth"]
Expand Down
2 changes: 1 addition & 1 deletion bin/reth/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ impl<DB: Database + DatabaseMetrics + DatabaseMetadata + 'static> NodeBuilderWit
network.event_listener().map(Into::into),
beacon_engine_handle.event_listener().map(Into::into),
pipeline_events.map(Into::into),
if self.config.debug.tip.is_none() {
if self.config.debug.tip.is_none() && !self.config.dev.dev {
Either::Left(
ConsensusLayerHealthEvents::new(Box::new(blockchain_db.clone()))
.map(Into::into),
Expand Down
2 changes: 1 addition & 1 deletion crates/node-builder/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ where
network.event_listener().map(Into::into),
beacon_engine_handle.event_listener().map(Into::into),
pipeline_events.map(Into::into),
if config.debug.tip.is_none() {
if config.debug.tip.is_none() && !config.dev.dev {
Either::Left(
ConsensusLayerHealthEvents::new(Box::new(blockchain_db.clone()))
.map(Into::into),
Expand Down
35 changes: 18 additions & 17 deletions crates/storage/provider/src/providers/database/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,21 +61,6 @@ impl<DB> ProviderFactory<DB> {
})
}

/// Create new database provider by passing a path. [`ProviderFactory`] will own the database
/// instance.
pub fn new_with_database_path<P: AsRef<Path>>(
path: P,
chain_spec: Arc<ChainSpec>,
args: DatabaseArguments,
static_files_path: PathBuf,
) -> RethResult<ProviderFactory<DatabaseEnv>> {
Ok(ProviderFactory::<DatabaseEnv> {
db: init_db(path, args).map_err(|e| RethError::Custom(e.to_string()))?,
chain_spec,
static_file_provider: StaticFileProvider::new(static_files_path)?,
})
}

/// Enables metrics on the static file provider.
pub fn with_static_files_metrics(mut self) -> Self {
self.static_file_provider = self.static_file_provider.with_metrics();
Expand All @@ -99,6 +84,23 @@ impl<DB> ProviderFactory<DB> {
}
}

impl ProviderFactory<DatabaseEnv> {
/// Create new database provider by passing a path. [`ProviderFactory`] will own the database
/// instance.
pub fn new_with_database_path<P: AsRef<Path>>(
path: P,
chain_spec: Arc<ChainSpec>,
args: DatabaseArguments,
static_files_path: PathBuf,
) -> RethResult<Self> {
Ok(ProviderFactory::<DatabaseEnv> {
db: init_db(path, args).map_err(|e| RethError::Custom(e.to_string()))?,
chain_spec,
static_file_provider: StaticFileProvider::new(static_files_path)?,
})
}
}

impl<DB: Database> ProviderFactory<DB> {
/// Returns a provider with a created `DbTx` inside, which allows fetching data from the
/// database using different types of providers. Example: [`HeaderProvider`]
Expand Down Expand Up @@ -607,7 +609,6 @@ mod tests {
use reth_db::{
tables,
test_utils::{create_test_static_files_dir, ERROR_TEMPDIR},
DatabaseEnv,
};
use reth_interfaces::{
provider::ProviderError,
Expand Down Expand Up @@ -653,7 +654,7 @@ mod tests {
#[test]
fn provider_factory_with_database_path() {
let chain_spec = ChainSpecBuilder::mainnet().build();
let factory = ProviderFactory::<DatabaseEnv>::new_with_database_path(
let factory = ProviderFactory::new_with_database_path(
tempfile::TempDir::new().expect(ERROR_TEMPDIR).into_path(),
Arc::new(chain_spec),
Default::default(),
Expand Down
12 changes: 12 additions & 0 deletions examples/custom-inspector/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "custom-inspector"
version = "0.0.0"
publish = false
edition.workspace = true
license.workspace = true

[dependencies]
reth.workspace = true
clap = { workspace = true, features = ["derive"] }
futures-util.workspace = true
eyre.workspace = true
149 changes: 149 additions & 0 deletions examples/custom-inspector/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
//! Example of how to use a custom inspector to trace new pending transactions
//!
//! Run with
//!
//! ```not_rust
//! cargo run --release -p custom-inspector --node --http --ws --recipients 0x....,0x....
//! ```
//!
//! If no recipients are specified, all transactions will be inspected.
#![warn(unused_crate_dependencies)]

use clap::Parser;
use futures_util::stream::StreamExt;
use reth::{
cli::{
components::{RethNodeComponents, RethRpcComponents, RethRpcServerHandles},
config::RethRpcConfig,
ext::{RethCliExt, RethNodeCommandConfig},
Cli,
},
primitives::{Address, BlockId, IntoRecoveredTransaction},
revm::{
inspector_handle_register,
interpreter::{Interpreter, OpCode},
Database, Evm, EvmContext, Inspector,
},
rpc::{
compat::transaction::transaction_to_call_request,
eth::{revm_utils::EvmOverrides, EthTransactions},
},
tasks::TaskSpawner,
transaction_pool::TransactionPool,
};
use std::collections::HashSet;

fn main() {
Cli::<MyRethCliExt>::parse().run().unwrap();
}

/// The type that tells the reth CLI what extensions to use
struct MyRethCliExt;

impl RethCliExt for MyRethCliExt {
/// This tells the reth CLI to trace addresses via `RethCliTxpoolExt`
type Node = RethCliTxpoolExt;
}

/// Our custom cli args extension that adds one flag to reth default CLI.
#[derive(Debug, Clone, Default, clap::Args)]
struct RethCliTxpoolExt {
/// The addresses of the recipients that we want to trace.
#[arg(long, value_delimiter = ',')]
pub recipients: Vec<Address>,
}

/// A dummy inspector that logs the opcodes and their corresponding program counter for a
/// transaction
#[derive(Default, Debug, Clone)]
struct DummyInspector {
ret_val: Vec<String>,
}

impl<DB> Inspector<DB> for DummyInspector
where
DB: Database,
{
/// This method is called at each step of the EVM execution.
/// It checks if the current opcode is valid and if so, it stores the opcode and its
/// corresponding program counter in the `ret_val` vector.
fn step(&mut self, interp: &mut Interpreter, _context: &mut EvmContext<DB>) {
if let Some(opcode) = OpCode::new(interp.current_opcode()) {
self.ret_val.push(format!("{}: {}", interp.program_counter(), opcode));
}
}
}

impl RethNodeCommandConfig for RethCliTxpoolExt {
/// Sets up a subscription to listen for new pending transactions and traces them.
/// If the transaction is from one of the specified recipients, it will be traced.
/// If no recipients are specified, all transactions will be traced.
fn on_rpc_server_started<Conf, Reth>(
&mut self,
_config: &Conf,
components: &Reth,
rpc_components: RethRpcComponents<'_, Reth>,
_handles: RethRpcServerHandles,
) -> eyre::Result<()>
where
Conf: RethRpcConfig,
Reth: RethNodeComponents,
{
let recipients = self.recipients.iter().copied().collect::<HashSet<_>>();

// create a new subscription to pending transactions
let mut pending_transactions = components.pool().new_pending_pool_transactions_listener();

let eth_api = rpc_components.registry.eth_api();

println!("Spawning trace task!");
// Spawn an async block to listen for transactions.
components.task_executor().spawn(Box::pin(async move {
// Waiting for new transactions
while let Some(event) = pending_transactions.next().await {
let tx = event.transaction;
println!("Transaction received: {tx:?}");

if recipients.is_empty() {
// convert the pool transaction
let call_request = transaction_to_call_request(tx.to_recovered_transaction());

let result = eth_api
.spawn_with_call_at(
call_request,
BlockId::default(),
EvmOverrides::default(),
move |db, env| {
let mut dummy_inspector = DummyInspector::default();
{
// configure the evm with the custom inspector
let mut evm = Evm::builder()
.with_db(db)
.with_external_context(&mut dummy_inspector)
.with_env_with_handler_cfg(env)
.append_handler_register(inspector_handle_register)
.build();
// execute the transaction on a blocking task and await the
// inspector result
let _ = evm.transact()?;
}
Ok(dummy_inspector)
},
)
.await;

if let Ok(ret_val) = result {
let hash = tx.hash();
println!(
"Inspector result for transaction {}: \n {}",
hash,
ret_val.ret_val.join("\n")
);
}
}
}
}));
Ok(())
}
}

0 comments on commit d47171b

Please sign in to comment.