diff --git a/crates/blockchain-tree/src/blockchain_tree.rs b/crates/blockchain-tree/src/blockchain_tree.rs index efc7e82ce6..68b7d02c79 100644 --- a/crates/blockchain-tree/src/blockchain_tree.rs +++ b/crates/blockchain-tree/src/blockchain_tree.rs @@ -16,8 +16,8 @@ use reth_interfaces::{ Error, }; use reth_primitives::{ - BlockHash, BlockNumHash, BlockNumber, ForkBlock, Hardfork, SealedBlock, SealedBlockWithSenders, - SealedHeader, U256, + BlockHash, BlockNumHash, BlockNumber, ForkBlock, Hardfork, Receipt, SealedBlock, + SealedBlockWithSenders, SealedHeader, U256, }; use reth_provider::{ chain::{ChainSplit, SplitAt}, @@ -217,6 +217,15 @@ impl BlockchainTree chain.block(block_hash) } + /// Returns the block's receipts with matching hash from any side-chain. + /// + /// Caution: This will not return blocks from the canonical chain. + pub fn receipts_by_block_hash(&self, block_hash: BlockHash) -> Option<&[Receipt]> { + let id = self.block_indices.get_blocks_chain_id(&block_hash)?; + let chain = self.chains.get(&id)?; + chain.receipts_by_block_hash(block_hash) + } + /// Returns true if the block is included in a side-chain. fn is_block_hash_inside_chain(&self, block_hash: BlockHash) -> bool { self.block_by_hash(block_hash).is_some() diff --git a/crates/blockchain-tree/src/shareable.rs b/crates/blockchain-tree/src/shareable.rs index bd3eb32477..759ca402a7 100644 --- a/crates/blockchain-tree/src/shareable.rs +++ b/crates/blockchain-tree/src/shareable.rs @@ -11,7 +11,8 @@ use reth_interfaces::{ Error, }; use reth_primitives::{ - BlockHash, BlockNumHash, BlockNumber, SealedBlock, SealedBlockWithSenders, SealedHeader, + BlockHash, BlockNumHash, BlockNumber, Receipt, SealedBlock, SealedBlockWithSenders, + SealedHeader, }; use reth_provider::{ BlockchainTreePendingStateProvider, CanonStateSubscriptions, ExecutorFactory, @@ -152,6 +153,11 @@ impl BlockchainTreeViewer trace!(target: "blockchain_tree", "Returning first pending block"); self.tree.read().pending_block().cloned() } + + fn receipts_by_block_hash(&self, block_hash: BlockHash) -> Option> { + let tree = self.tree.read(); + Some(tree.receipts_by_block_hash(block_hash)?.to_vec()) + } } impl BlockchainTreePendingStateProvider diff --git a/crates/interfaces/src/blockchain_tree/mod.rs b/crates/interfaces/src/blockchain_tree/mod.rs index 4e9e3b4771..c1b182b24c 100644 --- a/crates/interfaces/src/blockchain_tree/mod.rs +++ b/crates/interfaces/src/blockchain_tree/mod.rs @@ -1,6 +1,7 @@ use crate::{blockchain_tree::error::InsertBlockError, Error}; use reth_primitives::{ - BlockHash, BlockNumHash, BlockNumber, SealedBlock, SealedBlockWithSenders, SealedHeader, + BlockHash, BlockNumHash, BlockNumber, Receipt, SealedBlock, SealedBlockWithSenders, + SealedHeader, }; use std::collections::{BTreeMap, HashSet}; @@ -215,6 +216,14 @@ pub trait BlockchainTreeViewer: Send + Sync { self.block_by_hash(self.pending_block_num_hash()?.hash) } + /// Returns the pending receipts if there is one. + fn pending_receipts(&self) -> Option> { + self.receipts_by_block_hash(self.pending_block_num_hash()?.hash) + } + + /// Returns the pending receipts if there is one. + fn receipts_by_block_hash(&self, block_hash: BlockHash) -> Option>; + /// Returns the pending block if there is one. fn pending_header(&self) -> Option { self.header_by_hash(self.pending_block_num_hash()?.hash) diff --git a/crates/rpc/rpc/src/debug.rs b/crates/rpc/rpc/src/debug.rs index 3cdf35b8b4..6adb46c4be 100644 --- a/crates/rpc/rpc/src/debug.rs +++ b/crates/rpc/rpc/src/debug.rs @@ -12,7 +12,7 @@ use crate::{ use async_trait::async_trait; use jsonrpsee::core::RpcResult; use reth_primitives::{Account, Block, BlockId, BlockNumberOrTag, Bytes, TransactionSigned, H256}; -use reth_provider::{BlockProviderIdExt, HeaderProvider, ReceiptProviderIdExt, StateProviderBox}; +use reth_provider::{BlockProviderIdExt, HeaderProvider, StateProviderBox}; use reth_revm::{ database::{State, SubState}, env::tx_env_with_recovered, diff --git a/crates/storage/provider/src/chain.rs b/crates/storage/provider/src/chain.rs index ff74d4cedb..605caadedd 100644 --- a/crates/storage/provider/src/chain.rs +++ b/crates/storage/provider/src/chain.rs @@ -126,6 +126,12 @@ impl Chain { Self { state, blocks: block_num_hash } } + /// Get all receipts for the given block. + pub fn receipts_by_block_hash(&self, block_hash: BlockHash) -> Option<&[Receipt]> { + let num = self.block_number(block_hash)?; + Some(self.state.receipts(num)) + } + /// Get all receipts with attachment. /// /// Attachment includes block number, block hash, transaction hash and transaction index. diff --git a/crates/storage/provider/src/providers/mod.rs b/crates/storage/provider/src/providers/mod.rs index e45080d2bd..e3143c60bd 100644 --- a/crates/storage/provider/src/providers/mod.rs +++ b/crates/storage/provider/src/providers/mod.rs @@ -2,8 +2,8 @@ use crate::{ BlockHashProvider, BlockIdProvider, BlockNumProvider, BlockProvider, BlockProviderIdExt, BlockchainTreePendingStateProvider, CanonChainTracker, CanonStateNotifications, CanonStateSubscriptions, EvmEnvProvider, HeaderProvider, PostStateDataProvider, ProviderError, - ReceiptProvider, StageCheckpointReader, StateProviderBox, StateProviderFactory, - TransactionsProvider, WithdrawalsProvider, + ReceiptProvider, ReceiptProviderIdExt, StageCheckpointReader, StateProviderBox, + StateProviderFactory, TransactionsProvider, WithdrawalsProvider, }; use reth_db::{database::Database, models::StoredBlockBodyIndices}; use reth_interfaces::{ @@ -327,6 +327,33 @@ where self.database.provider()?.receipts_by_block(block) } } +impl ReceiptProviderIdExt for BlockchainProvider +where + DB: Database, + Tree: BlockchainTreeViewer + Send + Sync, +{ + fn receipts_by_block_id(&self, block: BlockId) -> Result>> { + match block { + BlockId::Hash(rpc_block_hash) => { + let mut receipts = self.receipts_by_block(rpc_block_hash.block_hash.into())?; + if receipts.is_none() && !rpc_block_hash.require_canonical.unwrap_or(false) { + receipts = self.tree.receipts_by_block_hash(rpc_block_hash.block_hash); + } + Ok(receipts) + } + BlockId::Number(num_tag) => match num_tag { + BlockNumberOrTag::Pending => Ok(self.tree.pending_receipts()), + _ => { + if let Some(num) = self.convert_block_number(num_tag)? { + self.receipts_by_block(num.into()) + } else { + Ok(None) + } + } + }, + } + } +} impl WithdrawalsProvider for BlockchainProvider where @@ -600,6 +627,10 @@ where fn pending_block_num_hash(&self) -> Option { self.tree.pending_block_num_hash() } + + fn receipts_by_block_hash(&self, block_hash: BlockHash) -> Option> { + self.tree.receipts_by_block_hash(block_hash) + } } impl CanonChainTracker for BlockchainProvider @@ -640,7 +671,7 @@ where impl BlockProviderIdExt for BlockchainProvider where - Self: BlockProvider + BlockIdProvider, + Self: BlockProvider + BlockIdProvider + ReceiptProviderIdExt, Tree: BlockchainTreeEngine, { fn block_by_id(&self, id: BlockId) -> Result> { diff --git a/crates/storage/provider/src/test_utils/mock.rs b/crates/storage/provider/src/test_utils/mock.rs index 4e09510e72..0c6cd427ba 100644 --- a/crates/storage/provider/src/test_utils/mock.rs +++ b/crates/storage/provider/src/test_utils/mock.rs @@ -2,8 +2,8 @@ use crate::{ traits::{BlockSource, ReceiptProvider}, AccountReader, BlockHashProvider, BlockIdProvider, BlockNumProvider, BlockProvider, BlockProviderIdExt, EvmEnvProvider, HeaderProvider, PostState, PostStateDataProvider, - StateProvider, StateProviderBox, StateProviderFactory, StateRootProvider, TransactionsProvider, - WithdrawalsProvider, + ReceiptProviderIdExt, StateProvider, StateProviderBox, StateProviderFactory, StateRootProvider, + TransactionsProvider, WithdrawalsProvider, }; use parking_lot::Mutex; use reth_db::models::StoredBlockBodyIndices; @@ -239,6 +239,8 @@ impl ReceiptProvider for MockEthProvider { } } +impl ReceiptProviderIdExt for MockEthProvider {} + impl BlockHashProvider for MockEthProvider { fn block_hash(&self, number: u64) -> Result> { let lock = self.blocks.lock(); diff --git a/crates/storage/provider/src/test_utils/noop.rs b/crates/storage/provider/src/test_utils/noop.rs index 2edbde9ca5..253e7982e8 100644 --- a/crates/storage/provider/src/test_utils/noop.rs +++ b/crates/storage/provider/src/test_utils/noop.rs @@ -1,9 +1,9 @@ use crate::{ traits::{BlockSource, ReceiptProvider}, AccountReader, BlockHashProvider, BlockIdProvider, BlockNumProvider, BlockProvider, - BlockProviderIdExt, EvmEnvProvider, HeaderProvider, PostState, StageCheckpointReader, - StateProvider, StateProviderBox, StateProviderFactory, StateRootProvider, TransactionsProvider, - WithdrawalsProvider, + BlockProviderIdExt, EvmEnvProvider, HeaderProvider, PostState, ReceiptProviderIdExt, + StageCheckpointReader, StateProvider, StateProviderBox, StateProviderFactory, + StateRootProvider, TransactionsProvider, WithdrawalsProvider, }; use reth_db::models::StoredBlockBodyIndices; use reth_interfaces::Result; @@ -179,6 +179,8 @@ impl ReceiptProvider for NoopProvider { } } +impl ReceiptProviderIdExt for NoopProvider {} + impl HeaderProvider for NoopProvider { fn header(&self, _block_hash: &BlockHash) -> Result> { Ok(None) diff --git a/crates/storage/provider/src/traits/block.rs b/crates/storage/provider/src/traits/block.rs index f2ffe87675..c8fbc16e8f 100644 --- a/crates/storage/provider/src/traits/block.rs +++ b/crates/storage/provider/src/traits/block.rs @@ -1,6 +1,6 @@ use crate::{ - BlockIdProvider, BlockNumProvider, HeaderProvider, ReceiptProvider, TransactionsProvider, - WithdrawalsProvider, + BlockIdProvider, BlockNumProvider, HeaderProvider, ReceiptProvider, ReceiptProviderIdExt, + TransactionsProvider, WithdrawalsProvider, }; use reth_db::models::StoredBlockBodyIndices; use reth_interfaces::Result; @@ -113,7 +113,7 @@ pub trait BlockProvider: /// `BlockIdProvider` methods should be used to resolve `BlockId`s to block numbers or hashes, and /// retrieving the block should be done using the type's `BlockProvider` methods. #[auto_impl::auto_impl(&, Arc)] -pub trait BlockProviderIdExt: BlockProvider + BlockIdProvider { +pub trait BlockProviderIdExt: BlockProvider + BlockIdProvider + ReceiptProviderIdExt { /// Returns the block with matching tag from the database /// /// Returns `None` if block is not found. diff --git a/crates/storage/provider/src/traits/receipts.rs b/crates/storage/provider/src/traits/receipts.rs index 46cf992c74..3192679f67 100644 --- a/crates/storage/provider/src/traits/receipts.rs +++ b/crates/storage/provider/src/traits/receipts.rs @@ -1,5 +1,5 @@ use reth_interfaces::Result; -use reth_primitives::{BlockHashOrNumber, BlockId, Receipt, TxHash, TxNumber}; +use reth_primitives::{BlockHashOrNumber, BlockId, BlockNumberOrTag, Receipt, TxHash, TxNumber}; use crate::BlockIdProvider; @@ -7,12 +7,18 @@ use crate::BlockIdProvider; #[auto_impl::auto_impl(&, Arc)] pub trait ReceiptProvider: Send + Sync { /// Get receipt by transaction number + /// + /// Returns `None` if the transaction is not found. fn receipt(&self, id: TxNumber) -> Result>; /// Get receipt by transaction hash. + /// + /// Returns `None` if the transaction is not found. fn receipt_by_hash(&self, hash: TxHash) -> Result>; /// Get receipts by block num or hash. + /// + /// Returns `None` if the block is not found. fn receipts_by_block(&self, block: BlockHashOrNumber) -> Result>>; } @@ -29,7 +35,6 @@ pub trait ReceiptProvider: Send + Sync { pub trait ReceiptProviderIdExt: ReceiptProvider + BlockIdProvider { /// Get receipt by block id fn receipts_by_block_id(&self, block: BlockId) -> Result>> { - // TODO: to implement EIP-1898 at the provider level or not let id = match block { BlockId::Hash(hash) => BlockHashOrNumber::Hash(hash.block_hash), BlockId::Number(num_tag) => { @@ -43,6 +48,14 @@ pub trait ReceiptProviderIdExt: ReceiptProvider + BlockIdProvider { self.receipts_by_block(id) } -} -impl ReceiptProviderIdExt for T where T: ReceiptProvider + BlockIdProvider {} + /// Returns the block with the matching `BlockId` from the database. + /// + /// Returns `None` if block is not found. + fn receipts_by_number_or_tag( + &self, + number_or_tag: BlockNumberOrTag, + ) -> Result>> { + self.receipts_by_block_id(number_or_tag.into()) + } +}