From 06bf5c77839972a8df7f9195499a67d38e840d29 Mon Sep 17 00:00:00 2001 From: Emilia Hane Date: Tue, 19 Nov 2024 10:27:23 +0100 Subject: [PATCH] chore(sdk): make `Chain` generic over data primitives (#12635) --- crates/ethereum/node/src/node.rs | 16 +---- crates/evm/execution-types/src/chain.rs | 60 ++++++++++--------- crates/optimism/evm/src/lib.rs | 2 +- crates/optimism/node/src/node.rs | 2 +- crates/primitives-traits/src/node.rs | 43 +++++++++++-- crates/primitives/src/lib.rs | 13 +++- .../transaction-pool/src/blobstore/tracker.rs | 2 +- 7 files changed, 86 insertions(+), 52 deletions(-) diff --git a/crates/ethereum/node/src/node.rs b/crates/ethereum/node/src/node.rs index 5265329f1..1615ef0e6 100644 --- a/crates/ethereum/node/src/node.rs +++ b/crates/ethereum/node/src/node.rs @@ -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::{ @@ -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}; @@ -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] diff --git a/crates/evm/execution-types/src/chain.rs b/crates/evm/execution-types/src/chain.rs index dc633e2d7..b32b53b88 100644 --- a/crates/evm/execution-types/src/chain.rs +++ b/crates/evm/execution-types/src/chain.rs @@ -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; @@ -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 { /// All blocks in this chain. blocks: BTreeMap, /// The outcome of block execution for this chain. @@ -34,14 +35,14 @@ 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, /// 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, } -impl Chain { +impl Chain { /// Create new Chain from blocks and state. /// /// # Warning @@ -49,7 +50,7 @@ impl Chain { /// A chain of blocks should not be empty. pub fn new( blocks: impl IntoIterator, - execution_outcome: ExecutionOutcome, + execution_outcome: ExecutionOutcome, trie_updates: Option, ) -> Self { let blocks = blocks.into_iter().map(|b| (b.number, b)).collect::>(); @@ -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, trie_updates: Option, ) -> Self { Self::new([block], execution_outcome, trie_updates) @@ -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 { &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 { &mut self.execution_outcome } @@ -132,7 +133,7 @@ impl Chain { pub fn execution_outcome_at_block( &self, block_number: BlockNumber, - ) -> Option { + ) -> Option> { if self.tip().number == block_number { return Some(self.execution_outcome.clone()) } @@ -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) { + pub fn into_inner( + self, + ) -> (ChainBlocks<'static>, ExecutionOutcome, Option) { (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) { (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>> + '_ { + pub fn block_receipts_iter(&self) -> impl Iterator>> + '_ { self.execution_outcome.receipts().iter() } @@ -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>)> + '_ { + ) -> impl Iterator>)> + '_ { self.blocks_iter().zip(self.block_receipts_iter()) } @@ -219,7 +222,7 @@ impl Chain { } /// Get all receipts for the given block. - pub fn receipts_by_block_hash(&self, block_hash: BlockHash) -> Option> { + pub fn receipts_by_block_hash(&self, block_hash: BlockHash) -> Option> { let num = self.block_number(block_hash)?; self.execution_outcome.receipts_by_block(num).iter().map(Option::as_ref).collect() } @@ -227,7 +230,7 @@ impl Chain { /// Get all receipts with attachment. /// /// Attachment includes block number, block hash, transaction hash and transaction index. - pub fn receipts_with_attachment(&self) -> Vec { + pub fn receipts_with_attachment(&self) -> Vec> { 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()) @@ -250,7 +253,7 @@ impl Chain { pub fn append_block( &mut self, block: SealedBlockWithSenders, - execution_outcome: ExecutionOutcome, + execution_outcome: ExecutionOutcome, ) { self.blocks.insert(block.number, block); self.execution_outcome.extend(execution_outcome); @@ -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 { let chain_tip = *self.blocks.last_entry().expect("chain is never empty").key(); let block_number = match split_at { ChainSplitTarget::Hash(block_hash) => { @@ -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 { /// 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. @@ -484,26 +487,26 @@ impl From for ChainSplitTarget { /// Result of a split chain. #[derive(Clone, Debug, PartialEq, Eq)] -pub enum ChainSplit { +pub enum ChainSplit { /// 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), /// Chain is not split. Canonical chain is returned. /// Given block split is lower than first block. - NoSplitCanonical(Chain), + NoSplitCanonical(Chain), /// 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, /// 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, }, } @@ -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 = @@ -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]), @@ -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); @@ -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() diff --git a/crates/optimism/evm/src/lib.rs b/crates/optimism/evm/src/lib.rs index 9569c1cb8..55dc3fc7d 100644 --- a/crates/optimism/evm/src/lib.rs +++ b/crates/optimism/evm/src/lib.rs @@ -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])); diff --git a/crates/optimism/node/src/node.rs b/crates/optimism/node/src/node.rs index 238953c9d..699239a43 100644 --- a/crates/optimism/node/src/node.rs +++ b/crates/optimism/node/src/node.rs @@ -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 { diff --git a/crates/primitives-traits/src/node.rs b/crates/primitives-traits/src/node.rs index 35c8ea0f6..c11a19a10 100644 --- a/crates/primitives-traits/src/node.rs +++ b/crates/primitives-traits/src/node.rs @@ -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 () { @@ -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>; /// Signed version of the transaction type. diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index 45067d600..2618f6719 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -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; @@ -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; +} diff --git a/crates/transaction-pool/src/blobstore/tracker.rs b/crates/transaction-pool/src/blobstore/tracker.rs index f22dcf570..63d6e30ee 100644 --- a/crates/transaction-pool/src/blobstore/tracker.rs +++ b/crates/transaction-pool/src/blobstore/tracker.rs @@ -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