example simulation transportless (#5025)

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
Supernovahs.eth
2023-10-17 19:03:31 +05:30
committed by GitHub
parent ede8278916
commit 1483175e2f
11 changed files with 208 additions and 5 deletions

12
Cargo.lock generated
View File

@ -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"

View File

@ -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"

View File

@ -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;

View File

@ -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.

View File

@ -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()),
}
}

View File

@ -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.

View File

@ -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];

View File

@ -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

View File

@ -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"

View 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

View 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(())
}
}