mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
example simulation transportless (#5025)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -7989,6 +7989,18 @@ version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
|
||||
|
||||
[[package]]
|
||||
name = "trace-transaction-cli"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"eyre",
|
||||
"futures-util",
|
||||
"jsonrpsee",
|
||||
"reth",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.39"
|
||||
|
||||
@ -51,6 +51,7 @@ members = [
|
||||
"examples/cli-extension-event-hooks",
|
||||
"examples/rpc-db",
|
||||
"examples/manual-p2p",
|
||||
"examples/trace-transaction-cli"
|
||||
]
|
||||
default-members = ["bin/reth"]
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
@ -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()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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];
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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"
|
||||
|
||||
16
examples/trace-transaction-cli/Cargo.toml
Normal file
16
examples/trace-transaction-cli/Cargo.toml
Normal file
@ -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
examples/trace-transaction-cli/src/main.rs
Normal file
101
examples/trace-transaction-cli/src/main.rs
Normal file
@ -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(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user