mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-02-19 03:04:27 -05:00
feat(txpool): add Block associated type to TransactionValidator trait (#21359)
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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())?;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
>;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user