diff --git a/src/payload/ext/checkpoint.rs b/src/payload/ext/checkpoint.rs index c5e4be4..882e69a 100644 --- a/src/payload/ext/checkpoint.rs +++ b/src/payload/ext/checkpoint.rs @@ -2,7 +2,7 @@ use { crate::{ alloy::{ consensus::transaction::{Transaction, TxHashRef}, - primitives::{Address, B256, U256}, + primitives::{Address, B256, TxHash, U256}, }, prelude::*, reth::{errors::ProviderError, primitives::Recovered, revm::DatabaseRef}, @@ -14,7 +14,7 @@ use { /// Quality of Life extensions for the `Checkpoint` type. pub trait CheckpointExt: super::sealed::Sealed { /// Returns `true` if this checkpoint is the baseline checkpoint in the - /// history, and has no transactions in its history. + /// history and has no transactions in its history. fn is_empty(&self) -> bool; /// Returns the first checkpoint in the chain of checkpoints since the @@ -37,24 +37,33 @@ pub trait CheckpointExt: super::sealed::Sealed { self.history().blob_gas_used() } - /// Returns the effective tip for this transaction. + /// Returns the effective tip of the checkpoint, as the cumulative effective + /// tip of all transactions in this checkpoint. fn effective_tip_per_gas(&self) -> u128; - /// If this checkpoint was created by applying a blob transaction, - /// returns the blob gas used by the blob transaction, `None` otherwise. + /// If this checkpoint was created by applying one or more blobs transactions, + /// returns the cumulative blob gas used by theses, `None` otherwise. fn blob_gas_used(&self) -> Option; - /// Returns `true` if this checkpoint was created by applying EIP-4844 blob - /// transaction, `false` otherwise. + /// Returns `true` if this checkpoint was created by applying at least one + /// EIP-4844 blob transaction, `false` otherwise. fn has_blobs(&self) -> bool; + //// Iterates over all blob transactions in the checkpoint. + fn blobs(&self) -> impl Iterator>>; + /// Returns a span that includes all checkpoints from the beginning of the - /// block payload we're building to the current checkpoint. + /// block payload we're building up to the current one (included). fn history(&self) -> Span

; - /// Returns a span that includes all staging history of this checkpoint, - /// which is all preceding checkpoints from the last barrier, or the entire - /// history if there is no barrier checkpoint. + /// Check if the checkpoint contains a transaction with a given hash. + fn contains(&self, tx_hash: impl Into) -> bool; + + /// Returns a span that includes the staging history of this checkpoint. + /// The staging history of a checkpoint is all the preceding checkpoints from + /// the last barrier up to this current checkpoint, or the entire history if + /// there is no barrier checkpoint. If the current checkpoint is a barrier + /// the staging history will be empty. fn history_staging(&self) -> Span

{ let history = self.history(); let immutable_prefix = history @@ -64,20 +73,20 @@ pub trait CheckpointExt: super::sealed::Sealed { history.skip(immutable_prefix) } - /// Returns a span that includes all checkpoints in the sealed history, - /// that is the history from the beginning of the block until the last - /// barrier included. If there are no barriers, the entire history is - /// returned. + /// Returns a span that includes the sealed history of this checkpoint. + /// The sealed history of a checkpoint is all checkpoints from the + /// beginning of the block building job until the last barrier included. + /// If there are no barriers, the sealed history is empty fn history_sealed(&self) -> Span

{ let history = self.history(); - let immutable_prefix = history + let mutable_start = history .iter() .rposition(Checkpoint::is_barrier) - .unwrap_or(0); - history.take(immutable_prefix + 1) + .map_or(0, |i| i + 1); + history.take(mutable_start) } - /// Creates a new span that includes this checkpoints and all other + /// Creates a new span that includes this checkpoint and all other /// checkpoints that are between this checkpoint and the given checkpoint. /// /// The two checkpoints must be part of the same linear history, meaning that @@ -92,7 +101,8 @@ pub trait CheckpointExt: super::sealed::Sealed { /// Returns the nonce of a given account at this checkpoint. fn nonce_of(&self, address: Address) -> Result; - /// Returns all nonces for each signer in this checkpoint. + /// Returns tuples of signer and nonce for each transaction in this + /// checkpoint. fn nonces(&self) -> Vec<(Address, u64)>; /// Returns a list of all unique signers in this checkpoint. @@ -102,8 +112,8 @@ pub trait CheckpointExt: super::sealed::Sealed { /// hash. fn hash(&self) -> Option; - /// Returns `true` if this checkpoint has any transactions with non-success - /// execution outcome. + /// Returns `true` if this checkpoint has any transactions with a + /// non-successful execution outcome. fn has_failures(&self) -> bool; /// Returns an iterator over all transactions in this checkpoint that did not @@ -171,7 +181,18 @@ impl CheckpointExt

for Checkpoint

{ /// Returns `true` if this checkpoint was created by applying an EIP-4844 blob /// transaction, `false` otherwise. fn has_blobs(&self) -> bool { - self.blob_gas_used().is_some() + self + .transactions() + .iter() + .any(|tx| tx.blob_gas_used().is_some()) + } + + //// Iterates over all blob transactions in the checkpoint. + fn blobs(&self) -> impl Iterator>> { + self + .transactions() + .iter() + .filter(|tx| tx.blob_gas_used().is_some()) } /// Returns a span that includes all checkpoints from the beginning of the @@ -185,7 +206,13 @@ impl CheckpointExt

for Checkpoint

{ .expect("history is always linear between self and root") } - /// Creates a new span that includes this checkpoints and all other + /// Check if the checkpoint contains a transaction with a given hash. + fn contains(&self, tx_hash: impl Into) -> bool { + let hash = tx_hash.into(); + self.transactions().iter().any(|tx| *tx.tx_hash() == hash) + } + + /// Creates a new span that includes this checkpoint and all other /// checkpoints that are between this checkpoint and the given checkpoint. /// /// The two checkpoints must be part of the same linear history, meaning that @@ -216,7 +243,8 @@ impl CheckpointExt

for Checkpoint

{ ) } - /// Returns all nonces for each signer in this checkpoint. + /// Returns tuples of signer and nonce for each transaction in this + /// checkpoint. fn nonces(&self) -> Vec<(Address, u64)> { self .transactions() @@ -245,8 +273,8 @@ impl CheckpointExt

for Checkpoint

{ } } - /// Returns `true` if this checkpoint has any transactions with non-success - /// execution outcome. + /// Returns `true` if this checkpoint has any transactions with a + /// non-successful execution outcome. fn has_failures(&self) -> bool { self.failed_txs().next().is_some() } @@ -275,17 +303,11 @@ impl CheckpointExt

for Checkpoint

{ self.as_bundle().is_some() } - /// Returns the timestamp of initial checkpoint that was created at the very - /// beginning of the payload building process. It is the timestamp if the - /// first barrier checkpoint in the history of this checkpoint that is created - /// by `Checkpoint::new_at_block`. + /// Returns the timestamp of the initial checkpoint that was created at the + /// very beginning of the payload building process. It is the timestamp if + /// the first barrier checkpoint in the history of this checkpoint that is + /// created by `Checkpoint::new_at_block`. fn building_since(&self) -> Instant { - let mut created_at = self.created_at(); - let mut current = self.clone(); - while let Some(prev) = current.prev() { - created_at = prev.created_at(); - current = prev; - } - created_at + self.root().created_at() } } diff --git a/src/payload/ext/span.rs b/src/payload/ext/span.rs index 8c8e2b7..a6bdedb 100644 --- a/src/payload/ext/span.rs +++ b/src/payload/ext/span.rs @@ -1,8 +1,5 @@ use crate::{ - alloy::{ - consensus::transaction::{Transaction, TxHashRef}, - primitives::TxHash, - }, + alloy::primitives::TxHash, prelude::*, reth::primitives::Recovered, }; @@ -17,7 +14,7 @@ pub trait SpanExt: super::sealed::Sealed { /// Checks if this span contains a checkpoint with a transaction with a given /// hash. - fn contains(&self, txhash: impl Into) -> bool; + fn contains(&self, tx_hash: impl Into) -> bool; /// Iterates of all transactions in the span in chronological order as they /// appear in the payload under construction. @@ -54,16 +51,21 @@ pub trait SpanExt: super::sealed::Sealed { } impl SpanExt

for Span

{ + /// Returns the total gas used by all checkpoints in the span. + fn gas_used(&self) -> u64 { + self.iter().map(CheckpointExt::gas_used).sum() + } + + /// Returns the total blob gas used by all blob transactions in the span. + fn blob_gas_used(&self) -> u64 { + self.iter().filter_map(CheckpointExt::blob_gas_used).sum() + } + /// Checks if this span contains a checkpoint with a transaction with a given /// hash. - fn contains(&self, txhash: impl Into) -> bool { - let hash = txhash.into(); - self.iter().any(|checkpoint| { - checkpoint - .transactions() - .iter() - .any(|tx| *tx.tx_hash() == hash) - }) + fn contains(&self, tx_hash: impl Into) -> bool { + let hash = tx_hash.into(); + self.iter().any(|checkpoint| checkpoint.contains(hash)) } /// Iterates of all transactions in the span in chronological order as they @@ -73,32 +75,12 @@ impl SpanExt

for Span

{ fn transactions( &self, ) -> impl Iterator>> { - self.iter().flat_map(|checkpoint| checkpoint.transactions()) + self.iter().flat_map(Checkpoint::transactions) } /// Iterates over all blob transactions in the span. fn blobs(&self) -> impl Iterator>> { - self - .transactions() - .filter(|tx| tx.blob_gas_used().is_some()) - } - - /// Returns the total gas used by all checkpoints in the span. - fn gas_used(&self) -> u64 { - self.iter().map(CheckpointExt::gas_used).sum() - } - - /// Returns the total blob gas used by all blob transactions in the span. - fn blob_gas_used(&self) -> u64 { - self - .iter() - .flat_map(|checkpoint| { - checkpoint - .transactions() - .iter() - .filter_map(|tx| tx.blob_gas_used()) - }) - .sum() + self.iter().flat_map(Checkpoint::blobs) } /// Divides the span into two spans at a given index. diff --git a/src/payload/span.rs b/src/payload/span.rs index 706fc35..9393e50 100644 --- a/src/payload/span.rs +++ b/src/payload/span.rs @@ -5,30 +5,31 @@ use { thiserror::Error, }; -#[derive(Debug, Clone, Error)] -pub enum Error { - /// This error means that the one of the checkpoints is not a descendant of - /// the other. - #[error("There is no linear history between the checkpoints")] - NonlinearHistory, -} - /// A span represents a sequence of checkpoints in the payload building process -/// with linear history. While checkpoints only allow to traverse the history -/// backwards, a span allows to traverse the history forwards as well. +/// with linear history. While checkpoints only allow traversing the history +/// backwards, a span allows traversing the history forwards as well. /// -/// Using a span you can also treat a number of checkpoints as a single +/// Using a span, you can also treat a number of checkpoints as a single /// aggregate of state transitions. /// /// A span can be used as a database reference for an evm instance. When a span -/// is used as a database, only new state that was created or modified by -/// checkpoints in the span are visible, any state from checkpoints outside of -/// the span or the base state of the block is not available. +/// is used as a database, only new states that were created or modified by +/// checkpoints in the span are visible. Any states from checkpoints outside +/// the span or the base state of the block are not available. #[derive(Clone)] pub struct Span { checkpoints: VecDeque>, } +#[derive(Debug, Clone, Error)] +pub enum Error { + /// This error means that one of the checkpoints is not a descendant of + /// the other. A span cannot be created as the history between the checkpoints + /// is not linear. + #[error("There is no linear history between the checkpoints")] + NonlinearHistory, +} + /// Construction impl Span

{ /// Attempts to create a span between two checkpoints. @@ -60,12 +61,8 @@ impl Span

{ // Gather all checkpoints from the descendant to the ancestor // and ensure that the history is linear. - let mut checkpoints = Vec::with_capacity( - descendant - .depth() - .saturating_sub(ancestor.depth()) - .saturating_add(1), - ); + let distance = descendant.depth().saturating_sub(ancestor.depth()); + let mut checkpoints = Vec::with_capacity(distance.saturating_add(1)); let mut current = descendant; checkpoints.push(current.clone()); @@ -78,9 +75,9 @@ impl Span

{ checkpoints.push(prev.clone()); if prev == ancestor { - // we've reached the ancestor checkpoint and we have linear history. The - // collected checkpoints are in reverse order, so we need to reverse - // them before returning. + // we've reached the ancestor checkpoint, and we have linear history. + // The collected checkpoints are in reverse order, so we need to + // reverse them before returning. return Ok(Self { checkpoints: checkpoints.into_iter().rev().collect(), });