feat(txpool): add Block associated type to TransactionValidator trait (#21359)

This commit is contained in:
Arsenii Kulikov
2026-01-23 17:16:05 +04:00
committed by GitHub
parent 22a68756c7
commit 1bd8fab887
16 changed files with 138 additions and 112 deletions

View File

@@ -18,7 +18,7 @@ use reth_evm::{
};
use reth_network::{primitives::BasicNetworkPrimitives, NetworkHandle, PeersInfo};
use reth_node_api::{
AddOnsContext, FullNodeComponents, HeaderTy, NodeAddOns, NodePrimitives,
AddOnsContext, BlockTy, FullNodeComponents, HeaderTy, NodeAddOns, NodePrimitives,
PayloadAttributesBuilder, PrimitivesTy, TxTy,
};
use reth_node_builder::{
@@ -53,8 +53,8 @@ use reth_rpc_eth_types::{error::FromEvmError, EthApiError};
use reth_rpc_server_types::RethRpcModule;
use reth_tracing::tracing::{debug, info};
use reth_transaction_pool::{
blobstore::DiskFileBlobStore, EthTransactionPool, PoolPooledTx, PoolTransaction,
TransactionPool, TransactionValidationTaskExecutor,
blobstore::DiskFileBlobStore, EthPooledTransaction, EthTransactionPool, PoolPooledTx,
PoolTransaction, TransactionPool, TransactionValidationTaskExecutor,
};
use revm::context::TxEnv;
use std::{marker::PhantomData, sync::Arc, time::SystemTime};
@@ -464,7 +464,8 @@ where
>,
Node: FullNodeTypes<Types = Types>,
{
type Pool = EthTransactionPool<Node::Provider, DiskFileBlobStore>;
type Pool =
EthTransactionPool<Node::Provider, DiskFileBlobStore, EthPooledTransaction, BlockTy<Types>>;
async fn build_pool(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Pool> {
let pool_config = ctx.pool_config();

View File

@@ -4,7 +4,7 @@ use crate::{BuilderContext, FullNodeTypes};
use alloy_primitives::Address;
use reth_chain_state::CanonStateSubscriptions;
use reth_chainspec::EthereumHardforks;
use reth_node_api::{NodeTypes, TxTy};
use reth_node_api::{BlockTy, NodeTypes, TxTy};
use reth_transaction_pool::{
blobstore::DiskFileBlobStore, BlobStore, CoinbaseTipOrdering, PoolConfig, PoolTransaction,
SubPoolLimit, TransactionPool, TransactionValidationTaskExecutor, TransactionValidator,
@@ -129,7 +129,7 @@ impl<'a, Node: FullNodeTypes, V> TxPoolBuilder<'a, Node, V> {
impl<'a, Node, V> TxPoolBuilder<'a, Node, TransactionValidationTaskExecutor<V>>
where
Node: FullNodeTypes<Types: NodeTypes<ChainSpec: EthereumHardforks>>,
V: TransactionValidator + 'static,
V: TransactionValidator<Block = BlockTy<Node::Types>> + 'static,
V::Transaction:
PoolTransaction<Consensus = TxTy<Node::Types>> + reth_transaction_pool::EthPoolTransaction,
{
@@ -248,7 +248,7 @@ fn spawn_pool_maintenance_task<Node, Pool>(
) -> eyre::Result<()>
where
Node: FullNodeTypes<Types: NodeTypes<ChainSpec: EthereumHardforks>>,
Pool: reth_transaction_pool::TransactionPoolExt + Clone + 'static,
Pool: reth_transaction_pool::TransactionPoolExt<Block = BlockTy<Node::Types>> + Clone + 'static,
Pool::Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>,
{
let chain_events = ctx.provider().canonical_state_stream();
@@ -280,7 +280,7 @@ pub fn spawn_maintenance_tasks<Node, Pool>(
) -> eyre::Result<()>
where
Node: FullNodeTypes<Types: NodeTypes<ChainSpec: EthereumHardforks>>,
Pool: reth_transaction_pool::TransactionPoolExt + Clone + 'static,
Pool: reth_transaction_pool::TransactionPoolExt<Block = BlockTy<Node::Types>> + Clone + 'static,
Pool::Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>,
{
spawn_local_backup_task(ctx, pool.clone())?;

View File

@@ -16,7 +16,7 @@ use reth_network::{
PeersInfo,
};
use reth_node_api::{
AddOnsContext, BuildNextEnv, EngineTypes, FullNodeComponents, HeaderTy, NodeAddOns,
AddOnsContext, BlockTy, BuildNextEnv, EngineTypes, FullNodeComponents, HeaderTy, NodeAddOns,
NodePrimitives, PayloadAttributesBuilder, PayloadTypes, PrimitivesTy, TxTy,
};
use reth_node_builder::{
@@ -962,7 +962,7 @@ where
Node: FullNodeTypes<Types: NodeTypes<ChainSpec: OpHardforks>>,
T: EthPoolTransaction<Consensus = TxTy<Node::Types>> + OpPooledTx,
{
type Pool = OpTransactionPool<Node::Provider, DiskFileBlobStore, T>;
type Pool = OpTransactionPool<Node::Provider, DiskFileBlobStore, T, BlockTy<Node::Types>>;
async fn build_pool(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Pool> {
let Self { pool_config_overrides, .. } = self;

View File

@@ -9,6 +9,7 @@
#![cfg_attr(docsrs, feature(doc_cfg))]
mod validator;
use op_alloy_consensus::OpBlock;
pub use validator::{OpL1BlockInfo, OpTransactionValidator};
pub mod conditional;
@@ -24,8 +25,8 @@ pub mod estimated_da_size;
use reth_transaction_pool::{CoinbaseTipOrdering, Pool, TransactionValidationTaskExecutor};
/// Type alias for default optimism transaction pool
pub type OpTransactionPool<Client, S, T = OpPooledTransaction> = Pool<
TransactionValidationTaskExecutor<OpTransactionValidator<Client, T>>,
pub type OpTransactionPool<Client, S, T = OpPooledTransaction, B = OpBlock> = Pool<
TransactionValidationTaskExecutor<OpTransactionValidator<Client, T, B>>,
CoinbaseTipOrdering<T>,
S,
>;

View File

@@ -325,10 +325,11 @@ mod tests {
#[tokio::test]
async fn validate_optimism_transaction() {
let client = MockEthProvider::default().with_chain_spec(OP_MAINNET.clone());
let validator = EthTransactionValidatorBuilder::new(client)
.no_shanghai()
.no_cancun()
.build(InMemoryBlobStore::default());
let validator =
EthTransactionValidatorBuilder::new(client)
.no_shanghai()
.no_cancun()
.build::<_, _, reth_optimism_primitives::OpBlock>(InMemoryBlobStore::default());
let validator = OpTransactionValidator::new(validator);
let origin = TransactionOrigin::External;

View File

@@ -1,5 +1,6 @@
use crate::{supervisor::SupervisorClient, InvalidCrossTx, OpPooledTx};
use alloy_consensus::{BlockHeader, Transaction};
use op_alloy_consensus::OpBlock;
use op_revm::L1BlockInfo;
use parking_lot::RwLock;
use reth_chainspec::ChainSpecProvider;
@@ -39,9 +40,9 @@ impl OpL1BlockInfo {
/// Validator for Optimism transactions.
#[derive(Debug, Clone)]
pub struct OpTransactionValidator<Client, Tx> {
pub struct OpTransactionValidator<Client, Tx, B = OpBlock> {
/// The type that performs the actual validation.
inner: Arc<EthTransactionValidator<Client, Tx>>,
inner: Arc<EthTransactionValidator<Client, Tx, B>>,
/// Additional block info required for validation.
block_info: Arc<OpL1BlockInfo>,
/// If true, ensure that the transaction's sender has enough balance to cover the L1 gas fee
@@ -54,7 +55,7 @@ pub struct OpTransactionValidator<Client, Tx> {
fork_tracker: Arc<OpForkTracker>,
}
impl<Client, Tx> OpTransactionValidator<Client, Tx> {
impl<Client, Tx, B: Block> OpTransactionValidator<Client, Tx, B> {
/// Returns the configured chain spec
pub fn chain_spec(&self) -> Arc<Client::ChainSpec>
where
@@ -86,14 +87,15 @@ impl<Client, Tx> OpTransactionValidator<Client, Tx> {
}
}
impl<Client, Tx> OpTransactionValidator<Client, Tx>
impl<Client, Tx, B> OpTransactionValidator<Client, Tx, B>
where
Client:
ChainSpecProvider<ChainSpec: OpHardforks> + StateProviderFactory + BlockReaderIdExt + Sync,
Tx: EthPoolTransaction + OpPooledTx,
B: Block,
{
/// Create a new [`OpTransactionValidator`].
pub fn new(inner: EthTransactionValidator<Client, Tx>) -> Self {
pub fn new(inner: EthTransactionValidator<Client, Tx, B>) -> Self {
let this = Self::with_block_info(inner, OpL1BlockInfo::default());
if let Ok(Some(block)) =
this.inner.client().block_by_number_or_tag(alloy_eips::BlockNumberOrTag::Latest)
@@ -112,7 +114,7 @@ where
/// Create a new [`OpTransactionValidator`] with the given [`OpL1BlockInfo`].
pub fn with_block_info(
inner: EthTransactionValidator<Client, Tx>,
inner: EthTransactionValidator<Client, Tx, B>,
block_info: OpL1BlockInfo,
) -> Self {
Self {
@@ -288,13 +290,15 @@ where
}
}
impl<Client, Tx> TransactionValidator for OpTransactionValidator<Client, Tx>
impl<Client, Tx, B> TransactionValidator for OpTransactionValidator<Client, Tx, B>
where
Client:
ChainSpecProvider<ChainSpec: OpHardforks> + StateProviderFactory + BlockReaderIdExt + Sync,
Tx: EthPoolTransaction + OpPooledTx,
B: Block,
{
type Transaction = Tx;
type Block = B;
async fn validate_transaction(
&self,
@@ -325,10 +329,7 @@ where
.await
}
fn on_new_head_block<B>(&self, new_tip_block: &SealedBlock<B>)
where
B: Block,
{
fn on_new_head_block(&self, new_tip_block: &SealedBlock<Self::Block>) {
self.inner.on_new_head_block(new_tip_block);
self.update_l1_block_info(
new_tip_block.header(),

View File

@@ -303,7 +303,7 @@ use aquamarine as _;
use reth_chainspec::{ChainSpecProvider, EthereumHardforks};
use reth_eth_wire_types::HandleMempoolData;
use reth_execution_types::ChangedAccount;
use reth_primitives_traits::{Block, Recovered};
use reth_primitives_traits::Recovered;
use reth_storage_api::StateProviderFactory;
use std::{collections::HashSet, sync::Arc};
use tokio::sync::mpsc::Receiver;
@@ -328,8 +328,13 @@ mod traits;
pub mod test_utils;
/// Type alias for default ethereum transaction pool
pub type EthTransactionPool<Client, S, T = EthPooledTransaction> = Pool<
TransactionValidationTaskExecutor<EthTransactionValidator<Client, T>>,
pub type EthTransactionPool<
Client,
S,
T = EthPooledTransaction,
B = reth_ethereum_primitives::Block,
> = Pool<
TransactionValidationTaskExecutor<EthTransactionValidator<Client, T, B>>,
CoinbaseTipOrdering<T>,
S,
>;
@@ -776,16 +781,15 @@ where
T: TransactionOrdering<Transaction = <V as TransactionValidator>::Transaction>,
S: BlobStore,
{
type Block = V::Block;
#[instrument(skip(self), target = "txpool")]
fn set_block_info(&self, info: BlockInfo) {
trace!(target: "txpool", "updating pool block info");
self.pool.set_block_info(info)
}
fn on_canonical_state_change<B>(&self, update: CanonicalStateUpdate<'_, B>)
where
B: Block,
{
fn on_canonical_state_change(&self, update: CanonicalStateUpdate<'_, Self::Block>) {
self.pool.on_canonical_state_change(update);
}

View File

@@ -107,7 +107,8 @@ where
+ ChainSpecProvider<ChainSpec: EthChainSpec<Header = N::BlockHeader> + EthereumHardforks>
+ Clone
+ 'static,
P: TransactionPoolExt<Transaction: PoolTransaction<Consensus = N::SignedTx>> + 'static,
P: TransactionPoolExt<Transaction: PoolTransaction<Consensus = N::SignedTx>, Block = N::Block>
+ 'static,
St: Stream<Item = CanonStateNotification<N>> + Send + Unpin + 'static,
Tasks: TaskSpawner + Clone + 'static,
{
@@ -133,7 +134,8 @@ pub async fn maintain_transaction_pool<N, Client, P, St, Tasks>(
+ ChainSpecProvider<ChainSpec: EthChainSpec<Header = N::BlockHeader> + EthereumHardforks>
+ Clone
+ 'static,
P: TransactionPoolExt<Transaction: PoolTransaction<Consensus = N::SignedTx>> + 'static,
P: TransactionPoolExt<Transaction: PoolTransaction<Consensus = N::SignedTx>, Block = N::Block>
+ 'static,
St: Stream<Item = CanonStateNotification<N>> + Send + Unpin + 'static,
Tasks: TaskSpawner + Clone + 'static,
{
@@ -855,7 +857,8 @@ mod tests {
use super::*;
use crate::{
blobstore::InMemoryBlobStore, validate::EthTransactionValidatorBuilder,
CoinbaseTipOrdering, EthPooledTransaction, Pool, TransactionOrigin,
CoinbaseTipOrdering, EthPooledTransaction, EthTransactionValidator, Pool,
TransactionOrigin,
};
use alloy_eips::eip2718::Decodable2718;
use alloy_primitives::{hex, U256};
@@ -889,7 +892,8 @@ mod tests {
let sender = hex!("1f9090aaE28b8a3dCeaDf281B0F12828e676c326").into();
provider.add_account(sender, ExtendedAccount::new(42, U256::MAX));
let blob_store = InMemoryBlobStore::default();
let validator = EthTransactionValidatorBuilder::new(provider).build(blob_store.clone());
let validator: EthTransactionValidator<_, _, reth_ethereum_primitives::Block> =
EthTransactionValidatorBuilder::new(provider).build(blob_store.clone());
let txpool = Pool::new(
validator,

View File

@@ -373,6 +373,7 @@ pub struct MockTransactionValidator<T> {
impl<T: EthPoolTransaction> TransactionValidator for MockTransactionValidator<T> {
type Transaction = T;
type Block = reth_ethereum_primitives::Block;
async fn validate_transaction(
&self,

View File

@@ -114,7 +114,6 @@ pub use events::{FullTransactionEvent, NewTransactionEvent, TransactionEvent};
pub use listener::{AllTransactionsEvents, TransactionEvents, TransactionListenerKind};
pub use parked::{BasefeeOrd, ParkedOrd, ParkedPool, QueuedOrd};
pub use pending::PendingPool;
use reth_primitives_traits::Block;
mod best;
pub use best::BestTransactions;
@@ -504,10 +503,7 @@ where
}
/// Updates the entire pool after a new block was executed.
pub fn on_canonical_state_change<B>(&self, update: CanonicalStateUpdate<'_, B>)
where
B: Block,
{
pub fn on_canonical_state_change(&self, update: CanonicalStateUpdate<'_, V::Block>) {
trace!(target: "txpool", ?update, "updating pool on canonical state change");
let block_info = update.block_info();

View File

@@ -4,6 +4,7 @@ use crate::{
validate::ValidTransaction, EthPooledTransaction, PoolTransaction, TransactionOrigin,
TransactionValidationOutcome, TransactionValidator,
};
use reth_ethereum_primitives::Block;
/// A transaction validator that determines all transactions to be valid.
#[derive(Debug)]
@@ -33,6 +34,7 @@ where
T: PoolTransaction,
{
type Transaction = T;
type Block = Block;
async fn validate_transaction(
&self,

View File

@@ -667,6 +667,9 @@ pub trait TransactionPool: Clone + Debug + Send + Sync {
/// Extension for [`TransactionPool`] trait that allows to set the current block info.
#[auto_impl::auto_impl(&, Arc)]
pub trait TransactionPoolExt: TransactionPool {
/// The block type used for chain tip updates.
type Block: Block;
/// Sets the current block info for the pool.
fn set_block_info(&self, info: BlockInfo);
@@ -685,9 +688,7 @@ pub trait TransactionPoolExt: TransactionPool {
/// sidecar must not be removed from the blob store. Only after a blob transaction is
/// finalized, its sidecar is removed from the blob store. This ensures that in case of a reorg,
/// the sidecar is still available.
fn on_canonical_state_change<B>(&self, update: CanonicalStateUpdate<'_, B>)
where
B: Block;
fn on_canonical_state_change(&self, update: CanonicalStateUpdate<'_, Self::Block>);
/// Updates the accounts in the pool
fn update_accounts(&self, accounts: Vec<ChangedAccount>);

View File

@@ -28,7 +28,7 @@ use alloy_eips::{
use reth_chainspec::{ChainSpecProvider, EthChainSpec, EthereumHardforks};
use reth_primitives_traits::{
constants::MAX_TX_GAS_LIMIT_OSAKA, transaction::error::InvalidTransactionError, Account, Block,
GotExpected, SealedBlock,
GotExpected,
};
use reth_storage_api::{AccountInfoReader, BytecodeReader, StateProviderFactory};
use reth_tasks::TaskSpawner;
@@ -58,7 +58,7 @@ use tokio::sync::Mutex;
///
/// And adheres to the configured [`LocalTransactionConfig`].
#[derive(Debug)]
pub struct EthTransactionValidator<Client, T> {
pub struct EthTransactionValidator<Client, T, B = reth_ethereum_primitives::Block> {
/// This type fetches account info from the db
client: Client,
/// Blobstore used for fetching re-injected blob transactions.
@@ -90,14 +90,14 @@ pub struct EthTransactionValidator<Client, T> {
/// Disable balance checks during transaction validation
disable_balance_check: bool,
/// Marker for the transaction type
_marker: PhantomData<T>,
_marker: PhantomData<(T, B)>,
/// Metrics for tsx pool validation
validation_metrics: TxPoolValidationMetrics,
/// Bitmap of custom transaction types that are allowed.
other_tx_types: U256,
}
impl<Client, Tx> EthTransactionValidator<Client, Tx> {
impl<Client, Tx, B: Block> EthTransactionValidator<Client, Tx, B> {
/// Returns the configured chain spec
pub fn chain_spec(&self) -> Arc<Client::ChainSpec>
where
@@ -176,7 +176,7 @@ impl<Client, Tx> EthTransactionValidator<Client, Tx> {
}
}
impl<Client, Tx> EthTransactionValidator<Client, Tx>
impl<Client, Tx, B: Block> EthTransactionValidator<Client, Tx, B>
where
Client: ChainSpecProvider<ChainSpec: EthereumHardforks> + StateProviderFactory,
Tx: EthPoolTransaction,
@@ -799,12 +799,14 @@ where
}
}
impl<Client, Tx> TransactionValidator for EthTransactionValidator<Client, Tx>
impl<Client, Tx, B> TransactionValidator for EthTransactionValidator<Client, Tx, B>
where
Client: ChainSpecProvider<ChainSpec: EthereumHardforks> + StateProviderFactory,
Tx: EthPoolTransaction,
B: Block,
{
type Transaction = Tx;
type Block = B;
async fn validate_transaction(
&self,
@@ -829,11 +831,8 @@ where
self.validate_batch_with_origin(origin, transactions)
}
fn on_new_head_block<B>(&self, new_tip_block: &SealedBlock<B>)
where
B: Block,
{
self.on_new_head_block(new_tip_block.header())
fn on_new_head_block(&self, new_tip_block: &reth_primitives_traits::SealedBlock<Self::Block>) {
Self::on_new_head_block(self, new_tip_block.header())
}
}
@@ -1105,9 +1104,10 @@ impl<Client> EthTransactionValidatorBuilder<Client> {
}
/// Builds a the [`EthTransactionValidator`] without spawning validator tasks.
pub fn build<Tx, S>(self, blob_store: S) -> EthTransactionValidator<Client, Tx>
pub fn build<Tx, S, B>(self, blob_store: S) -> EthTransactionValidator<Client, Tx, B>
where
S: BlobStore,
B: Block,
{
let Self {
client,
@@ -1170,17 +1170,18 @@ impl<Client> EthTransactionValidatorBuilder<Client> {
/// The validator will spawn `additional_tasks` additional tasks for validation.
///
/// By default this will spawn 1 additional task.
pub fn build_with_tasks<Tx, T, S>(
pub fn build_with_tasks<Tx, T, S, B>(
self,
tasks: T,
blob_store: S,
) -> TransactionValidationTaskExecutor<EthTransactionValidator<Client, Tx>>
) -> TransactionValidationTaskExecutor<EthTransactionValidator<Client, Tx, B>>
where
T: TaskSpawner,
S: BlobStore,
B: Block,
{
let additional_tasks = self.additional_tasks;
let validator = self.build(blob_store);
let validator = self.build::<Tx, S, B>(blob_store);
let (tx, task) = ValidationTask::new();
@@ -1341,7 +1342,8 @@ mod tests {
ExtendedAccount::new(transaction.nonce(), U256::MAX),
);
let blob_store = InMemoryBlobStore::default();
let validator = EthTransactionValidatorBuilder::new(provider).build(blob_store.clone());
let validator: EthTransactionValidator<_, _> =
EthTransactionValidatorBuilder::new(provider).build(blob_store.clone());
let outcome = validator.validate_one(TransactionOrigin::External, transaction.clone());
@@ -1368,9 +1370,10 @@ mod tests {
);
let blob_store = InMemoryBlobStore::default();
let validator = EthTransactionValidatorBuilder::new(provider)
.set_block_gas_limit(1_000_000) // tx gas limit is 1_015_288
.build(blob_store.clone());
let validator: EthTransactionValidator<_, _> =
EthTransactionValidatorBuilder::new(provider)
.set_block_gas_limit(1_000_000) // tx gas limit is 1_015_288
.build(blob_store.clone());
let outcome = validator.validate_one(TransactionOrigin::External, transaction.clone());
@@ -1401,9 +1404,10 @@ mod tests {
);
let blob_store = InMemoryBlobStore::default();
let validator = EthTransactionValidatorBuilder::new(provider)
.set_tx_fee_cap(100) // 100 wei cap
.build(blob_store.clone());
let validator: EthTransactionValidator<_, _> =
EthTransactionValidatorBuilder::new(provider)
.set_tx_fee_cap(100) // 100 wei cap
.build(blob_store.clone());
let outcome = validator.validate_one(TransactionOrigin::Local, transaction.clone());
assert!(outcome.is_invalid());
@@ -1438,9 +1442,10 @@ mod tests {
);
let blob_store = InMemoryBlobStore::default();
let validator = EthTransactionValidatorBuilder::new(provider)
.set_tx_fee_cap(0) // no cap
.build(blob_store);
let validator: EthTransactionValidator<_, _> =
EthTransactionValidatorBuilder::new(provider)
.set_tx_fee_cap(0) // no cap
.build(blob_store);
let outcome = validator.validate_one(TransactionOrigin::Local, transaction);
assert!(outcome.is_valid());
@@ -1456,9 +1461,10 @@ mod tests {
);
let blob_store = InMemoryBlobStore::default();
let validator = EthTransactionValidatorBuilder::new(provider)
.set_tx_fee_cap(2e18 as u128) // 2 ETH cap
.build(blob_store);
let validator: EthTransactionValidator<_, _> =
EthTransactionValidatorBuilder::new(provider)
.set_tx_fee_cap(2e18 as u128) // 2 ETH cap
.build(blob_store);
let outcome = validator.validate_one(TransactionOrigin::Local, transaction);
assert!(outcome.is_valid());
@@ -1474,9 +1480,10 @@ mod tests {
);
let blob_store = InMemoryBlobStore::default();
let validator = EthTransactionValidatorBuilder::new(provider)
.with_max_tx_gas_limit(Some(500_000)) // Set limit lower than transaction gas limit (1_015_288)
.build(blob_store.clone());
let validator: EthTransactionValidator<_, _> =
EthTransactionValidatorBuilder::new(provider)
.with_max_tx_gas_limit(Some(500_000)) // Set limit lower than transaction gas limit (1_015_288)
.build(blob_store.clone());
let outcome = validator.validate_one(TransactionOrigin::External, transaction.clone());
assert!(outcome.is_invalid());
@@ -1506,9 +1513,10 @@ mod tests {
);
let blob_store = InMemoryBlobStore::default();
let validator = EthTransactionValidatorBuilder::new(provider)
.with_max_tx_gas_limit(None) // disabled
.build(blob_store);
let validator: EthTransactionValidator<_, _> =
EthTransactionValidatorBuilder::new(provider)
.with_max_tx_gas_limit(None) // disabled
.build(blob_store);
let outcome = validator.validate_one(TransactionOrigin::External, transaction);
assert!(outcome.is_valid());
@@ -1524,9 +1532,10 @@ mod tests {
);
let blob_store = InMemoryBlobStore::default();
let validator = EthTransactionValidatorBuilder::new(provider)
.with_max_tx_gas_limit(Some(2_000_000)) // Set limit higher than transaction gas limit (1_015_288)
.build(blob_store);
let validator: EthTransactionValidator<_, _> =
EthTransactionValidatorBuilder::new(provider)
.with_max_tx_gas_limit(Some(2_000_000)) // Set limit higher than transaction gas limit (1_015_288)
.build(blob_store);
let outcome = validator.validate_one(TransactionOrigin::External, transaction);
assert!(outcome.is_valid());
@@ -1727,8 +1736,9 @@ mod tests {
);
// Validate with balance check enabled
let validator = EthTransactionValidatorBuilder::new(provider.clone())
.build(InMemoryBlobStore::default());
let validator: EthTransactionValidator<_, _> =
EthTransactionValidatorBuilder::new(provider.clone())
.build(InMemoryBlobStore::default());
let outcome = validator.validate_one(TransactionOrigin::External, transaction.clone());
let expected_cost = *transaction.cost();
@@ -1743,9 +1753,10 @@ mod tests {
}
// Validate with balance check disabled
let validator = EthTransactionValidatorBuilder::new(provider)
.disable_balance_check() // This should allow the transaction through despite zero balance
.build(InMemoryBlobStore::default());
let validator: EthTransactionValidator<_, _> =
EthTransactionValidatorBuilder::new(provider)
.disable_balance_check()
.build(InMemoryBlobStore::default());
let outcome = validator.validate_one(TransactionOrigin::External, transaction);
assert!(outcome.is_valid()); // Should be valid because balance check is disabled

View File

@@ -9,7 +9,7 @@ use crate::{
use alloy_eips::{eip7594::BlobTransactionSidecarVariant, eip7702::SignedAuthorization};
use alloy_primitives::{Address, TxHash, B256, U256};
use futures_util::future::Either;
use reth_primitives_traits::{Recovered, SealedBlock};
use reth_primitives_traits::{Block, Recovered, SealedBlock};
use std::{fmt, fmt::Debug, future::Future, time::Instant};
mod constants;
@@ -24,7 +24,6 @@ pub use task::{TransactionValidationTaskExecutor, ValidationTask};
pub use constants::{
DEFAULT_MAX_TX_INPUT_BYTES, MAX_CODE_BYTE_SIZE, MAX_INIT_CODE_BYTE_SIZE, TX_SLOT_BYTE_SIZE,
};
use reth_primitives_traits::Block;
/// A Result type returned after checking a transaction's validity.
#[derive(Debug)]
@@ -174,6 +173,9 @@ pub trait TransactionValidator: Debug + Send + Sync {
/// The transaction type to validate.
type Transaction: PoolTransaction;
/// The block type used for new head block notifications.
type Block: Block;
/// Validates the transaction and returns a [`TransactionValidationOutcome`] describing the
/// validity of the given transaction.
///
@@ -236,19 +238,16 @@ pub trait TransactionValidator: Debug + Send + Sync {
/// Invoked when the head block changes.
///
/// This can be used to update fork specific values (timestamp).
fn on_new_head_block<B>(&self, _new_tip_block: &SealedBlock<B>)
where
B: Block,
{
}
fn on_new_head_block(&self, _new_tip_block: &SealedBlock<Self::Block>) {}
}
impl<A, B> TransactionValidator for Either<A, B>
where
A: TransactionValidator,
B: TransactionValidator<Transaction = A::Transaction>,
B: TransactionValidator<Transaction = A::Transaction, Block = A::Block>,
{
type Transaction = A::Transaction;
type Block = A::Block;
async fn validate_transaction(
&self,
@@ -282,10 +281,7 @@ where
}
}
fn on_new_head_block<Bl>(&self, new_tip_block: &SealedBlock<Bl>)
where
Bl: Block,
{
fn on_new_head_block(&self, new_tip_block: &SealedBlock<Self::Block>) {
match self {
Self::Left(v) => v.on_new_head_block(new_tip_block),
Self::Right(v) => v.on_new_head_block(new_tip_block),

View File

@@ -8,7 +8,7 @@ use crate::{
TransactionValidator,
};
use futures_util::{lock::Mutex, StreamExt};
use reth_primitives_traits::{Block, SealedBlock};
use reth_primitives_traits::SealedBlock;
use reth_tasks::TaskSpawner;
use std::{future::Future, pin::Pin, sync::Arc};
use tokio::{
@@ -171,7 +171,7 @@ impl<Client, Tx> TransactionValidationTaskExecutor<EthTransactionValidator<Clien
{
EthTransactionValidatorBuilder::new(client)
.with_additional_tasks(num_additional_tasks)
.build_with_tasks::<Tx, T, S>(tasks, blob_store)
.build_with_tasks(tasks, blob_store)
}
}
@@ -197,6 +197,7 @@ where
V: TransactionValidator + 'static,
{
type Transaction = <V as TransactionValidator>::Transaction;
type Block = V::Block;
async fn validate_transaction(
&self,
@@ -284,10 +285,7 @@ where
self.validate_transactions(transactions.into_iter().map(|tx| (origin, tx)).collect()).await
}
fn on_new_head_block<B>(&self, new_tip_block: &SealedBlock<B>)
where
B: Block,
{
fn on_new_head_block(&self, new_tip_block: &SealedBlock<Self::Block>) {
self.validator.on_new_head_block(new_tip_block)
}
}
@@ -307,6 +305,7 @@ mod tests {
impl TransactionValidator for NoopValidator {
type Transaction = MockTransaction;
type Block = reth_ethereum_primitives::Block;
async fn validate_transaction(
&self,

View File

@@ -6,14 +6,14 @@ use reth_ethereum::{
chainspec::ChainSpec,
cli::interface::Cli,
node::{
api::{FullNodeTypes, NodeTypes},
api::{BlockTy, FullNodeTypes, NodeTypes},
builder::{components::PoolBuilder, BuilderContext},
node::EthereumAddOns,
EthereumNode,
},
pool::{
blobstore::InMemoryBlobStore, EthTransactionPool, PoolConfig,
TransactionValidationTaskExecutor,
blobstore::InMemoryBlobStore, CoinbaseTipOrdering, EthPooledTransaction,
EthTransactionPool, Pool, PoolConfig, TransactionValidationTaskExecutor,
},
provider::CanonStateSubscriptions,
EthPrimitives,
@@ -53,7 +53,12 @@ impl<Node> PoolBuilder<Node> for CustomPoolBuilder
where
Node: FullNodeTypes<Types: NodeTypes<ChainSpec = ChainSpec, Primitives = EthPrimitives>>,
{
type Pool = EthTransactionPool<Node::Provider, InMemoryBlobStore>;
type Pool = EthTransactionPool<
Node::Provider,
InMemoryBlobStore,
EthPooledTransaction,
BlockTy<Node::Types>,
>;
async fn build_pool(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Pool> {
let data_dir = ctx.config().datadir();
@@ -62,10 +67,13 @@ where
.with_head_timestamp(ctx.head().timestamp)
.kzg_settings(ctx.kzg_settings()?)
.with_additional_tasks(ctx.config().txpool.additional_validation_tasks)
.build_with_tasks(ctx.task_executor().clone(), blob_store.clone());
.build_with_tasks::<_, _, _, BlockTy<Node::Types>>(
ctx.task_executor().clone(),
blob_store.clone(),
);
let transaction_pool =
reth_ethereum::pool::Pool::eth_pool(validator, blob_store, self.pool_config);
Pool::new(validator, CoinbaseTipOrdering::default(), blob_store, self.pool_config);
info!(target: "reth::cli", "Transaction pool initialized");
let transactions_path = data_dir.txpool_transactions();