diff --git a/crates/transaction-pool/src/noop.rs b/crates/transaction-pool/src/noop.rs index 2f17b3c43b76..0c0aa860662d 100644 --- a/crates/transaction-pool/src/noop.rs +++ b/crates/transaction-pool/src/noop.rs @@ -4,11 +4,11 @@ //! to be generic over it. use crate::{ - error::PoolError, traits::PendingTransactionListenerKind, AllPoolTransactions, - AllTransactionsEvents, BestTransactions, BlockInfo, EthPooledTransaction, NewTransactionEvent, - PoolResult, PoolSize, PoolTransaction, PropagatedTransactions, TransactionEvents, - TransactionOrigin, TransactionPool, TransactionValidationOutcome, TransactionValidator, - ValidPoolTransaction, + error::PoolError, traits::PendingTransactionListenerKind, validate::ValidTransaction, + AllPoolTransactions, AllTransactionsEvents, BestTransactions, BlockInfo, EthPooledTransaction, + NewTransactionEvent, PoolResult, PoolSize, PoolTransaction, PropagatedTransactions, + TransactionEvents, TransactionOrigin, TransactionPool, TransactionValidationOutcome, + TransactionValidator, ValidPoolTransaction, }; use reth_primitives::{Address, TxHash}; use std::{collections::HashSet, marker::PhantomData, sync::Arc}; @@ -184,7 +184,7 @@ impl TransactionValidator for MockTransactionValidator { TransactionValidationOutcome::Valid { balance: Default::default(), state_nonce: 0, - transaction, + transaction: ValidTransaction::Valid(transaction), propagate: match origin { TransactionOrigin::External => true, TransactionOrigin::Local => self.propagate_local, diff --git a/crates/transaction-pool/src/pool/mod.rs b/crates/transaction-pool/src/pool/mod.rs index 5056a3905487..940fff3d0b79 100644 --- a/crates/transaction-pool/src/pool/mod.rs +++ b/crates/transaction-pool/src/pool/mod.rs @@ -96,7 +96,9 @@ mod events; pub use events::{FullTransactionEvent, TransactionEvent}; mod listener; -use crate::{pool::txpool::UpdateOutcome, traits::PendingTransactionListenerKind}; +use crate::{ + pool::txpool::UpdateOutcome, traits::PendingTransactionListenerKind, validate::ValidTransaction, +}; pub use listener::{AllTransactionsEvents, TransactionEvents}; mod best; @@ -314,6 +316,17 @@ where let transaction_id = TransactionId::new(sender_id, transaction.nonce()); let encoded_length = transaction.encoded_length(); + let (transaction, _maybe_sidecar) = match transaction { + ValidTransaction::Valid(tx) => (tx, None), + ValidTransaction::ValidWithSidecar { transaction, sidecar } => { + debug_assert!( + transaction.is_eip4844(), + "validator returned sidecar for non EIP-4844 transaction" + ); + (transaction, Some(sidecar)) + } + }; + let tx = ValidPoolTransaction { transaction, transaction_id, diff --git a/crates/transaction-pool/src/validate/eth.rs b/crates/transaction-pool/src/validate/eth.rs index 7bf3ecb94cd5..0c0e5e3f2757 100644 --- a/crates/transaction-pool/src/validate/eth.rs +++ b/crates/transaction-pool/src/validate/eth.rs @@ -4,8 +4,8 @@ use crate::{ error::InvalidPoolTransactionError, traits::{PoolTransaction, TransactionOrigin}, validate::{ - task::ValidationJobSender, TransactionValidatorError, ValidationTask, MAX_INIT_CODE_SIZE, - TX_MAX_SIZE, + task::ValidationJobSender, TransactionValidatorError, ValidTransaction, ValidationTask, + MAX_INIT_CODE_SIZE, TX_MAX_SIZE, }, TransactionValidationOutcome, TransactionValidator, }; @@ -499,7 +499,7 @@ where TransactionValidationOutcome::Valid { balance: account.balance, state_nonce: account.nonce, - transaction, + transaction: ValidTransaction::Valid(transaction), // by this point assume all external transactions should be propagated propagate: match origin { TransactionOrigin::External => true, diff --git a/crates/transaction-pool/src/validate/mod.rs b/crates/transaction-pool/src/validate/mod.rs index 989f7cc78d3f..37bc883ca1f6 100644 --- a/crates/transaction-pool/src/validate/mod.rs +++ b/crates/transaction-pool/src/validate/mod.rs @@ -6,7 +6,8 @@ use crate::{ traits::{PoolTransaction, TransactionOrigin}, }; use reth_primitives::{ - Address, IntoRecoveredTransaction, TransactionKind, TransactionSignedEcRecovered, TxHash, U256, + Address, BlobTransactionSidecar, IntoRecoveredTransaction, TransactionKind, + TransactionSignedEcRecovered, TxHash, H256, U256, }; use std::{fmt, time::Instant}; @@ -32,9 +33,13 @@ pub enum TransactionValidationOutcome { balance: U256, /// Current nonce of the sender. state_nonce: u64, - /// Validated transaction. - // TODO add enum type for blob,regular? - transaction: T, + /// The validated transaction. + /// + /// See also [ValidTransaction]. + /// + /// If this is a _new_ EIP-4844 blob transaction, then this must contain the extracted + /// sidecar. + transaction: ValidTransaction, /// Whether to propagate the transaction to the network. propagate: bool, }, @@ -56,6 +61,65 @@ impl TransactionValidationOutcome { } } +/// A wrapper type for a transaction that is valid and has an optional extracted EIP-4844 blob +/// transaction sidecar. +/// +/// If this is provided, then the sidecar will be temporarily stored in the blob store until the +/// transaction is finalized. +/// +/// Note: Since blob transactions can be re-injected without their sidecar (after reorg), the +/// validator can omit the sidecar if it is still in the blob store and return a +/// [ValidTransaction::Valid] instead. +#[derive(Debug)] +pub enum ValidTransaction { + /// A valid transaction without a sidecar. + Valid(T), + /// A valid transaction for which a sidecar should be stored. + /// + /// Caution: The [TransactionValidator] must ensure that this is only returned for EIP-4844 + /// transactions. + ValidWithSidecar { + /// The valid EIP-4844 transaction. + transaction: T, + /// The extracted sidecar of that transaction + sidecar: BlobTransactionSidecar, + }, +} + +impl ValidTransaction { + #[inline] + pub(crate) fn transaction(&self) -> &T { + match self { + Self::Valid(transaction) => transaction, + Self::ValidWithSidecar { transaction, .. } => transaction, + } + } + + /// Returns the address of that transaction. + #[inline] + pub(crate) fn sender(&self) -> Address { + self.transaction().sender() + } + + /// Returns the hash of the transaction. + #[inline] + pub(crate) fn hash(&self) -> &H256 { + self.transaction().hash() + } + + /// Returns the length of the rlp encoded object + #[inline] + pub(crate) fn encoded_length(&self) -> usize { + self.transaction().encoded_length() + } + + /// Returns the nonce of the transaction. + #[inline] + pub(crate) fn nonce(&self) -> u64 { + self.transaction().nonce() + } +} + /// Provides support for validating transaction at any given state of the chain #[async_trait::async_trait] pub trait TransactionValidator: Send + Sync { @@ -113,6 +177,11 @@ pub trait TransactionValidator: Send + Sync { } /// A valid transaction in the pool. +/// +/// This is used as the internal representation of a transaction inside the pool. +/// +/// For EIP-4844 blob transactions this will _not_ contain the blob sidecar which is stored +/// separately in the [BlobStore](crate::blobstore::BlobStore). pub struct ValidPoolTransaction { /// The transaction pub transaction: T, diff --git a/examples/network-txpool.rs b/examples/network-txpool.rs index afb854460ccb..84e605b883db 100644 --- a/examples/network-txpool.rs +++ b/examples/network-txpool.rs @@ -10,8 +10,8 @@ use reth_network::{config::rng_secret_key, NetworkConfig, NetworkManager}; use reth_provider::test_utils::NoopProvider; use reth_transaction_pool::{ - CoinbaseTipOrdering, EthPooledTransaction, PoolTransaction, TransactionOrigin, TransactionPool, - TransactionValidationOutcome, TransactionValidator, + validate::ValidTransaction, CoinbaseTipOrdering, EthPooledTransaction, PoolTransaction, + TransactionOrigin, TransactionPool, TransactionValidationOutcome, TransactionValidator, }; #[tokio::main] @@ -79,7 +79,7 @@ impl TransactionValidator for OkValidator { TransactionValidationOutcome::Valid { balance: transaction.cost(), state_nonce: transaction.nonce(), - transaction, + transaction: ValidTransaction::Valid(transaction), propagate: false, } }