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:
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user