Skip to content

Commit

Permalink
example simulation transportless (paradigmxyz#5025)
Browse files Browse the repository at this point in the history
Co-authored-by: Matthias Seitz <[email protected]>
  • Loading branch information
supernovahs and mattsse authored Oct 17, 2023
1 parent ede8278 commit 1483175
Show file tree
Hide file tree
Showing 11 changed files with 208 additions and 5 deletions.
12 changes: 12 additions & 0 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ members = [
"examples/cli-extension-event-hooks",
"examples/rpc-db",
"examples/manual-p2p",
"examples/trace-transaction-cli"
]
default-members = ["bin/reth"]

Expand Down Expand Up @@ -107,7 +108,6 @@ reth-discv4 = { path = "./crates/net/discv4" }
reth-eth-wire = { path = "./crates/net/eth-wire" }
reth-ecies = { path = "./crates/net/ecies" }
reth-tracing = { path = "./crates/tracing" }

# revm
revm = "3.5.0"
revm-primitives = "1.3.0"
Expand Down
2 changes: 1 addition & 1 deletion crates/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub mod snapshot;
pub mod stage;
mod storage;
/// Helpers for working with transactions
mod transaction;
pub mod transaction;
pub mod trie;
mod withdrawal;

Expand Down
15 changes: 15 additions & 0 deletions crates/primitives/src/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,21 @@ impl Transaction {
}
}

/// Blob versioned hashes for eip4844 transaction, for legacy,eip1559 and eip2930 transactions
/// this is `None`
///
/// This is also commonly referred to as the "blob versioned hashes" (`BlobVersionedHashes`).
pub fn blob_versioned_hashes(&self) -> Option<Vec<B256>> {
match self {
Transaction::Legacy(_) => None,
Transaction::Eip2930(_) => None,
Transaction::Eip1559(_) => None,
Transaction::Eip4844(TxEip4844 { blob_versioned_hashes, .. }) => {
Some(blob_versioned_hashes.to_vec())
}
}
}

/// Max fee per blob gas for eip4844 transaction [TxEip4844].
///
/// Returns `None` for non-eip4844 transactions.
Expand Down
42 changes: 41 additions & 1 deletion crates/rpc/rpc-types-compat/src/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use reth_primitives::{
TransactionKind as PrimitiveTransactionKind, TransactionSignedEcRecovered, TxType, B256, U128,
U256, U64,
};
use reth_rpc_types::Transaction;
use reth_rpc_types::{CallInput, CallRequest, Transaction};
use signature::from_primitive_signature;
/// Create a new rpc transaction result for a mined transaction, using the given block hash,
/// number, and tx index fields to populate the corresponding fields in the rpc result.
Expand Down Expand Up @@ -132,3 +132,43 @@ fn fill(
blob_versioned_hashes,
}
}

/// Convert [TransactionSignedEcRecovered] to [CallRequest]
pub fn transaction_to_call_request(tx: TransactionSignedEcRecovered) -> CallRequest {
let from = tx.signer();
let to = tx.transaction.to();
let gas = tx.transaction.gas_limit();
let value = tx.transaction.value();
let input = tx.transaction.input().clone();
let nonce = tx.transaction.nonce();
let chain_id = tx.transaction.chain_id();
let access_list = tx.transaction.access_list().cloned();
let max_fee_per_blob_gas = tx.transaction.max_fee_per_blob_gas();
let blob_versioned_hashes = tx.transaction.blob_versioned_hashes();
let tx_type = tx.transaction.tx_type();

// fees depending on the transaction type
let (gas_price, max_fee_per_gas) = if tx.is_dynamic_fee() {
(None, Some(tx.max_fee_per_gas()))
} else {
(Some(tx.max_fee_per_gas()), None)
};
let max_priority_fee_per_gas = tx.transaction.max_priority_fee_per_gas();

CallRequest {
from: Some(from),
to,
gas_price: gas_price.map(U256::from),
max_fee_per_gas: max_fee_per_gas.map(U256::from),
max_priority_fee_per_gas: max_priority_fee_per_gas.map(U256::from),
gas: Some(U256::from(gas)),
value: Some(value.into()),
input: CallInput::new(input),
nonce: Some(U64::from(nonce)),
chain_id: chain_id.map(U64::from),
access_list,
max_fee_per_blob_gas: max_fee_per_blob_gas.map(U256::from),
blob_versioned_hashes,
transaction_type: Some(tx_type.into()),
}
}
10 changes: 10 additions & 0 deletions crates/rpc/rpc-types/src/eth/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,16 @@ pub struct CallInput {
}

