Skip to content

Commit

Permalink
chore(sdk): make Chain generic over data primitives (#12635)
Browse files Browse the repository at this point in the history
  • Loading branch information
emhane authored Nov 19, 2024
1 parent e859e17 commit 06bf5c7
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 52 deletions.
16 changes: 2 additions & 14 deletions crates/ethereum/node/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ use reth_evm::execute::BasicBlockExecutorProvider;
use reth_evm_ethereum::execute::EthExecutionStrategyFactory;
use reth_network::{NetworkHandle, PeersInfo};
use reth_node_api::{
AddOnsContext, ConfigureEvm, EngineValidator, FullNodeComponents, NodePrimitives,
NodeTypesWithDB,
AddOnsContext, ConfigureEvm, EngineValidator, FullNodeComponents, NodeTypesWithDB,
};
use reth_node_builder::{
components::{
Expand All @@ -26,7 +25,7 @@ use reth_node_builder::{
BuilderContext, Node, NodeAdapter, NodeComponentsBuilder, PayloadBuilderConfig, PayloadTypes,
};
use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService};
use reth_primitives::{Block, Receipt, TransactionSigned, TxType};
use reth_primitives::EthPrimitives;
use reth_provider::CanonStateSubscriptions;
use reth_rpc::EthApi;
use reth_tracing::tracing::{debug, info};
Expand All @@ -38,17 +37,6 @@ use reth_trie_db::MerklePatriciaTrie;

use crate::{EthEngineTypes, EthEvmConfig};

/// Ethereum primitive types.
#[derive(Debug, Default, Clone)]
pub struct EthPrimitives;

impl NodePrimitives for EthPrimitives {
type Block = Block;
type SignedTx = TransactionSigned;
type TxType = TxType;
type Receipt = Receipt;
}

/// Type configuration for a regular Ethereum node.
#[derive(Debug, Default, Clone, Copy)]
#[non_exhaustive]
Expand Down
60 changes: 32 additions & 28 deletions crates/evm/execution-types/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ use alloy_primitives::{Address, BlockHash, BlockNumber, TxHash};
use core::{fmt, ops::RangeInclusive};
use reth_execution_errors::{BlockExecutionError, InternalBlockExecutionError};
use reth_primitives::{
Receipt, SealedBlock, SealedBlockWithSenders, SealedHeader, TransactionSigned,
SealedBlock, SealedBlockWithSenders, SealedHeader, TransactionSigned,
TransactionSignedEcRecovered,
};
use reth_primitives_traits::NodePrimitives;
use reth_trie::updates::TrieUpdates;
use revm::db::BundleState;

Expand All @@ -25,7 +26,7 @@ use revm::db::BundleState;
/// A chain of blocks should not be empty.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Chain {
pub struct Chain<N: NodePrimitives = reth_primitives::EthPrimitives> {
/// All blocks in this chain.
blocks: BTreeMap<BlockNumber, SealedBlockWithSenders>,
/// The outcome of block execution for this chain.
Expand All @@ -34,22 +35,22 @@ pub struct Chain {
/// chain, ranging from the [`Chain::first`] block to the [`Chain::tip`] block, inclusive.
///
/// Additionally, it includes the individual state changes that led to the current state.
execution_outcome: ExecutionOutcome,
execution_outcome: ExecutionOutcome<N::Receipt>,
/// State trie updates after block is added to the chain.
/// NOTE: Currently, trie updates are present only for
/// single-block chains that extend the canonical chain.
trie_updates: Option<TrieUpdates>,
}

impl Chain {
impl<N: NodePrimitives> Chain<N> {
/// Create new Chain from blocks and state.
///
/// # Warning
///
/// A chain of blocks should not be empty.
pub fn new(
blocks: impl IntoIterator<Item = SealedBlockWithSenders>,
execution_outcome: ExecutionOutcome,
execution_outcome: ExecutionOutcome<N::Receipt>,
trie_updates: Option<TrieUpdates>,
) -> Self {
let blocks = blocks.into_iter().map(|b| (b.number, b)).collect::<BTreeMap<_, _>>();
Expand All @@ -61,7 +62,7 @@ impl Chain {
/// Create new Chain from a single block and its state.
pub fn from_block(
block: SealedBlockWithSenders,
execution_outcome: ExecutionOutcome,
execution_outcome: ExecutionOutcome<N::Receipt>,
trie_updates: Option<TrieUpdates>,
) -> Self {
Self::new([block], execution_outcome, trie_updates)
Expand Down Expand Up @@ -93,12 +94,12 @@ impl Chain {
}

/// Get execution outcome of this chain
pub const fn execution_outcome(&self) -> &ExecutionOutcome {
pub const fn execution_outcome(&self) -> &ExecutionOutcome<N::Receipt> {
&self.execution_outcome
}

/// Get mutable execution outcome of this chain
pub fn execution_outcome_mut(&mut self) -> &mut ExecutionOutcome {
pub fn execution_outcome_mut(&mut self) -> &mut ExecutionOutcome<N::Receipt> {
&mut self.execution_outcome
}

Expand Down Expand Up @@ -132,7 +133,7 @@ impl Chain {
pub fn execution_outcome_at_block(
&self,
block_number: BlockNumber,
) -> Option<ExecutionOutcome> {
) -> Option<ExecutionOutcome<N::Receipt>> {
if self.tip().number == block_number {
return Some(self.execution_outcome.clone())
}
Expand All @@ -149,19 +150,21 @@ impl Chain {
/// 1. The blocks contained in the chain.
/// 2. The execution outcome representing the final state.
/// 3. The optional trie updates.
pub fn into_inner(self) -> (ChainBlocks<'static>, ExecutionOutcome, Option<TrieUpdates>) {
pub fn into_inner(
self,
) -> (ChainBlocks<'static>, ExecutionOutcome<N::Receipt>, Option<TrieUpdates>) {
(ChainBlocks { blocks: Cow::Owned(self.blocks) }, self.execution_outcome, self.trie_updates)
}

/// Destructure the chain into its inner components:
/// 1. A reference to the blocks contained in the chain.
/// 2. A reference to the execution outcome representing the final state.
pub const fn inner(&self) -> (ChainBlocks<'_>, &ExecutionOutcome) {
pub const fn inner(&self) -> (ChainBlocks<'_>, &ExecutionOutcome<N::Receipt>) {
(ChainBlocks { blocks: Cow::Borrowed(&self.blocks) }, &self.execution_outcome)
}

/// Returns an iterator over all the receipts of the blocks in the chain.
pub fn block_receipts_iter(&self) -> impl Iterator<Item = &Vec<Option<Receipt>>> + '_ {
pub fn block_receipts_iter(&self) -> impl Iterator<Item = &Vec<Option<N::Receipt>>> + '_ {
self.execution_outcome.receipts().iter()
}

Expand All @@ -173,7 +176,7 @@ impl Chain {
/// Returns an iterator over all blocks and their receipts in the chain.
pub fn blocks_and_receipts(
&self,
) -> impl Iterator<Item = (&SealedBlockWithSenders, &Vec<Option<Receipt>>)> + '_ {
) -> impl Iterator<Item = (&SealedBlockWithSenders, &Vec<Option<N::Receipt>>)> + '_ {
self.blocks_iter().zip(self.block_receipts_iter())
}

Expand Down Expand Up @@ -219,15 +222,15 @@ impl Chain {
}

/// Get all receipts for the given block.
pub fn receipts_by_block_hash(&self, block_hash: BlockHash) -> Option<Vec<&Receipt>> {
pub fn receipts_by_block_hash(&self, block_hash: BlockHash) -> Option<Vec<&N::Receipt>> {
let num = self.block_number(block_hash)?;
self.execution_outcome.receipts_by_block(num).iter().map(Option::as_ref).collect()
}

/// Get all receipts with attachment.
///
/// Attachment includes block number, block hash, transaction hash and transaction index.
pub fn receipts_with_attachment(&self) -> Vec<BlockReceipts> {
pub fn receipts_with_attachment(&self) -> Vec<BlockReceipts<N::Receipt>> {
let mut receipt_attach = Vec::with_capacity(self.blocks().len());
for ((block_num, block), receipts) in
self.blocks().iter().zip(self.execution_outcome.receipts().iter())
Expand All @@ -250,7 +253,7 @@ impl Chain {
pub fn append_block(
&mut self,
block: SealedBlockWithSenders,
execution_outcome: ExecutionOutcome,
execution_outcome: ExecutionOutcome<N::Receipt>,
) {
self.blocks.insert(block.number, block);
self.execution_outcome.extend(execution_outcome);
Expand Down Expand Up @@ -300,7 +303,7 @@ impl Chain {
///
/// If chain doesn't have any blocks.
#[track_caller]
pub fn split(mut self, split_at: ChainSplitTarget) -> ChainSplit {
pub fn split(mut self, split_at: ChainSplitTarget) -> ChainSplit<N> {
let chain_tip = *self.blocks.last_entry().expect("chain is never empty").key();
let block_number = match split_at {
ChainSplitTarget::Hash(block_hash) => {
Expand Down Expand Up @@ -454,11 +457,11 @@ impl IntoIterator for ChainBlocks<'_> {

/// Used to hold receipts and their attachment.
#[derive(Default, Clone, Debug, PartialEq, Eq)]
pub struct BlockReceipts {
pub struct BlockReceipts<T = reth_primitives::Receipt> {
/// Block identifier
pub block: BlockNumHash,
/// Transaction identifier and receipt.
pub tx_receipts: Vec<(TxHash, Receipt)>,
pub tx_receipts: Vec<(TxHash, T)>,
}

/// The target block where the chain should be split.
Expand All @@ -484,26 +487,26 @@ impl From<BlockHash> for ChainSplitTarget {

/// Result of a split chain.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ChainSplit {
pub enum ChainSplit<N: NodePrimitives = reth_primitives::EthPrimitives> {
/// Chain is not split. Pending chain is returned.
/// Given block split is higher than last block.
/// Or in case of split by hash when hash is unknown.
NoSplitPending(Chain),
NoSplitPending(Chain<N>),
/// Chain is not split. Canonical chain is returned.
/// Given block split is lower than first block.
NoSplitCanonical(Chain),
NoSplitCanonical(Chain<N>),
/// Chain is split into two: `[canonical]` and `[pending]`
/// The target of this chain split [`ChainSplitTarget`] belongs to the `canonical` chain.
Split {
/// Contains lower block numbers that are considered canonicalized. It ends with
/// the [`ChainSplitTarget`] block. The state of this chain is now empty and no longer
/// usable.
canonical: Chain,
canonical: Chain<N>,
/// Right contains all subsequent blocks __after__ the [`ChainSplitTarget`] that are still
/// pending.
///
/// The state of the original chain is moved here.
pending: Chain,
pending: Chain<N>,
},
}

Expand Down Expand Up @@ -678,7 +681,7 @@ mod tests {

block3.set_parent_hash(block2_hash);

let mut chain1 =
let mut chain1: Chain =
Chain { blocks: BTreeMap::from([(1, block1), (2, block2)]), ..Default::default() };

let chain2 =
Expand All @@ -692,7 +695,7 @@ mod tests {

#[test]
fn test_number_split() {
let execution_outcome1 = ExecutionOutcome::new(
let execution_outcome1: ExecutionOutcome = ExecutionOutcome::new(
BundleState::new(
vec![(
Address::new([2; 20]),
Expand Down Expand Up @@ -739,7 +742,8 @@ mod tests {
let mut block_state_extended = execution_outcome1;
block_state_extended.extend(execution_outcome2);

let chain = Chain::new(vec![block1.clone(), block2.clone()], block_state_extended, None);
let chain: Chain =
Chain::new(vec![block1.clone(), block2.clone()], block_state_extended, None);

let (split1_execution_outcome, split2_execution_outcome) =
chain.execution_outcome.clone().split_at(2);
Expand Down Expand Up @@ -838,7 +842,7 @@ mod tests {

// Create a Chain object with a BTreeMap of blocks mapped to their block numbers,
// including block1_hash and block2_hash, and the execution_outcome
let chain = Chain {
let chain: Chain = Chain {
blocks: BTreeMap::from([(10, block1), (11, block2)]),
execution_outcome: execution_outcome.clone(),
..Default::default()
Expand Down
2 changes: 1 addition & 1 deletion crates/optimism/evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ mod tests {

// Create a Chain object with a BTreeMap of blocks mapped to their block numbers,
// including block1_hash and block2_hash, and the execution_outcome
let chain = Chain::new([block1, block2], execution_outcome.clone(), None);
let chain: Chain = Chain::new([block1, block2], execution_outcome.clone(), None);

// Assert that the proper receipt vector is returned for block1_hash
assert_eq!(chain.receipts_by_block_hash(block1_hash), Some(vec![&receipt1]));
Expand Down
2 changes: 1 addition & 1 deletion crates/optimism/node/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ use reth_trie_db::MerklePatriciaTrie;
use std::sync::Arc;

/// Optimism primitive types.
#[derive(Debug, Default, Clone)]
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct OpPrimitives;

impl NodePrimitives for OpPrimitives {
Expand Down
43 changes: 37 additions & 6 deletions crates/primitives-traits/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,44 @@ use core::fmt;
use crate::{BlockBody, FullBlock, FullReceipt, FullSignedTx, FullTxType, MaybeSerde};

/// Configures all the primitive types of the node.
pub trait NodePrimitives: Send + Sync + Unpin + Clone + Default + fmt::Debug + 'static {
pub trait NodePrimitives:
Send + Sync + Unpin + Clone + Default + fmt::Debug + PartialEq + Eq + 'static
{
/// Block primitive.
type Block: Send + Sync + Unpin + Clone + Default + fmt::Debug + MaybeSerde + 'static;
type Block: Send
+ Sync
+ Unpin
+ Clone
+ Default
+ fmt::Debug
+ PartialEq
+ Eq
+ MaybeSerde
+ 'static;
/// Signed version of the transaction type.
type SignedTx: Send + Sync + Unpin + Clone + Default + fmt::Debug + MaybeSerde + 'static;
type SignedTx: Send
+ Sync
+ Unpin
+ Clone
+ Default
+ fmt::Debug
+ PartialEq
+ Eq
+ MaybeSerde
+ 'static;
/// Transaction envelope type ID.
type TxType: Send + Sync + Unpin + Clone + Default + fmt::Debug + 'static;
type TxType: Send + Sync + Unpin + Clone + Default + fmt::Debug + PartialEq + Eq + 'static;
/// A receipt.
type Receipt: Send + Sync + Unpin + Clone + Default + fmt::Debug + MaybeSerde + 'static;
type Receipt: Send
+ Sync
+ Unpin
+ Clone
+ Default
+ fmt::Debug
+ PartialEq
+ Eq
+ MaybeSerde
+ 'static;
}

impl NodePrimitives for () {
Expand All @@ -22,7 +51,9 @@ impl NodePrimitives for () {
}

/// Helper trait that sets trait bounds on [`NodePrimitives`].
pub trait FullNodePrimitives: Send + Sync + Unpin + Clone + Default + fmt::Debug + 'static {
pub trait FullNodePrimitives:
Send + Sync + Unpin + Clone + Default + fmt::Debug + PartialEq + Eq + 'static
{
/// Block primitive.
type Block: FullBlock<Body: BlockBody<Transaction = Self::SignedTx>>;
/// Signed version of the transaction type.
Expand Down
13 changes: 12 additions & 1 deletion crates/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ pub use receipt::{
};
pub use reth_primitives_traits::{
logs_bloom, Account, Bytecode, GotExpected, GotExpectedBoxed, HeaderError, Log, LogData,
SealedHeader, StorageEntry,
NodePrimitives, SealedHeader, StorageEntry,
};
pub use static_file::StaticFileSegment;

Expand Down Expand Up @@ -74,3 +74,14 @@ pub mod serde_bincode_compat {
transaction::{serde_bincode_compat as transaction, serde_bincode_compat::*},
};
}

/// Temp helper struct for integrating [`NodePrimitives`].
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct EthPrimitives;

impl NodePrimitives for EthPrimitives {
type Block = crate::Block;
type SignedTx = crate::TransactionSigned;
type TxType = crate::TxType;
type Receipt = crate::Receipt;
}
2 changes: 1 addition & 1 deletion crates/transaction-pool/src/blobstore/tracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ mod tests {
};

// Extract blocks from the chain
let chain = Chain::new(vec![block1, block2], Default::default(), None);
let chain: Chain = Chain::new(vec![block1, block2], Default::default(), None);
let blocks = chain.into_inner().0;

// Add new chain blocks to the tracker
Expand Down

0 comments on commit 06bf5c7

Please sign in to comment.