feat: add pending receipts (#3320)

This commit is contained in:
Matthias Seitz
2023-06-22 22:00:16 +02:00
committed by GitHub
parent a4c2f5f69c
commit e8b09cc59b
10 changed files with 98 additions and 20 deletions

View File

@ -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<DB: Database, C: Consensus, EF: ExecutorFactory> BlockchainTree<DB, C, EF>
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()

View File

@ -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<DB: Database, C: Consensus, EF: ExecutorFactory> 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<Vec<Receipt>> {
let tree = self.tree.read();
Some(tree.receipts_by_block_hash(block_hash)?.to_vec())
}
}
impl<DB: Database, C: Consensus, EF: ExecutorFactory> BlockchainTreePendingStateProvider

View File

@ -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<Vec<Receipt>> {
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<Vec<Receipt>>;
/// Returns the pending block if there is one.
fn pending_header(&self) -> Option<SealedHeader> {
self.header_by_hash(self.pending_block_num_hash()?.hash)

View File

@ -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,

View File

@ -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.

View File

@ -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<DB, Tree> ReceiptProviderIdExt for BlockchainProvider<DB, Tree>
where
DB: Database,
Tree: BlockchainTreeViewer + Send + Sync,
{
fn receipts_by_block_id(&self, block: BlockId) -> Result<Option<Vec<Receipt>>> {
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<DB, Tree> WithdrawalsProvider for BlockchainProvider<DB, Tree>
where
@ -600,6 +627,10 @@ where
fn pending_block_num_hash(&self) -> Option<BlockNumHash> {
self.tree.pending_block_num_hash()
}
fn receipts_by_block_hash(&self, block_hash: BlockHash) -> Option<Vec<Receipt>> {
self.tree.receipts_by_block_hash(block_hash)
}
}
impl<DB, Tree> CanonChainTracker for BlockchainProvider<DB, Tree>
@ -640,7 +671,7 @@ where
impl<DB, Tree> BlockProviderIdExt for BlockchainProvider<DB, Tree>
where
Self: BlockProvider + BlockIdProvider,
Self: BlockProvider + BlockIdProvider + ReceiptProviderIdExt,
Tree: BlockchainTreeEngine,
{
fn block_by_id(&self, id: BlockId) -> Result<Option<Block>> {

View File

@ -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<Option<H256>> {
let lock = self.blocks.lock();

View File

@ -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<Option<Header>> {
Ok(None)

View File

@ -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.

View File

@ -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<Option<Receipt>>;
/// Get receipt by transaction hash.
///
/// Returns `None` if the transaction is not found.
fn receipt_by_hash(&self, hash: TxHash) -> Result<Option<Receipt>>;
/// Get receipts by block num or hash.
///
/// Returns `None` if the block is not found.
fn receipts_by_block(&self, block: BlockHashOrNumber) -> Result<Option<Vec<Receipt>>>;
}
@ -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<Option<Vec<Receipt>>> {
// 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<T> 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<Option<Vec<Receipt>>> {
self.receipts_by_block_id(number_or_tag.into())
}
}