diff --git a/Cargo.lock b/Cargo.lock index 6bf468e1e..7813960ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3122,6 +3122,7 @@ dependencies = [ name = "example-network-txpool" version = "0.0.0" dependencies = [ + "alloy-consensus", "eyre", "reth-network", "reth-provider", diff --git a/crates/net/network/src/transactions/mod.rs b/crates/net/network/src/transactions/mod.rs index 5b53fd2e2..5cd84af86 100644 --- a/crates/net/network/src/transactions/mod.rs +++ b/crates/net/network/src/transactions/mod.rs @@ -1710,7 +1710,7 @@ impl PooledTransactionsHashesBuilder { Self::Eth68(msg) => { msg.hashes.push(*pooled_tx.hash()); msg.sizes.push(pooled_tx.encoded_length()); - msg.types.push(pooled_tx.transaction.tx_type()); + msg.types.push(pooled_tx.transaction.ty()); } } } diff --git a/crates/optimism/node/src/txpool.rs b/crates/optimism/node/src/txpool.rs index fd8a4f1ec..586d514a9 100644 --- a/crates/optimism/node/src/txpool.rs +++ b/crates/optimism/node/src/txpool.rs @@ -2,9 +2,8 @@ use alloy_consensus::{ BlobTransactionSidecar, BlobTransactionValidationError, BlockHeader, Transaction, Typed2718, }; -use alloy_eips::eip2718::Encodable2718; -use alloy_primitives::{Address, TxHash, TxKind, U256}; -use op_alloy_consensus::OpTypedTransaction; +use alloy_eips::{eip2718::Encodable2718, eip7702::SignedAuthorization}; +use alloy_primitives::{Address, Bytes, TxHash, TxKind, B256, U256}; use parking_lot::RwLock; use reth_node_api::{Block, BlockBody}; use reth_optimism_evm::RethL1BlockInfo; @@ -14,7 +13,7 @@ use reth_primitives::{ transaction::TransactionConversionError, GotExpected, InvalidTransactionError, Recovered, SealedBlock, }; -use reth_primitives_traits::SignedTransaction; +use reth_primitives_traits::{InMemorySize, SignedTransaction}; use reth_provider::{BlockReaderIdExt, ChainSpecProvider, StateProviderFactory}; use reth_revm::L1BlockInfo; use reth_transaction_pool::{ @@ -123,68 +122,94 @@ impl PoolTransaction for OpPooledTransaction { self.inner.transaction.signer_ref() } - fn nonce(&self) -> u64 { - self.inner.transaction.nonce() - } - fn cost(&self) -> &U256 { &self.inner.cost } - fn gas_limit(&self) -> u64 { - self.inner.transaction.gas_limit() - } - - fn max_fee_per_gas(&self) -> u128 { - self.inner.transaction.max_fee_per_gas() - } - - fn access_list(&self) -> Option<&AccessList> { - self.inner.transaction.access_list() - } - - fn max_priority_fee_per_gas(&self) -> Option { - self.inner.transaction.max_priority_fee_per_gas() - } - - fn max_fee_per_blob_gas(&self) -> Option { - self.inner.transaction.max_fee_per_blob_gas() - } - - fn effective_tip_per_gas(&self, base_fee: u64) -> Option { - self.inner.transaction.effective_tip_per_gas(base_fee) - } - - fn priority_fee_or_price(&self) -> u128 { - self.inner.transaction.priority_fee_or_price() - } - - fn kind(&self) -> TxKind { - self.inner.transaction.kind() - } - - fn is_create(&self) -> bool { - self.inner.transaction.is_create() - } - - fn input(&self) -> &[u8] { - self.inner.transaction.input() - } - - fn size(&self) -> usize { - self.inner.transaction.input().len() - } - - fn tx_type(&self) -> u8 { - self.inner.transaction.ty() - } - fn encoded_length(&self) -> usize { self.inner.encoded_length } +} - fn chain_id(&self) -> Option { - self.inner.transaction.chain_id() +impl Typed2718 for OpPooledTransaction { + fn ty(&self) -> u8 { + self.inner.ty() + } +} + +impl InMemorySize for OpPooledTransaction { + fn size(&self) -> usize { + self.inner.size() + } +} + +impl alloy_consensus::Transaction for OpPooledTransaction { + fn chain_id(&self) -> Option { + self.inner.chain_id() + } + + fn nonce(&self) -> u64 { + self.inner.nonce() + } + + fn gas_limit(&self) -> u64 { + self.inner.gas_limit() + } + + fn gas_price(&self) -> Option { + self.inner.gas_price() + } + + fn max_fee_per_gas(&self) -> u128 { + self.inner.max_fee_per_gas() + } + + fn max_priority_fee_per_gas(&self) -> Option { + self.inner.max_priority_fee_per_gas() + } + + fn max_fee_per_blob_gas(&self) -> Option { + self.inner.max_fee_per_blob_gas() + } + + fn priority_fee_or_price(&self) -> u128 { + self.inner.priority_fee_or_price() + } + + fn effective_gas_price(&self, base_fee: Option) -> u128 { + self.inner.effective_gas_price(base_fee) + } + + fn is_dynamic_fee(&self) -> bool { + self.inner.is_dynamic_fee() + } + + fn kind(&self) -> TxKind { + self.inner.kind() + } + + fn is_create(&self) -> bool { + self.inner.is_create() + } + + fn value(&self) -> U256 { + self.inner.value() + } + + fn input(&self) -> &Bytes { + self.inner.input() + } + + fn access_list(&self) -> Option<&AccessList> { + self.inner.access_list() + } + + fn blob_versioned_hashes(&self) -> Option<&[B256]> { + self.inner.blob_versioned_hashes() + } + + fn authorization_list(&self) -> Option<&[SignedAuthorization]> { + self.inner.authorization_list() } } @@ -193,10 +218,6 @@ impl EthPoolTransaction for OpPooledTransaction { EthBlobTransactionSidecar::None } - fn blob_count(&self) -> usize { - 0 - } - fn try_into_pooled_eip4844( self, _sidecar: Arc, @@ -216,14 +237,7 @@ impl EthPoolTransaction for OpPooledTransaction { _sidecar: &BlobTransactionSidecar, _settings: &KzgSettings, ) -> Result<(), BlobTransactionValidationError> { - Err(BlobTransactionValidationError::NotBlobTransaction(self.tx_type())) - } - - fn authorization_count(&self) -> usize { - match self.inner.transaction.transaction() { - OpTypedTransaction::Eip7702(tx) => tx.authorization_list.len(), - _ => 0, - } + Err(BlobTransactionValidationError::NotBlobTransaction(self.ty())) } } diff --git a/crates/transaction-pool/benches/reorder.rs b/crates/transaction-pool/benches/reorder.rs index 534f0e201..234004f96 100644 --- a/crates/transaction-pool/benches/reorder.rs +++ b/crates/transaction-pool/benches/reorder.rs @@ -113,7 +113,7 @@ fn generate_test_data( mod implementations { use super::*; - use reth_transaction_pool::PoolTransaction; + use alloy_consensus::Transaction; use std::collections::BinaryHeap; /// This implementation appends the transactions and uses [`Vec::sort_by`] function for sorting. diff --git a/crates/transaction-pool/src/pool/best.rs b/crates/transaction-pool/src/pool/best.rs index 7d58e3984..47b19e42c 100644 --- a/crates/transaction-pool/src/pool/best.rs +++ b/crates/transaction-pool/src/pool/best.rs @@ -4,6 +4,8 @@ use crate::{ pool::pending::PendingTransaction, PoolTransaction, TransactionOrdering, ValidPoolTransaction, }; +use alloy_consensus::Transaction; +use alloy_eips::Typed2718; use alloy_primitives::Address; use core::fmt; use reth_payload_util::PayloadTransactions; diff --git a/crates/transaction-pool/src/pool/blob.rs b/crates/transaction-pool/src/pool/blob.rs index e6c0cb245..b20247fdf 100644 --- a/crates/transaction-pool/src/pool/blob.rs +++ b/crates/transaction-pool/src/pool/blob.rs @@ -29,7 +29,7 @@ pub(crate) struct BlobTransactions { pending_fees: PendingFees, /// Keeps track of the size of this pool. /// - /// See also [`PoolTransaction::size`]. + /// See also [`reth_primitives_traits::InMemorySize::size`]. size_of: SizeTracker, } diff --git a/crates/transaction-pool/src/pool/mod.rs b/crates/transaction-pool/src/pool/mod.rs index 348e76947..954ef66f3 100644 --- a/crates/transaction-pool/src/pool/mod.rs +++ b/crates/transaction-pool/src/pool/mod.rs @@ -87,7 +87,7 @@ use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard}; use reth_eth_wire_types::HandleMempoolData; use reth_execution_types::ChangedAccount; -use alloy_eips::eip4844::BlobTransactionSidecar; +use alloy_eips::{eip4844::BlobTransactionSidecar, Typed2718}; use reth_primitives::Recovered; use rustc_hash::FxHashMap; use std::{collections::HashSet, fmt, sync::Arc, time::Instant}; diff --git a/crates/transaction-pool/src/pool/parked.rs b/crates/transaction-pool/src/pool/parked.rs index 29216af47..bc02497a4 100644 --- a/crates/transaction-pool/src/pool/parked.rs +++ b/crates/transaction-pool/src/pool/parked.rs @@ -43,7 +43,7 @@ pub struct ParkedPool { sender_transaction_count: FxHashMap, /// Keeps track of the size of this pool. /// - /// See also [`PoolTransaction::size`]. + /// See also [`reth_primitives_traits::InMemorySize::size`]. size_of: SizeTracker, } @@ -520,6 +520,7 @@ impl Ord for QueuedOrd { mod tests { use super::*; use crate::test_utils::{MockTransaction, MockTransactionFactory, MockTransactionSet}; + use alloy_consensus::Transaction; use alloy_primitives::address; use reth_primitives::TxType; use std::collections::HashSet; diff --git a/crates/transaction-pool/src/pool/pending.rs b/crates/transaction-pool/src/pool/pending.rs index d169bfa37..78506549d 100644 --- a/crates/transaction-pool/src/pool/pending.rs +++ b/crates/transaction-pool/src/pool/pending.rs @@ -43,7 +43,7 @@ pub struct PendingPool { independent_transactions: FxHashMap>, /// Keeps track of the size of this pool. /// - /// See also [`PoolTransaction::size`](crate::traits::PoolTransaction::size). + /// See also [`reth_primitives_traits::InMemorySize::size`]. size_of: SizeTracker, /// Used to broadcast new transactions that have been added to the `PendingPool` to existing /// `static_files` of this pool. @@ -613,6 +613,7 @@ mod tests { test_utils::{MockOrdering, MockTransaction, MockTransactionFactory, MockTransactionSet}, PoolTransaction, }; + use alloy_consensus::Transaction; use alloy_primitives::address; use reth_primitives::TxType; use std::collections::HashSet; diff --git a/crates/transaction-pool/src/pool/txpool.rs b/crates/transaction-pool/src/pool/txpool.rs index a0a1f6a36..cfe09a139 100644 --- a/crates/transaction-pool/src/pool/txpool.rs +++ b/crates/transaction-pool/src/pool/txpool.rs @@ -25,6 +25,7 @@ use alloy_consensus::constants::{ use alloy_eips::{ eip1559::{ETHEREUM_BLOCK_GAS_LIMIT, MIN_PROTOCOL_BASE_FEE}, eip4844::BLOB_TX_MIN_BLOB_GASPRICE, + Typed2718, }; use alloy_primitives::{Address, TxHash, B256}; use rustc_hash::FxHashMap; @@ -571,7 +572,7 @@ impl TxPool { let mut eip7702_count = 0; for tx in self.all_transactions.transactions_iter() { - match tx.transaction.tx_type() { + match tx.transaction.ty() { LEGACY_TX_TYPE_ID => legacy_count += 1, EIP2930_TX_TYPE_ID => eip2930_count += 1, EIP1559_TX_TYPE_ID => eip1559_count += 1, @@ -1978,6 +1979,7 @@ mod tests { traits::TransactionOrigin, SubPoolLimit, }; + use alloy_consensus::Transaction; use alloy_primitives::address; use reth_primitives::TxType; diff --git a/crates/transaction-pool/src/test_utils/mock.rs b/crates/transaction-pool/src/test_utils/mock.rs index 3c393ed50..752d50754 100644 --- a/crates/transaction-pool/src/test_utils/mock.rs +++ b/crates/transaction-pool/src/test_utils/mock.rs @@ -218,6 +218,8 @@ pub enum MockTransaction { input: Bytes, /// The sidecar information for the transaction. sidecar: BlobTransactionSidecar, + /// The blob versioned hashes for the transaction. + blob_versioned_hashes: Vec, /// The size of the transaction, returned in the implementation of [`PoolTransaction`]. size: usize, /// The cost of the transaction, returned in the implementation of [`PoolTransaction`]. @@ -359,6 +361,7 @@ impl MockTransaction { input: Bytes::new(), access_list: Default::default(), sidecar: Default::default(), + blob_versioned_hashes: Default::default(), size: Default::default(), cost: U256::ZERO, } @@ -367,7 +370,10 @@ impl MockTransaction { /// Returns a new EIP4844 transaction with a provided sidecar pub fn eip4844_with_sidecar(sidecar: BlobTransactionSidecar) -> Self { let mut transaction = Self::eip4844(); - if let Self::Eip4844 { sidecar: ref mut existing_sidecar, .. } = &mut transaction { + if let Self::Eip4844 { sidecar: existing_sidecar, blob_versioned_hashes, .. } = + &mut transaction + { + *blob_versioned_hashes = sidecar.versioned_hashes().collect(); *existing_sidecar = sidecar; } transaction @@ -702,10 +708,6 @@ impl PoolTransaction for MockTransaction { self.get_sender() } - fn nonce(&self) -> u64 { - *self.get_nonce() - } - // Having `get_cost` from `make_setters_getters` would be cleaner but we didn't // want to also generate the error-prone cost setters. For now cost should be // correct at construction and auto-updated per field update via `update_cost`, @@ -720,10 +722,56 @@ impl PoolTransaction for MockTransaction { } } + /// Returns the encoded length of the transaction. + fn encoded_length(&self) -> usize { + self.size() + } +} + +impl InMemorySize for MockTransaction { + fn size(&self) -> usize { + *self.get_size() + } +} + +impl Typed2718 for MockTransaction { + fn ty(&self) -> u8 { + match self { + Self::Legacy { .. } => TxType::Legacy.into(), + Self::Eip1559 { .. } => TxType::Eip1559.into(), + Self::Eip4844 { .. } => TxType::Eip4844.into(), + Self::Eip2930 { .. } => TxType::Eip2930.into(), + Self::Eip7702 { .. } => TxType::Eip7702.into(), + } + } +} + +impl alloy_consensus::Transaction for MockTransaction { + fn chain_id(&self) -> Option { + match self { + Self::Legacy { chain_id, .. } => *chain_id, + Self::Eip1559 { chain_id, .. } | + Self::Eip4844 { chain_id, .. } | + Self::Eip2930 { chain_id, .. } | + Self::Eip7702 { chain_id, .. } => Some(*chain_id), + } + } + + fn nonce(&self) -> u64 { + *self.get_nonce() + } + fn gas_limit(&self) -> u64 { *self.get_gas_limit() } + fn gas_price(&self) -> Option { + match self { + Self::Legacy { gas_price, .. } | Self::Eip2930 { gas_price, .. } => Some(*gas_price), + _ => None, + } + } + fn max_fee_per_gas(&self) -> u128 { match self { Self::Legacy { gas_price, .. } | Self::Eip2930 { gas_price, .. } => *gas_price, @@ -733,16 +781,6 @@ impl PoolTransaction for MockTransaction { } } - fn access_list(&self) -> Option<&AccessList> { - match self { - Self::Legacy { .. } => None, - Self::Eip1559 { access_list: accesslist, .. } | - Self::Eip4844 { access_list: accesslist, .. } | - Self::Eip2930 { access_list: accesslist, .. } | - Self::Eip7702 { access_list: accesslist, .. } => Some(accesslist), - } - } - fn max_priority_fee_per_gas(&self) -> Option { match self { Self::Legacy { .. } | Self::Eip2930 { .. } => None, @@ -759,33 +797,6 @@ impl PoolTransaction for MockTransaction { } } - /// Calculates the effective tip per gas given a base fee. - fn effective_tip_per_gas(&self, base_fee: u64) -> Option { - // Convert base_fee to u128 for precision in calculations - let base_fee = base_fee as u128; - - // Retrieve the maximum fee per gas - let max_fee_per_gas = self.max_fee_per_gas(); - - // If the maximum fee per gas is less than the base fee, return None - if max_fee_per_gas < base_fee { - return None - } - - // Calculate the fee by subtracting the base fee from the maximum fee per gas - let fee = max_fee_per_gas - base_fee; - - // If the maximum priority fee per gas is available, return the minimum of fee and priority - // fee - if let Some(priority_fee) = self.max_priority_fee_per_gas() { - return Some(fee.min(priority_fee)) - } - - // Otherwise, return the calculated fee - Some(fee) - } - - /// Returns the priority fee or gas price based on the transaction type. fn priority_fee_or_price(&self) -> u128 { match self { Self::Legacy { gas_price, .. } | Self::Eip2930 { gas_price, .. } => *gas_price, @@ -795,7 +806,28 @@ impl PoolTransaction for MockTransaction { } } - /// Returns the transaction kind associated with the transaction. + fn effective_gas_price(&self, base_fee: Option) -> u128 { + base_fee.map_or(self.max_fee_per_gas(), |base_fee| { + // if the tip is greater than the max priority fee per gas, set it to the max + // priority fee per gas + base fee + let tip = self.max_fee_per_gas().saturating_sub(base_fee as u128); + if let Some(max_tip) = self.max_priority_fee_per_gas() { + if tip > max_tip { + max_tip + base_fee as u128 + } else { + // otherwise return the max fee per gas + self.max_fee_per_gas() + } + } else { + self.max_fee_per_gas() + } + }) + } + + fn is_dynamic_fee(&self) -> bool { + !matches!(self, Self::Legacy { .. } | Self::Eip2930 { .. }) + } + fn kind(&self) -> TxKind { match self { Self::Legacy { to, .. } | Self::Eip1559 { to, .. } | Self::Eip2930 { to, .. } => *to, @@ -803,7 +835,6 @@ impl PoolTransaction for MockTransaction { } } - /// Returns true if the transaction is a contract creation. fn is_create(&self) -> bool { match self { Self::Legacy { to, .. } | Self::Eip1559 { to, .. } | Self::Eip2930 { to, .. } => { @@ -813,40 +844,41 @@ impl PoolTransaction for MockTransaction { } } - /// Returns the input data associated with the transaction. - fn input(&self) -> &[u8] { - self.get_input() - } - - /// Returns the size of the transaction. - fn size(&self) -> usize { - *self.get_size() - } - - /// Returns the transaction type as a byte identifier. - fn tx_type(&self) -> u8 { + fn value(&self) -> U256 { match self { - Self::Legacy { .. } => TxType::Legacy.into(), - Self::Eip1559 { .. } => TxType::Eip1559.into(), - Self::Eip4844 { .. } => TxType::Eip4844.into(), - Self::Eip2930 { .. } => TxType::Eip2930.into(), - Self::Eip7702 { .. } => TxType::Eip7702.into(), + Self::Legacy { value, .. } | + Self::Eip1559 { value, .. } | + Self::Eip2930 { value, .. } | + Self::Eip4844 { value, .. } | + Self::Eip7702 { value, .. } => *value, } } - /// Returns the encoded length of the transaction. - fn encoded_length(&self) -> usize { - self.size() + fn input(&self) -> &Bytes { + self.get_input() } - /// Returns the chain ID associated with the transaction. - fn chain_id(&self) -> Option { + fn access_list(&self) -> Option<&AccessList> { match self { - Self::Legacy { chain_id, .. } => *chain_id, - Self::Eip1559 { chain_id, .. } | - Self::Eip4844 { chain_id, .. } | - Self::Eip2930 { chain_id, .. } | - Self::Eip7702 { chain_id, .. } => Some(*chain_id), + Self::Legacy { .. } => None, + Self::Eip1559 { access_list: accesslist, .. } | + Self::Eip4844 { access_list: accesslist, .. } | + Self::Eip2930 { access_list: accesslist, .. } | + Self::Eip7702 { access_list: accesslist, .. } => Some(accesslist), + } + } + + fn blob_versioned_hashes(&self) -> Option<&[B256]> { + match self { + Self::Eip4844 { blob_versioned_hashes, .. } => Some(blob_versioned_hashes), + _ => None, + } + } + + fn authorization_list(&self) -> Option<&[SignedAuthorization]> { + match self { + Self::Eip7702 { authorization_list, .. } => Some(authorization_list), + _ => None, } } } @@ -859,13 +891,6 @@ impl EthPoolTransaction for MockTransaction { } } - fn blob_count(&self) -> usize { - match self { - Self::Eip4844 { sidecar, .. } => sidecar.blobs.len(), - _ => 0, - } - } - fn try_into_pooled_eip4844( self, sidecar: Arc, @@ -897,10 +922,6 @@ impl EthPoolTransaction for MockTransaction { _ => Err(BlobTransactionValidationError::NotBlobTransaction(self.tx_type())), } } - - fn authorization_count(&self) -> usize { - 0 - } } impl TryFrom> for MockTransaction { @@ -1009,6 +1030,7 @@ impl TryFrom> for MockTransaction { input, access_list, sidecar: BlobTransactionSidecar::default(), + blob_versioned_hashes: Default::default(), size, cost: U256::from(gas_limit) * U256::from(max_fee_per_gas) + value, }), @@ -1202,7 +1224,7 @@ impl MockTransactionFactory { /// Generates a transaction ID for the given [`MockTransaction`]. pub fn tx_id(&mut self, tx: &MockTransaction) -> TransactionId { let sender = self.ids.sender_id_or_create(tx.sender()); - TransactionId::new(sender, tx.nonce()) + TransactionId::new(sender, *tx.get_nonce()) } /// Validates a [`MockTransaction`] and returns a [`MockValidTx`]. diff --git a/crates/transaction-pool/src/traits.rs b/crates/transaction-pool/src/traits.rs index b360cdb7a..9d838d3c2 100644 --- a/crates/transaction-pool/src/traits.rs +++ b/crates/transaction-pool/src/traits.rs @@ -7,12 +7,13 @@ use crate::{ }; use alloy_consensus::{ constants::{EIP1559_TX_TYPE_ID, EIP4844_TX_TYPE_ID, EIP7702_TX_TYPE_ID}, - BlockHeader, Signed, Transaction as _, Typed2718, + BlockHeader, Signed, Typed2718, }; use alloy_eips::{ eip2718::Encodable2718, eip2930::AccessList, eip4844::{BlobAndProofV1, BlobTransactionSidecar, BlobTransactionValidationError}, + eip7702::SignedAuthorization, }; use alloy_primitives::{Address, TxHash, TxKind, B256, U256}; use futures_util::{ready, Stream}; @@ -21,9 +22,9 @@ use reth_execution_types::ChangedAccount; use reth_primitives::{ kzg::KzgSettings, transaction::{SignedTransactionIntoRecoveredExt, TryFromRecoveredTransactionError}, - PooledTransaction, Recovered, SealedBlock, Transaction, TransactionSigned, + PooledTransaction, Recovered, SealedBlock, TransactionSigned, }; -use reth_primitives_traits::{Block, SignedTransaction}; +use reth_primitives_traits::{Block, InMemorySize, SignedTransaction}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use std::{ @@ -964,7 +965,9 @@ impl BestTransactionsAttributes { /// sidecar when they are gossiped around the network. It is expected that the `Consensus` format is /// a subset of the `Pooled` format. pub trait PoolTransaction: - fmt::Debug + alloy_consensus::Transaction + + InMemorySize + + fmt::Debug + Send + Sync + Clone @@ -1029,9 +1032,6 @@ pub trait PoolTransaction: /// Reference to the Sender of the transaction. fn sender_ref(&self) -> &Address; - /// Returns the nonce for this transaction. - fn nonce(&self) -> u64; - /// Returns the cost that this transaction is allowed to consume: /// /// For EIP-1559 transactions: `max_fee_per_gas * gas_limit + tx_value`. @@ -1040,87 +1040,11 @@ pub trait PoolTransaction: /// max_blob_fee_per_gas * blob_gas_used`. fn cost(&self) -> &U256; - /// Amount of gas that should be used in executing this transaction. This is paid up-front. - fn gas_limit(&self) -> u64; - - /// Returns the EIP-1559 the maximum fee per gas the caller is willing to pay. - /// - /// For legacy transactions this is `gas_price`. - /// - /// This is also commonly referred to as the "Gas Fee Cap" (`GasFeeCap`). - fn max_fee_per_gas(&self) -> u128; - - /// Returns the `access_list` for the particular transaction type. - /// For Legacy transactions, returns default. - fn access_list(&self) -> Option<&AccessList>; - - /// Returns the EIP-1559 Priority fee the caller is paying to the block author. - /// - /// This will return `None` for non-EIP1559 transactions - fn max_priority_fee_per_gas(&self) -> Option; - - /// Returns the EIP-4844 max fee per data gas - /// - /// This will return `None` for non-EIP4844 transactions - fn max_fee_per_blob_gas(&self) -> Option; - - /// Returns the effective tip for this transaction. - /// - /// For EIP-1559 transactions: `min(max_fee_per_gas - base_fee, max_priority_fee_per_gas)`. - /// For legacy transactions: `gas_price - base_fee`. - fn effective_tip_per_gas(&self, base_fee: u64) -> Option; - - /// Returns the max priority fee per gas if the transaction is an EIP-1559 transaction, and - /// otherwise returns the gas price. - fn priority_fee_or_price(&self) -> u128; - - /// Returns the transaction's [`TxKind`], which is the address of the recipient or - /// [`TxKind::Create`] if the transaction is a contract creation. - fn kind(&self) -> TxKind; - - /// Returns true if the transaction is a contract creation. - /// We don't provide a default implementation via `kind` as it copies the 21-byte - /// [`TxKind`] for this simple check. A proper implementation shouldn't allocate. - fn is_create(&self) -> bool; - - /// Returns the recipient of the transaction if it is not a [`TxKind::Create`] - /// transaction. - fn to(&self) -> Option
{ - self.kind().to().copied() - } - - /// Returns the input data of this transaction. - fn input(&self) -> &[u8]; - - /// Returns a measurement of the heap usage of this type and all its internals. - fn size(&self) -> usize; - - /// Returns the transaction type - fn tx_type(&self) -> u8; - - /// Returns true if the transaction is an EIP-1559 transaction. - fn is_eip1559(&self) -> bool { - self.tx_type() == EIP1559_TX_TYPE_ID - } - - /// Returns true if the transaction is an EIP-4844 transaction. - fn is_eip4844(&self) -> bool { - self.tx_type() == EIP4844_TX_TYPE_ID - } - - /// Returns true if the transaction is an EIP-7702 transaction. - fn is_eip7702(&self) -> bool { - self.tx_type() == EIP7702_TX_TYPE_ID - } - /// Returns the length of the rlp encoded transaction object /// /// Note: Implementations should cache this value. fn encoded_length(&self) -> usize; - /// Returns `chain_id` - fn chain_id(&self) -> Option; - /// Ensures that the transaction's code size does not exceed the provided `max_init_code_size`. /// /// This is specifically relevant for contract creation transactions ([`TxKind::Create`]), @@ -1149,14 +1073,11 @@ pub trait EthPoolTransaction: PoolTransaction { /// Extracts the blob sidecar from the transaction. fn take_blob(&mut self) -> EthBlobTransactionSidecar; - /// Returns the number of blobs this transaction has. - fn blob_count(&self) -> usize; - /// A specialization for the EIP-4844 transaction type. /// Tries to reattach the blob sidecar to the transaction. /// /// This returns an option, but callers should ensure that the transaction is an EIP-4844 - /// transaction: [`PoolTransaction::is_eip4844`]. + /// transaction: [`Typed2718::is_eip4844`]. fn try_into_pooled_eip4844( self, sidecar: Arc, @@ -1176,9 +1097,6 @@ pub trait EthPoolTransaction: PoolTransaction { blob: &BlobTransactionSidecar, settings: &KzgSettings, ) -> Result<(), BlobTransactionValidationError>; - - /// Returns the number of authorizations this transaction has. - fn authorization_count(&self) -> usize; } /// The default [`PoolTransaction`] for the [Pool](crate::Pool) for Ethereum. @@ -1300,11 +1218,6 @@ impl PoolTransaction for EthPooledTransaction { self.transaction.signer_ref() } - /// Returns the nonce for this transaction. - fn nonce(&self) -> u64 { - self.transaction.nonce() - } - /// Returns the cost that this transaction is allowed to consume: /// /// For EIP-1559 transactions: `max_fee_per_gas * gas_limit + tx_value`. @@ -1315,82 +1228,91 @@ impl PoolTransaction for EthPooledTransaction { &self.cost } - /// Amount of gas that should be used in executing this transaction. This is paid up-front. + /// Returns the length of the rlp encoded object + fn encoded_length(&self) -> usize { + self.encoded_length + } +} + +impl Typed2718 for EthPooledTransaction { + fn ty(&self) -> u8 { + self.transaction.ty() + } +} + +impl InMemorySize for EthPooledTransaction { + fn size(&self) -> usize { + self.transaction.size() + } +} + +impl alloy_consensus::Transaction for EthPooledTransaction { + fn chain_id(&self) -> Option { + self.transaction.chain_id() + } + + fn nonce(&self) -> u64 { + self.transaction.nonce() + } + fn gas_limit(&self) -> u64 { self.transaction.gas_limit() } - /// Returns the EIP-1559 Max base fee the caller is willing to pay. - /// - /// For legacy transactions this is `gas_price`. - /// - /// This is also commonly referred to as the "Gas Fee Cap" (`GasFeeCap`). + fn gas_price(&self) -> Option { + self.transaction.gas_price() + } + fn max_fee_per_gas(&self) -> u128 { - self.transaction.transaction().max_fee_per_gas() + self.transaction.max_fee_per_gas() } - fn access_list(&self) -> Option<&AccessList> { - self.transaction.access_list() - } - - /// Returns the EIP-1559 Priority fee the caller is paying to the block author. - /// - /// This will return `None` for non-EIP1559 transactions fn max_priority_fee_per_gas(&self) -> Option { - self.transaction.transaction().max_priority_fee_per_gas() + self.transaction.max_priority_fee_per_gas() } fn max_fee_per_blob_gas(&self) -> Option { self.transaction.max_fee_per_blob_gas() } - /// Returns the effective tip for this transaction. - /// - /// For EIP-1559 transactions: `min(max_fee_per_gas - base_fee, max_priority_fee_per_gas)`. - /// For legacy transactions: `gas_price - base_fee`. - fn effective_tip_per_gas(&self, base_fee: u64) -> Option { - self.transaction.effective_tip_per_gas(base_fee) - } - - /// Returns the max priority fee per gas if the transaction is an EIP-1559 transaction, and - /// otherwise returns the gas price. fn priority_fee_or_price(&self) -> u128 { self.transaction.priority_fee_or_price() } - /// Returns the transaction's [`TxKind`], which is the address of the recipient or - /// [`TxKind::Create`] if the transaction is a contract creation. + fn effective_gas_price(&self, base_fee: Option) -> u128 { + self.transaction.effective_gas_price(base_fee) + } + + fn is_dynamic_fee(&self) -> bool { + self.transaction.is_dynamic_fee() + } + fn kind(&self) -> TxKind { self.transaction.kind() } - /// Returns true if the transaction is a contract creation. fn is_create(&self) -> bool { self.transaction.is_create() } - fn input(&self) -> &[u8] { + fn value(&self) -> U256 { + self.transaction.value() + } + + fn input(&self) -> &revm_primitives::Bytes { self.transaction.input() } - /// Returns a measurement of the heap usage of this type and all its internals. - fn size(&self) -> usize { - self.transaction.transaction().input().len() + fn access_list(&self) -> Option<&AccessList> { + self.transaction.access_list() } - /// Returns the transaction type - fn tx_type(&self) -> u8 { - self.transaction.ty() + fn blob_versioned_hashes(&self) -> Option<&[B256]> { + self.transaction.blob_versioned_hashes() } - /// Returns the length of the rlp encoded object - fn encoded_length(&self) -> usize { - self.encoded_length - } - - /// Returns `chain_id` - fn chain_id(&self) -> Option { - self.transaction.chain_id() + fn authorization_list(&self) -> Option<&[SignedAuthorization]> { + self.transaction.authorization_list() } } @@ -1403,13 +1325,6 @@ impl EthPoolTransaction for EthPooledTransaction { } } - fn blob_count(&self) -> usize { - match self.transaction.transaction() { - Transaction::Eip4844(tx) => tx.blob_versioned_hashes.len(), - _ => 0, - } - } - fn try_into_pooled_eip4844( self, sidecar: Arc, @@ -1438,15 +1353,8 @@ impl EthPoolTransaction for EthPooledTransaction { settings: &KzgSettings, ) -> Result<(), BlobTransactionValidationError> { match self.transaction.transaction() { - Transaction::Eip4844(tx) => tx.validate_blob(sidecar, settings), - _ => Err(BlobTransactionValidationError::NotBlobTransaction(self.tx_type())), - } - } - - fn authorization_count(&self) -> usize { - match self.transaction.transaction() { - Transaction::Eip7702(tx) => tx.authorization_list.len(), - _ => 0, + reth_primitives::Transaction::Eip4844(tx) => tx.validate_blob(sidecar, settings), + _ => Err(BlobTransactionValidationError::NotBlobTransaction(self.ty())), } } } @@ -1640,7 +1548,7 @@ mod tests { use alloy_consensus::{TxEip1559, TxEip2930, TxEip4844, TxEip7702, TxLegacy}; use alloy_eips::eip4844::DATA_GAS_PER_BLOB; use alloy_primitives::PrimitiveSignature as Signature; - use reth_primitives::TransactionSigned; + use reth_primitives::{Transaction, TransactionSigned}; #[test] fn test_pool_size_invariants() { diff --git a/crates/transaction-pool/src/validate/eth.rs b/crates/transaction-pool/src/validate/eth.rs index 9f77d913b..7859e2bf8 100644 --- a/crates/transaction-pool/src/validate/eth.rs +++ b/crates/transaction-pool/src/validate/eth.rs @@ -190,7 +190,7 @@ where maybe_state: &mut Option>, ) -> TransactionValidationOutcome { // Checks for tx_type - match transaction.tx_type() { + match transaction.ty() { LEGACY_TX_TYPE_ID => { // Accept legacy transactions } @@ -307,7 +307,7 @@ where ) } - if transaction.authorization_count() == 0 { + if transaction.authorization_list().is_none_or(|l| l.is_empty()) { return TransactionValidationOutcome::Invalid( transaction, Eip7702PoolTransactionError::MissingEip7702AuthorizationList.into(), @@ -329,7 +329,7 @@ where ) } - let blob_count = transaction.blob_count(); + let blob_count = transaction.blob_versioned_hashes().map(|b| b.len()).unwrap_or(0); if blob_count == 0 { // no blobs return TransactionValidationOutcome::Invalid( @@ -865,7 +865,7 @@ pub fn ensure_intrinsic_gas( transaction.input(), transaction.is_create(), transaction.access_list().map(|list| list.0.as_slice()).unwrap_or(&[]), - transaction.authorization_count() as u64, + transaction.authorization_list().map(|l| l.len()).unwrap_or(0) as u64, ); let gas_limit = transaction.gas_limit(); @@ -883,6 +883,7 @@ mod tests { blobstore::InMemoryBlobStore, error::PoolErrorKind, traits::PoolTransaction, CoinbaseTipOrdering, EthPooledTransaction, Pool, TransactionPool, }; + use alloy_consensus::Transaction; use alloy_eips::eip2718::Decodable2718; use alloy_primitives::{hex, U256}; use reth_primitives::{transaction::SignedTransactionIntoRecoveredExt, PooledTransaction}; diff --git a/crates/transaction-pool/src/validate/mod.rs b/crates/transaction-pool/src/validate/mod.rs index 0ba716e0b..6cc04f7b8 100644 --- a/crates/transaction-pool/src/validate/mod.rs +++ b/crates/transaction-pool/src/validate/mod.rs @@ -282,7 +282,7 @@ impl ValidPoolTransaction { /// Returns the type identifier of the transaction pub fn tx_type(&self) -> u8 { - self.transaction.tx_type() + self.transaction.ty() } /// Returns the address of the sender diff --git a/crates/transaction-pool/tests/it/evict.rs b/crates/transaction-pool/tests/it/evict.rs index 3b74b8cb2..eb677a6de 100644 --- a/crates/transaction-pool/tests/it/evict.rs +++ b/crates/transaction-pool/tests/it/evict.rs @@ -1,5 +1,6 @@ //! Transaction pool eviction tests. +use alloy_consensus::Transaction; use alloy_eips::eip1559::{ETHEREUM_BLOCK_GAS_LIMIT, MIN_PROTOCOL_BASE_FEE}; use alloy_primitives::{Address, B256}; use rand::distributions::Uniform; @@ -8,8 +9,7 @@ use reth_transaction_pool::{ test_utils::{ MockFeeRange, MockTransactionDistribution, MockTransactionRatio, TestPool, TestPoolBuilder, }, - BlockInfo, PoolConfig, PoolTransaction, SubPoolLimit, TransactionOrigin, TransactionPool, - TransactionPoolExt, + BlockInfo, PoolConfig, SubPoolLimit, TransactionOrigin, TransactionPool, TransactionPoolExt, }; #[tokio::test(flavor = "multi_thread")] diff --git a/examples/network-txpool/Cargo.toml b/examples/network-txpool/Cargo.toml index 7d4817263..41e2ecaef 100644 --- a/examples/network-txpool/Cargo.toml +++ b/examples/network-txpool/Cargo.toml @@ -6,6 +6,7 @@ edition.workspace = true license.workspace = true [dependencies] +alloy-consensus.workspace = true reth-provider = { workspace = true, features = ["test-utils"] } eyre.workspace = true tokio.workspace = true diff --git a/examples/network-txpool/src/main.rs b/examples/network-txpool/src/main.rs index 716e6cc57..ff066336f 100644 --- a/examples/network-txpool/src/main.rs +++ b/examples/network-txpool/src/main.rs @@ -7,6 +7,7 @@ //! cargo run --release -p network-txpool -- node //! ``` +use alloy_consensus::Transaction; use reth_network::{config::rng_secret_key, EthNetworkPrimitives, NetworkConfig, NetworkManager}; use reth_provider::test_utils::NoopProvider; use reth_transaction_pool::{