mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
chore(util): Add reth payload util (#12590)
This commit is contained in:
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -8324,6 +8324,7 @@ dependencies = [
|
|||||||
"reth-optimism-payload-builder",
|
"reth-optimism-payload-builder",
|
||||||
"reth-optimism-rpc",
|
"reth-optimism-rpc",
|
||||||
"reth-payload-builder",
|
"reth-payload-builder",
|
||||||
|
"reth-payload-util",
|
||||||
"reth-primitives",
|
"reth-primitives",
|
||||||
"reth-provider",
|
"reth-provider",
|
||||||
"reth-revm",
|
"reth-revm",
|
||||||
@ -8359,6 +8360,7 @@ dependencies = [
|
|||||||
"reth-optimism-forks",
|
"reth-optimism-forks",
|
||||||
"reth-payload-builder",
|
"reth-payload-builder",
|
||||||
"reth-payload-primitives",
|
"reth-payload-primitives",
|
||||||
|
"reth-payload-util",
|
||||||
"reth-primitives",
|
"reth-primitives",
|
||||||
"reth-provider",
|
"reth-provider",
|
||||||
"reth-revm",
|
"reth-revm",
|
||||||
@ -8486,6 +8488,15 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "reth-payload-util"
|
||||||
|
version = "1.1.1"
|
||||||
|
dependencies = [
|
||||||
|
"alloy-consensus",
|
||||||
|
"alloy-primitives",
|
||||||
|
"reth-primitives",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reth-payload-validator"
|
name = "reth-payload-validator"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
@ -9265,6 +9276,7 @@ dependencies = [
|
|||||||
"reth-execution-types",
|
"reth-execution-types",
|
||||||
"reth-fs-util",
|
"reth-fs-util",
|
||||||
"reth-metrics",
|
"reth-metrics",
|
||||||
|
"reth-payload-util",
|
||||||
"reth-primitives",
|
"reth-primitives",
|
||||||
"reth-primitives-traits",
|
"reth-primitives-traits",
|
||||||
"reth-provider",
|
"reth-provider",
|
||||||
|
|||||||
@ -82,6 +82,7 @@ members = [
|
|||||||
"crates/payload/builder/",
|
"crates/payload/builder/",
|
||||||
"crates/payload/primitives/",
|
"crates/payload/primitives/",
|
||||||
"crates/payload/validator/",
|
"crates/payload/validator/",
|
||||||
|
"crates/payload/util/",
|
||||||
"crates/primitives-traits/",
|
"crates/primitives-traits/",
|
||||||
"crates/primitives/",
|
"crates/primitives/",
|
||||||
"crates/prune/prune",
|
"crates/prune/prune",
|
||||||
@ -381,6 +382,7 @@ reth-optimism-storage = { path = "crates/optimism/storage" }
|
|||||||
reth-payload-builder = { path = "crates/payload/builder" }
|
reth-payload-builder = { path = "crates/payload/builder" }
|
||||||
reth-payload-primitives = { path = "crates/payload/primitives" }
|
reth-payload-primitives = { path = "crates/payload/primitives" }
|
||||||
reth-payload-validator = { path = "crates/payload/validator" }
|
reth-payload-validator = { path = "crates/payload/validator" }
|
||||||
|
reth-payload-util = { path = "crates/payload/util" }
|
||||||
reth-primitives = { path = "crates/primitives", default-features = false, features = [
|
reth-primitives = { path = "crates/primitives", default-features = false, features = [
|
||||||
"std",
|
"std",
|
||||||
] }
|
] }
|
||||||
|
|||||||
@ -16,6 +16,7 @@ reth-chainspec.workspace = true
|
|||||||
reth-engine-local.workspace = true
|
reth-engine-local.workspace = true
|
||||||
reth-primitives.workspace = true
|
reth-primitives.workspace = true
|
||||||
reth-payload-builder.workspace = true
|
reth-payload-builder.workspace = true
|
||||||
|
reth-payload-util.workspace = true
|
||||||
reth-basic-payload-builder.workspace = true
|
reth-basic-payload-builder.workspace = true
|
||||||
reth-consensus.workspace = true
|
reth-consensus.workspace = true
|
||||||
reth-node-api.workspace = true
|
reth-node-api.workspace = true
|
||||||
|
|||||||
@ -25,12 +25,10 @@ use reth_optimism_node::{
|
|||||||
OpEngineTypes, OpNode,
|
OpEngineTypes, OpNode,
|
||||||
};
|
};
|
||||||
use reth_optimism_payload_builder::builder::OpPayloadTransactions;
|
use reth_optimism_payload_builder::builder::OpPayloadTransactions;
|
||||||
|
use reth_payload_util::{PayloadTransactions, PayloadTransactionsChain, PayloadTransactionsFixed};
|
||||||
use reth_primitives::{SealedBlock, Transaction, TransactionSigned, TransactionSignedEcRecovered};
|
use reth_primitives::{SealedBlock, Transaction, TransactionSigned, TransactionSignedEcRecovered};
|
||||||
use reth_provider::providers::BlockchainProvider2;
|
use reth_provider::providers::BlockchainProvider2;
|
||||||
use reth_transaction_pool::{
|
use reth_transaction_pool::pool::BestPayloadTransactions;
|
||||||
pool::{BestPayloadTransactions, PayloadTransactionsChain, PayloadTransactionsFixed},
|
|
||||||
PayloadTransactions,
|
|
||||||
};
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
|||||||
@ -22,6 +22,7 @@ reth-rpc-types-compat.workspace = true
|
|||||||
reth-evm.workspace = true
|
reth-evm.workspace = true
|
||||||
reth-execution-types.workspace = true
|
reth-execution-types.workspace = true
|
||||||
reth-payload-builder.workspace = true
|
reth-payload-builder.workspace = true
|
||||||
|
reth-payload-util.workspace = true
|
||||||
reth-payload-primitives = { workspace = true, features = ["op"] }
|
reth-payload-primitives = { workspace = true, features = ["op"] }
|
||||||
reth-basic-payload-builder.workspace = true
|
reth-basic-payload-builder.workspace = true
|
||||||
reth-trie.workspace = true
|
reth-trie.workspace = true
|
||||||
|
|||||||
@ -16,6 +16,7 @@ use reth_optimism_chainspec::OpChainSpec;
|
|||||||
use reth_optimism_consensus::calculate_receipt_root_no_memo_optimism;
|
use reth_optimism_consensus::calculate_receipt_root_no_memo_optimism;
|
||||||
use reth_optimism_forks::OpHardforks;
|
use reth_optimism_forks::OpHardforks;
|
||||||
use reth_payload_primitives::{PayloadBuilderAttributes, PayloadBuilderError};
|
use reth_payload_primitives::{PayloadBuilderAttributes, PayloadBuilderError};
|
||||||
|
use reth_payload_util::PayloadTransactions;
|
||||||
use reth_primitives::{
|
use reth_primitives::{
|
||||||
proofs,
|
proofs,
|
||||||
revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg},
|
revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg},
|
||||||
@ -24,7 +25,7 @@ use reth_primitives::{
|
|||||||
use reth_provider::{ProviderError, StateProofProvider, StateProviderFactory, StateRootProvider};
|
use reth_provider::{ProviderError, StateProofProvider, StateProviderFactory, StateRootProvider};
|
||||||
use reth_revm::database::StateProviderDatabase;
|
use reth_revm::database::StateProviderDatabase;
|
||||||
use reth_transaction_pool::{
|
use reth_transaction_pool::{
|
||||||
noop::NoopTransactionPool, BestTransactionsAttributes, PayloadTransactions, TransactionPool,
|
noop::NoopTransactionPool, BestTransactionsAttributes, TransactionPool,
|
||||||
};
|
};
|
||||||
use reth_trie::HashedPostState;
|
use reth_trie::HashedPostState;
|
||||||
use revm::{
|
use revm::{
|
||||||
|
|||||||
20
crates/payload/util/Cargo.toml
Normal file
20
crates/payload/util/Cargo.toml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
[package]
|
||||||
|
name = "reth-payload-util"
|
||||||
|
version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
homepage.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
description = "reth payload utilities"
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# reth
|
||||||
|
reth-primitives.workspace = true
|
||||||
|
|
||||||
|
# alloy
|
||||||
|
alloy-primitives.workspace = true
|
||||||
|
alloy-consensus.workspace = true
|
||||||
15
crates/payload/util/src/lib.rs
Normal file
15
crates/payload/util/src/lib.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//! payload utils.
|
||||||
|
|
||||||
|
#![doc(
|
||||||
|
html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
|
||||||
|
html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
|
||||||
|
issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
|
||||||
|
)]
|
||||||
|
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
||||||
|
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||||
|
|
||||||
|
mod traits;
|
||||||
|
mod transaction;
|
||||||
|
|
||||||
|
pub use traits::PayloadTransactions;
|
||||||
|
pub use transaction::{PayloadTransactionsChain, PayloadTransactionsFixed};
|
||||||
20
crates/payload/util/src/traits.rs
Normal file
20
crates/payload/util/src/traits.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use alloy_primitives::Address;
|
||||||
|
use reth_primitives::TransactionSignedEcRecovered;
|
||||||
|
|
||||||
|
/// Iterator that returns transactions for the block building process in the order they should be
|
||||||
|
/// included in the block.
|
||||||
|
///
|
||||||
|
/// Can include transactions from the pool and other sources (alternative pools,
|
||||||
|
/// sequencer-originated transactions, etc.).
|
||||||
|
pub trait PayloadTransactions {
|
||||||
|
/// Returns the next transaction to include in the block.
|
||||||
|
fn next(
|
||||||
|
&mut self,
|
||||||
|
// In the future, `ctx` can include access to state for block building purposes.
|
||||||
|
ctx: (),
|
||||||
|
) -> Option<TransactionSignedEcRecovered>;
|
||||||
|
|
||||||
|
/// Exclude descendants of the transaction with given sender and nonce from the iterator,
|
||||||
|
/// because this transaction won't be included in the block.
|
||||||
|
fn mark_invalid(&mut self, sender: Address, nonce: u64);
|
||||||
|
}
|
||||||
128
crates/payload/util/src/transaction.rs
Normal file
128
crates/payload/util/src/transaction.rs
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
use crate::PayloadTransactions;
|
||||||
|
use alloy_consensus::Transaction;
|
||||||
|
use alloy_primitives::Address;
|
||||||
|
use reth_primitives::TransactionSignedEcRecovered;
|
||||||
|
|
||||||
|
/// An implementation of [`crate::traits::PayloadTransactions`] that yields
|
||||||
|
/// a pre-defined set of transactions.
|
||||||
|
///
|
||||||
|
/// This is useful to put a sequencer-specified set of transactions into the block
|
||||||
|
/// and compose it with the rest of the transactions.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PayloadTransactionsFixed<T> {
|
||||||
|
transactions: Vec<T>,
|
||||||
|
index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PayloadTransactionsFixed<T> {
|
||||||
|
/// Constructs a new [`PayloadTransactionsFixed`].
|
||||||
|
pub fn new(transactions: Vec<T>) -> Self {
|
||||||
|
Self { transactions, index: Default::default() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a new [`PayloadTransactionsFixed`] with a single transaction.
|
||||||
|
pub fn single(transaction: T) -> Self {
|
||||||
|
Self { transactions: vec![transaction], index: Default::default() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PayloadTransactions for PayloadTransactionsFixed<TransactionSignedEcRecovered> {
|
||||||
|
fn next(&mut self, _ctx: ()) -> Option<TransactionSignedEcRecovered> {
|
||||||
|
(self.index < self.transactions.len()).then(|| {
|
||||||
|
let tx = self.transactions[self.index].clone();
|
||||||
|
self.index += 1;
|
||||||
|
tx
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_invalid(&mut self, _sender: Address, _nonce: u64) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapper over [`crate::traits::PayloadTransactions`] that combines transactions from multiple
|
||||||
|
/// `PayloadTransactions` iterators and keeps track of the gas for both of iterators.
|
||||||
|
///
|
||||||
|
/// We can't use [`Iterator::chain`], because:
|
||||||
|
/// (a) we need to propagate the `mark_invalid` and `no_updates`
|
||||||
|
/// (b) we need to keep track of the gas
|
||||||
|
///
|
||||||
|
/// Notes that [`PayloadTransactionsChain`] fully drains the first iterator
|
||||||
|
/// before moving to the second one.
|
||||||
|
///
|
||||||
|
/// If the `before` iterator has transactions that are not fitting into the block,
|
||||||
|
/// the after iterator will get propagated a `mark_invalid` call for each of them.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PayloadTransactionsChain<B: PayloadTransactions, A: PayloadTransactions> {
|
||||||
|
/// Iterator that will be used first
|
||||||
|
before: B,
|
||||||
|
/// Allowed gas for the transactions from `before` iterator. If `None`, no gas limit is
|
||||||
|
/// enforced.
|
||||||
|
before_max_gas: Option<u64>,
|
||||||
|
/// Gas used by the transactions from `before` iterator
|
||||||
|
before_gas: u64,
|
||||||
|
/// Iterator that will be used after `before` iterator
|
||||||
|
after: A,
|
||||||
|
/// Allowed gas for the transactions from `after` iterator. If `None`, no gas limit is
|
||||||
|
/// enforced.
|
||||||
|
after_max_gas: Option<u64>,
|
||||||
|
/// Gas used by the transactions from `after` iterator
|
||||||
|
after_gas: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: PayloadTransactions, A: PayloadTransactions> PayloadTransactionsChain<B, A> {
|
||||||
|
/// Constructs a new [`PayloadTransactionsChain`].
|
||||||
|
pub fn new(
|
||||||
|
before: B,
|
||||||
|
before_max_gas: Option<u64>,
|
||||||
|
after: A,
|
||||||
|
after_max_gas: Option<u64>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
before,
|
||||||
|
before_max_gas,
|
||||||
|
before_gas: Default::default(),
|
||||||
|
after,
|
||||||
|
after_max_gas,
|
||||||
|
after_gas: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B, A> PayloadTransactions for PayloadTransactionsChain<B, A>
|
||||||
|
where
|
||||||
|
B: PayloadTransactions,
|
||||||
|
A: PayloadTransactions,
|
||||||
|
{
|
||||||
|
fn next(&mut self, ctx: ()) -> Option<TransactionSignedEcRecovered> {
|
||||||
|
while let Some(tx) = self.before.next(ctx) {
|
||||||
|
if let Some(before_max_gas) = self.before_max_gas {
|
||||||
|
if self.before_gas + tx.transaction.gas_limit() <= before_max_gas {
|
||||||
|
self.before_gas += tx.transaction.gas_limit();
|
||||||
|
return Some(tx);
|
||||||
|
}
|
||||||
|
self.before.mark_invalid(tx.signer(), tx.transaction.nonce());
|
||||||
|
self.after.mark_invalid(tx.signer(), tx.transaction.nonce());
|
||||||
|
} else {
|
||||||
|
return Some(tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while let Some(tx) = self.after.next(ctx) {
|
||||||
|
if let Some(after_max_gas) = self.after_max_gas {
|
||||||
|
if self.after_gas + tx.transaction.gas_limit() <= after_max_gas {
|
||||||
|
self.after_gas += tx.transaction.gas_limit();
|
||||||
|
return Some(tx);
|
||||||
|
}
|
||||||
|
self.after.mark_invalid(tx.signer(), tx.transaction.nonce());
|
||||||
|
} else {
|
||||||
|
return Some(tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark_invalid(&mut self, sender: Address, nonce: u64) {
|
||||||
|
self.before.mark_invalid(sender, nonce);
|
||||||
|
self.after.mark_invalid(sender, nonce);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -18,6 +18,7 @@ reth-chainspec.workspace = true
|
|||||||
reth-eth-wire-types.workspace = true
|
reth-eth-wire-types.workspace = true
|
||||||
reth-primitives = { workspace = true, features = ["c-kzg", "secp256k1"] }
|
reth-primitives = { workspace = true, features = ["c-kzg", "secp256k1"] }
|
||||||
reth-primitives-traits.workspace = true
|
reth-primitives-traits.workspace = true
|
||||||
|
reth-payload-util.workspace = true
|
||||||
reth-execution-types.workspace = true
|
reth-execution-types.workspace = true
|
||||||
reth-fs-util.workspace = true
|
reth-fs-util.workspace = true
|
||||||
reth-storage-api.workspace = true
|
reth-storage-api.workspace = true
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
identifier::{SenderId, TransactionId},
|
identifier::{SenderId, TransactionId},
|
||||||
pool::pending::PendingTransaction,
|
pool::pending::PendingTransaction,
|
||||||
PayloadTransactions, PoolTransaction, TransactionOrdering, ValidPoolTransaction,
|
PoolTransaction, TransactionOrdering, ValidPoolTransaction,
|
||||||
};
|
};
|
||||||
use alloy_consensus::Transaction;
|
|
||||||
use alloy_primitives::Address;
|
use alloy_primitives::Address;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
use reth_payload_util::PayloadTransactions;
|
||||||
use reth_primitives::TransactionSignedEcRecovered;
|
use reth_primitives::TransactionSignedEcRecovered;
|
||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeMap, BTreeSet, HashSet, VecDeque},
|
collections::{BTreeMap, BTreeSet, HashSet, VecDeque},
|
||||||
@ -20,7 +20,6 @@ use tracing::debug;
|
|||||||
/// This is a wrapper around [`BestTransactions`] that also enforces a specific basefee.
|
/// This is a wrapper around [`BestTransactions`] that also enforces a specific basefee.
|
||||||
///
|
///
|
||||||
/// This iterator guarantees that all transaction it returns satisfy both the base fee and blob fee!
|
/// This iterator guarantees that all transaction it returns satisfy both the base fee and blob fee!
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) struct BestTransactionsWithFees<T: TransactionOrdering> {
|
pub(crate) struct BestTransactionsWithFees<T: TransactionOrdering> {
|
||||||
pub(crate) best: BestTransactions<T>,
|
pub(crate) best: BestTransactions<T>,
|
||||||
pub(crate) base_fee: u64,
|
pub(crate) base_fee: u64,
|
||||||
@ -73,7 +72,6 @@ impl<T: TransactionOrdering> Iterator for BestTransactionsWithFees<T> {
|
|||||||
/// be executed on the current state, but only yields transactions that are ready to be executed
|
/// be executed on the current state, but only yields transactions that are ready to be executed
|
||||||
/// now. While it contains all gapless transactions of a sender, it _always_ only returns the
|
/// now. While it contains all gapless transactions of a sender, it _always_ only returns the
|
||||||
/// transaction with the current on chain nonce.
|
/// transaction with the current on chain nonce.
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) struct BestTransactions<T: TransactionOrdering> {
|
pub(crate) struct BestTransactions<T: TransactionOrdering> {
|
||||||
/// Contains a copy of _all_ transactions of the pending pool at the point in time this
|
/// Contains a copy of _all_ transactions of the pending pool at the point in time this
|
||||||
/// iterator was created.
|
/// iterator was created.
|
||||||
@ -397,130 +395,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An implementation of [`crate::traits::PayloadTransactions`] that yields
|
|
||||||
/// a pre-defined set of transactions.
|
|
||||||
///
|
|
||||||
/// This is useful to put a sequencer-specified set of transactions into the block
|
|
||||||
/// and compose it with the rest of the transactions.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct PayloadTransactionsFixed<T> {
|
|
||||||
transactions: Vec<T>,
|
|
||||||
index: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> PayloadTransactionsFixed<T> {
|
|
||||||
/// Constructs a new [`PayloadTransactionsFixed`].
|
|
||||||
pub fn new(transactions: Vec<T>) -> Self {
|
|
||||||
Self { transactions, index: Default::default() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a new [`PayloadTransactionsFixed`] with a single transaction.
|
|
||||||
pub fn single(transaction: T) -> Self {
|
|
||||||
Self { transactions: vec![transaction], index: Default::default() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PayloadTransactions for PayloadTransactionsFixed<TransactionSignedEcRecovered> {
|
|
||||||
fn next(&mut self, _ctx: ()) -> Option<TransactionSignedEcRecovered> {
|
|
||||||
(self.index < self.transactions.len()).then(|| {
|
|
||||||
let tx = self.transactions[self.index].clone();
|
|
||||||
self.index += 1;
|
|
||||||
tx
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_invalid(&mut self, _sender: Address, _nonce: u64) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wrapper over [`crate::traits::PayloadTransactions`] that combines transactions from multiple
|
|
||||||
/// `PayloadTransactions` iterators and keeps track of the gas for both of iterators.
|
|
||||||
///
|
|
||||||
/// We can't use [`Iterator::chain`], because:
|
|
||||||
/// (a) we need to propagate the `mark_invalid` and `no_updates`
|
|
||||||
/// (b) we need to keep track of the gas
|
|
||||||
///
|
|
||||||
/// Notes that [`PayloadTransactionsChain`] fully drains the first iterator
|
|
||||||
/// before moving to the second one.
|
|
||||||
///
|
|
||||||
/// If the `before` iterator has transactions that are not fitting into the block,
|
|
||||||
/// the after iterator will get propagated a `mark_invalid` call for each of them.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct PayloadTransactionsChain<B: PayloadTransactions, A: PayloadTransactions> {
|
|
||||||
/// Iterator that will be used first
|
|
||||||
before: B,
|
|
||||||
/// Allowed gas for the transactions from `before` iterator. If `None`, no gas limit is
|
|
||||||
/// enforced.
|
|
||||||
before_max_gas: Option<u64>,
|
|
||||||
/// Gas used by the transactions from `before` iterator
|
|
||||||
before_gas: u64,
|
|
||||||
/// Iterator that will be used after `before` iterator
|
|
||||||
after: A,
|
|
||||||
/// Allowed gas for the transactions from `after` iterator. If `None`, no gas limit is
|
|
||||||
/// enforced.
|
|
||||||
after_max_gas: Option<u64>,
|
|
||||||
/// Gas used by the transactions from `after` iterator
|
|
||||||
after_gas: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<B: PayloadTransactions, A: PayloadTransactions> PayloadTransactionsChain<B, A> {
|
|
||||||
/// Constructs a new [`PayloadTransactionsChain`].
|
|
||||||
pub fn new(
|
|
||||||
before: B,
|
|
||||||
before_max_gas: Option<u64>,
|
|
||||||
after: A,
|
|
||||||
after_max_gas: Option<u64>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
before,
|
|
||||||
before_max_gas,
|
|
||||||
before_gas: Default::default(),
|
|
||||||
after,
|
|
||||||
after_max_gas,
|
|
||||||
after_gas: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<B, A> PayloadTransactions for PayloadTransactionsChain<B, A>
|
|
||||||
where
|
|
||||||
B: PayloadTransactions,
|
|
||||||
A: PayloadTransactions,
|
|
||||||
{
|
|
||||||
fn next(&mut self, ctx: ()) -> Option<TransactionSignedEcRecovered> {
|
|
||||||
while let Some(tx) = self.before.next(ctx) {
|
|
||||||
if let Some(before_max_gas) = self.before_max_gas {
|
|
||||||
if self.before_gas + tx.transaction.gas_limit() <= before_max_gas {
|
|
||||||
self.before_gas += tx.transaction.gas_limit();
|
|
||||||
return Some(tx);
|
|
||||||
}
|
|
||||||
self.before.mark_invalid(tx.signer(), tx.transaction.nonce());
|
|
||||||
self.after.mark_invalid(tx.signer(), tx.transaction.nonce());
|
|
||||||
} else {
|
|
||||||
return Some(tx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while let Some(tx) = self.after.next(ctx) {
|
|
||||||
if let Some(after_max_gas) = self.after_max_gas {
|
|
||||||
if self.after_gas + tx.transaction.gas_limit() <= after_max_gas {
|
|
||||||
self.after_gas += tx.transaction.gas_limit();
|
|
||||||
return Some(tx);
|
|
||||||
}
|
|
||||||
self.after.mark_invalid(tx.signer(), tx.transaction.nonce());
|
|
||||||
} else {
|
|
||||||
return Some(tx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_invalid(&mut self, sender: Address, nonce: u64) {
|
|
||||||
self.before.mark_invalid(sender, nonce);
|
|
||||||
self.after.mark_invalid(sender, nonce);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -530,6 +404,7 @@ mod tests {
|
|||||||
Priority,
|
Priority,
|
||||||
};
|
};
|
||||||
use alloy_primitives::U256;
|
use alloy_primitives::U256;
|
||||||
|
use reth_payload_util::{PayloadTransactionsChain, PayloadTransactionsFixed};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_best_iter() {
|
fn test_best_iter() {
|
||||||
|
|||||||
@ -108,7 +108,6 @@ use crate::{
|
|||||||
};
|
};
|
||||||
pub use best::{
|
pub use best::{
|
||||||
BestPayloadTransactions, BestTransactionFilter, BestTransactionsWithPrioritizedSenders,
|
BestPayloadTransactions, BestTransactionFilter, BestTransactionsWithPrioritizedSenders,
|
||||||
PayloadTransactionsChain, PayloadTransactionsFixed,
|
|
||||||
};
|
};
|
||||||
pub use blob::{blob_tx_priority, fee_delta};
|
pub use blob::{blob_tx_priority, fee_delta};
|
||||||
pub use events::{FullTransactionEvent, TransactionEvent};
|
pub use events::{FullTransactionEvent, TransactionEvent};
|
||||||
|
|||||||
@ -1510,24 +1510,6 @@ impl<Tx: PoolTransaction> Stream for NewSubpoolTransactionStream<Tx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterator that returns transactions for the block building process in the order they should be
|
|
||||||
/// included in the block.
|
|
||||||
///
|
|
||||||
/// Can include transactions from the pool and other sources (alternative pools,
|
|
||||||
/// sequencer-originated transactions, etc.).
|
|
||||||
pub trait PayloadTransactions {
|
|
||||||
/// Returns the next transaction to include in the block.
|
|
||||||
fn next(
|
|
||||||
&mut self,
|
|
||||||
// In the future, `ctx` can include access to state for block building purposes.
|
|
||||||
ctx: (),
|
|
||||||
) -> Option<TransactionSignedEcRecovered>;
|
|
||||||
|
|
||||||
/// Exclude descendants of the transaction with given sender and nonce from the iterator,
|
|
||||||
/// because this transaction won't be included in the block.
|
|
||||||
fn mark_invalid(&mut self, sender: Address, nonce: u64);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
Reference in New Issue
Block a user