impl CallInput {
/// Creates a new instance with the given input data.
pub fn new(data: Bytes) -> Self {
Self::maybe_input(Some(data))
}

/// Creates a new instance with the given input data.
pub fn maybe_input(input: Option<Bytes>) -> Self {
Self { input, data: None }
}

/// Consumes the type and returns the optional input data.
///
/// Returns an error if both `data` and `input` fields are set and not equal.
Expand Down
6 changes: 6 additions & 0 deletions crates/transaction-pool/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,12 @@ pub trait PoolTransaction:
/// [`TransactionKind::Create`] if the transaction is a contract creation.
fn kind(&self) -> &TransactionKind;

/// Returns the recipient of the transaction if it is not a [TransactionKind::Create]
/// transaction.
fn to(&self) -> Option<Address> {
(*self.kind()).to()
}

/// Returns the input data of this transaction.
fn input(&self) -> &[u8];

Expand Down
5 changes: 5 additions & 0 deletions crates/transaction-pool/src/validate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,11 @@ impl<T: PoolTransaction> ValidPoolTransaction<T> {
self.transaction.sender()
}

/// Returns the recipient of the transaction if it is not a CREATE transaction.
pub fn to(&self) -> Option<Address> {
self.transaction.to()
}

/// Returns the internal identifier for the sender of this transaction
pub(crate) fn sender_id(&self) -> SenderId {
self.transaction_id.sender
Expand Down
2 changes: 0 additions & 2 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,10 @@ reth-network-api.workspace = true
reth-network.workspace = true
reth-transaction-pool.workspace = true
reth-tasks.workspace = true

eyre.workspace = true
futures.workspace = true
async-trait.workspace = true
tokio.workspace = true

[[example]]
name = "db-access"
path = "db-access.rs"
Expand Down
16 changes: 16 additions & 0 deletions examples/trace-transaction-cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "trace-transaction-cli"
version = "0.0.0"
publish = false
edition.workspace = true
license.workspace = true

[dependencies]
reth.workspace = true
clap = { workspace = true, features = ["derive"] }
jsonrpsee = { workspace = true, features = ["server", "macros"] }
futures-util.workspace = true
eyre.workspace = true

[dev-dependencies]
tokio.workspace = true
101 changes: 101 additions & 0 deletions examples/trace-transaction-cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//! Example of how to trace new pending transactions in the reth CLI
//!
//! Run with
//!
//! ```not_rust
//! cargo run --release -p trace-transaction-cli -- node --http --ws --recipients 0x....,0x....
//! ```
//!
//! If no recipients are specified, all transactions will be traced.
use clap::Parser;
use futures_util::StreamExt;
use reth::{
cli::{
components::{RethNodeComponents, RethRpcComponents, RethRpcServerHandles},
config::RethRpcConfig,
ext::{RethCliExt, RethNodeCommandConfig},
Cli,
},
primitives::{Address, IntoRecoveredTransaction},
rpc::{compat::transaction_to_call_request, types::trace::parity::TraceType},
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 {
/// recipients addresses that we want to trace
#[arg(long, value_delimiter = ',')]
pub recipients: Vec<Address>,
}

impl RethNodeCommandConfig for RethCliTxpoolExt {
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();

// get an instance of the `trace_` API handler
let traceapi = rpc_components.registry.trace_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 let Some(tx_recipient_address) = tx.to() {
if recipients.is_empty() || recipients.contains(&tx_recipient_address) {
// trace the transaction with `trace_call`
let callrequest =
transaction_to_call_request(tx.to_recovered_transaction());
if let Ok(trace_result) = traceapi
.trace_call(
callrequest,
HashSet::from([TraceType::Trace]),
None,
None,
None,
)
.await
{
println!(
"trace result for transaction : {:?} is {:?}",
tx.hash(),
trace_result
);
}
}
}
}
}));
Ok(())
}
}

0 comments on commit 1483175

Please sign in to comment.