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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
|
checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "trace-transaction-cli"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
"eyre",
|
||||||
|
"futures-util",
|
||||||
|
"jsonrpsee",
|
||||||
|
"reth",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
version = "0.1.39"
|
version = "0.1.39"
|
||||||
|
|||||||
@ -51,6 +51,7 @@ members = [
|
|||||||
"examples/cli-extension-event-hooks",
|
"examples/cli-extension-event-hooks",
|
||||||
"examples/rpc-db",
|
"examples/rpc-db",
|
||||||
"examples/manual-p2p",
|
"examples/manual-p2p",
|
||||||
|
"examples/trace-transaction-cli"
|
||||||
]
|
]
|
||||||
default-members = ["bin/reth"]
|
default-members = ["bin/reth"]
|
||||||
|
|
||||||
@ -107,7 +108,6 @@ reth-discv4 = { path = "./crates/net/discv4" }
|
|||||||
reth-eth-wire = { path = "./crates/net/eth-wire" }
|
reth-eth-wire = { path = "./crates/net/eth-wire" }
|
||||||
reth-ecies = { path = "./crates/net/ecies" }
|
reth-ecies = { path = "./crates/net/ecies" }
|
||||||
reth-tracing = { path = "./crates/tracing" }
|
reth-tracing = { path = "./crates/tracing" }
|
||||||
|
|
||||||
# revm
|
# revm
|
||||||
revm = "3.5.0"
|
revm = "3.5.0"
|
||||||
revm-primitives = "1.3.0"
|
revm-primitives = "1.3.0"
|
||||||
|
|||||||
@ -44,7 +44,7 @@ pub mod snapshot;
|
|||||||
pub mod stage;
|
pub mod stage;
|
||||||
mod storage;
|
mod storage;
|
||||||
/// Helpers for working with transactions
|
/// Helpers for working with transactions
|
||||||
mod transaction;
|
pub mod transaction;
|
||||||
pub mod trie;
|
pub mod trie;
|
||||||
mod withdrawal;
|
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].
|
/// Max fee per blob gas for eip4844 transaction [TxEip4844].
|
||||||
///
|
///
|
||||||
/// Returns `None` for non-eip4844 transactions.
|
/// Returns `None` for non-eip4844 transactions.
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use reth_primitives::{
|
|||||||
TransactionKind as PrimitiveTransactionKind, TransactionSignedEcRecovered, TxType, B256, U128,
|
TransactionKind as PrimitiveTransactionKind, TransactionSignedEcRecovered, TxType, B256, U128,
|
||||||
U256, U64,
|
U256, U64,
|
||||||
};
|
};
|
||||||
use reth_rpc_types::Transaction;
|
use reth_rpc_types::{CallInput, CallRequest, Transaction};
|
||||||
use signature::from_primitive_signature;
|
use signature::from_primitive_signature;
|
||||||
/// Create a new rpc transaction result for a mined transaction, using the given block hash,
|
/// 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.
|
/// number, and tx index fields to populate the corresponding fields in the rpc result.
|
||||||
@ -132,3 +132,43 @@ fn fill(
|
|||||||
blob_versioned_hashes,
|
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 {
|
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.
|
/// Consumes the type and returns the optional input data.
|
||||||
///
|
///
|
||||||
/// Returns an error if both `data` and `input` fields are set and not equal.
|
/// 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.
|
/// [`TransactionKind::Create`] if the transaction is a contract creation.
|
||||||
fn kind(&self) -> &TransactionKind;
|
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.
|
/// Returns the input data of this transaction.
|
||||||
fn input(&self) -> &[u8];
|
fn input(&self) -> &[u8];
|
||||||
|
|
||||||
|
|||||||
@ -226,6 +226,11 @@ impl<T: PoolTransaction> ValidPoolTransaction<T> {
|
|||||||
self.transaction.sender()
|
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
|
/// Returns the internal identifier for the sender of this transaction
|
||||||
pub(crate) fn sender_id(&self) -> SenderId {
|
pub(crate) fn sender_id(&self) -> SenderId {
|
||||||
self.transaction_id.sender
|
self.transaction_id.sender
|
||||||
|
|||||||
@ -21,12 +21,10 @@ reth-network-api.workspace = true
|
|||||||
reth-network.workspace = true
|
reth-network.workspace = true
|
||||||
reth-transaction-pool.workspace = true
|
reth-transaction-pool.workspace = true
|
||||||
reth-tasks.workspace = true
|
reth-tasks.workspace = true
|
||||||
|
|
||||||
eyre.workspace = true
|
eyre.workspace = true
|
||||||
futures.workspace = true
|
futures.workspace = true
|
||||||
async-trait.workspace = true
|
async-trait.workspace = true
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "db-access"
|
name = "db-access"
|
||||||
path = "db-access.rs"
|
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