feat: add Block AT to BlockReader (#12837)

This commit is contained in:
Arsenii Kulikov
2024-11-25 18:28:56 +04:00
committed by GitHub
parent e2c42ae242
commit c44e11b8ad
69 changed files with 664 additions and 267 deletions

View File

@ -2,21 +2,32 @@
use std::sync::Arc;
use alloy_consensus::BlockHeader;
use alloy_eips::BlockId;
use alloy_rpc_types_eth::{Block, Header, Index};
use futures::Future;
use reth_primitives::{Receipt, SealedBlock, SealedBlockWithSenders};
use reth_node_api::BlockBody;
use reth_primitives::{Receipt, SealedBlockFor, SealedBlockWithSenders};
use reth_provider::{BlockIdReader, BlockReader, BlockReaderIdExt, HeaderProvider};
use reth_rpc_types_compat::block::from_block;
use crate::{node::RpcNodeCoreExt, FromEthApiError, FullEthApiTypes, RpcBlock, RpcReceipt};
use crate::{
node::RpcNodeCoreExt, EthApiTypes, FromEthApiError, FullEthApiTypes, RpcBlock, RpcNodeCore,
RpcReceipt,
};
use super::{LoadPendingBlock, LoadReceipt, SpawnBlocking};
/// Result type of the fetched block receipts.
pub type BlockReceiptsResult<N, E> = Result<Option<Vec<RpcReceipt<N>>>, E>;
/// Result type of the fetched block and its receipts.
pub type BlockAndReceiptsResult<E> = Result<Option<(SealedBlock, Arc<Vec<Receipt>>)>, E>;
pub type BlockAndReceiptsResult<Eth> = Result<
Option<(
SealedBlockFor<<<Eth as RpcNodeCore>::Provider as BlockReader>::Block>,
Arc<Vec<Receipt>>,
)>,
<Eth as EthApiTypes>::Error,
>;
/// Block related functions for the [`EthApiServer`](crate::EthApiServer) trait in the
/// `eth_` namespace.
@ -49,7 +60,7 @@ pub trait EthBlocks: LoadBlock {
let block_hash = block.hash();
let mut total_difficulty = self
.provider()
.header_td_by_number(block.number)
.header_td_by_number(block.number())
.map_err(Self::Error::from_eth_err)?;
if total_difficulty.is_none() {
// if we failed to find td after we successfully loaded the block, try again using
@ -83,7 +94,7 @@ pub trait EthBlocks: LoadBlock {
.provider()
.pending_block()
.map_err(Self::Error::from_eth_err)?
.map(|block| block.body.transactions.len()))
.map(|block| block.body.transactions().len()))
}
let block_hash = match self
@ -120,7 +131,7 @@ pub trait EthBlocks: LoadBlock {
fn load_block_and_receipts(
&self,
block_id: BlockId,
) -> impl Future<Output = BlockAndReceiptsResult<Self::Error>> + Send
) -> impl Future<Output = BlockAndReceiptsResult<Self>> + Send
where
Self: LoadReceipt,
{
@ -198,10 +209,16 @@ pub trait EthBlocks: LoadBlock {
/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` blocks RPC methods.
pub trait LoadBlock: LoadPendingBlock + SpawnBlocking + RpcNodeCoreExt {
/// Returns the block object for the given block id.
#[expect(clippy::type_complexity)]
fn block_with_senders(
&self,
block_id: BlockId,
) -> impl Future<Output = Result<Option<Arc<SealedBlockWithSenders>>, Self::Error>> + Send {
) -> impl Future<
Output = Result<
Option<Arc<SealedBlockWithSenders<<Self::Provider as BlockReader>::Block>>>,
Self::Error,
>,
> + Send {
async move {
if block_id.is_pending() {
// Pending block can be fetched directly without need for caching

View File

@ -18,6 +18,7 @@ use alloy_rpc_types_eth::{
use futures::Future;
use reth_chainspec::EthChainSpec;
use reth_evm::{ConfigureEvm, ConfigureEvmEnv};
use reth_node_api::BlockBody;
use reth_primitives::TransactionSigned;
use reth_provider::{BlockIdReader, ChainSpecProvider, HeaderProvider};
use reth_revm::{
@ -278,14 +279,15 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock {
// we're essentially replaying the transactions in the block here, hence we need the
// state that points to the beginning of the block, which is the state at
// the parent block
let mut at = block.parent_hash;
let mut at = block.parent_hash();
let mut replay_block_txs = true;
let num_txs = transaction_index.index().unwrap_or(block.body.transactions.len());
let num_txs =
transaction_index.index().unwrap_or_else(|| block.body.transactions().len());
// but if all transactions are to be replayed, we can use the state at the block itself,
// however only if we're not targeting the pending block, because for pending we can't
// rely on the block's state being available
if !is_block_target_pending && num_txs == block.body.transactions.len() {
if !is_block_target_pending && num_txs == block.body.transactions().len() {
at = block.hash();
replay_block_txs = false;
}

View File

@ -1,5 +1,6 @@
//! Loads fee history from database. Helper trait for `eth_` fee and transaction RPC methods.
use alloy_consensus::BlockHeader;
use alloy_primitives::U256;
use alloy_rpc_types_eth::{BlockNumberOrTag, FeeHistory};
use futures::Future;
@ -287,7 +288,7 @@ pub trait LoadFee: LoadBlock {
.block_with_senders(BlockNumberOrTag::Pending.into())
.await?
.ok_or(EthApiError::HeaderNotFound(BlockNumberOrTag::Pending.into()))?
.base_fee_per_gas
.base_fee_per_gas()
.ok_or(EthApiError::InvalidTransaction(
RpcInvalidTransactionError::TxTypeNotSupported,
))?;
@ -324,7 +325,7 @@ pub trait LoadFee: LoadBlock {
let suggested_tip = self.suggested_priority_fee();
async move {
let (header, suggested_tip) = futures::try_join!(header, suggested_tip)?;
let base_fee = header.and_then(|h| h.base_fee_per_gas).unwrap_or_default();
let base_fee = header.and_then(|h| h.base_fee_per_gas()).unwrap_or_default();
Ok(suggested_tip + U256::from(base_fee))
}
}

View File

@ -45,7 +45,7 @@ use tracing::debug;
pub trait LoadPendingBlock:
EthApiTypes
+ RpcNodeCore<
Provider: BlockReaderIdExt
Provider: BlockReaderIdExt<Block = reth_primitives::Block>
+ EvmEnvProvider
+ ChainSpecProvider<ChainSpec: EthChainSpec + EthereumHardforks>
+ StateProviderFactory,
@ -114,9 +114,15 @@ pub trait LoadPendingBlock:
}
/// Returns the locally built pending block
#[expect(clippy::type_complexity)]
fn local_pending_block(
&self,
) -> impl Future<Output = Result<Option<(SealedBlockWithSenders, Vec<Receipt>)>, Self::Error>> + Send
) -> impl Future<
Output = Result<
Option<(SealedBlockWithSenders<<Self::Provider as BlockReader>::Block>, Vec<Receipt>)>,
Self::Error,
>,
> + Send
where
Self: SpawnBlocking,
{

View File

@ -10,6 +10,7 @@ use futures::Future;
use reth_chainspec::ChainSpecProvider;
use reth_evm::{system_calls::SystemCaller, ConfigureEvm, ConfigureEvmEnv};
use reth_primitives::SealedBlockWithSenders;
use reth_provider::BlockReader;
use reth_revm::database::StateProviderDatabase;
use reth_rpc_eth_types::{
cache::db::{StateCacheDb, StateCacheDbRefMutWrapper, StateProviderTraitObjWrapper},
@ -24,7 +25,7 @@ use revm_primitives::{
use super::{Call, LoadBlock, LoadPendingBlock, LoadState, LoadTransaction};
/// Executes CPU heavy tasks.
pub trait Trace: LoadState<Evm: ConfigureEvm<Header = Header>> {
pub trait Trace: LoadState<Provider: BlockReader, Evm: ConfigureEvm<Header = Header>> {
/// Executes the [`EnvWithHandlerCfg`] against the given [Database] without committing state
/// changes.
fn inspect<DB, I>(
@ -230,7 +231,7 @@ pub trait Trace: LoadState<Evm: ConfigureEvm<Header = Header>> {
fn trace_block_until<F, R>(
&self,
block_id: BlockId,
block: Option<Arc<SealedBlockWithSenders>>,
block: Option<Arc<SealedBlockWithSenders<<Self::Provider as BlockReader>::Block>>>,
highest_index: Option<u64>,
config: TracingInspectorConfig,
f: F,

View File

@ -1,7 +1,7 @@
//! Database access for `eth_` transaction RPC methods. Loads transaction and receipt data w.r.t.
//! network.
use alloy_consensus::Transaction;
use alloy_consensus::{BlockHeader, Transaction};
use alloy_dyn_abi::TypedData;
use alloy_eips::{eip2718::Encodable2718, BlockId};
use alloy_network::TransactionBuilder;
@ -199,8 +199,8 @@ pub trait EthTransactions: LoadTransaction<Provider: BlockReaderIdExt> {
async move {
if let Some(block) = self.block_with_senders(block_id).await? {
let block_hash = block.hash();
let block_number = block.number;
let base_fee_per_gas = block.base_fee_per_gas;
let block_number = block.number();
let base_fee_per_gas = block.base_fee_per_gas();
if let Some((signer, tx)) = block.transactions_with_sender().nth(index) {
let tx_info = TransactionInfo {
hash: Some(tx.hash()),
@ -275,8 +275,8 @@ pub trait EthTransactions: LoadTransaction<Provider: BlockReaderIdExt> {
.await?
.and_then(|block| {
let block_hash = block.hash();
let block_number = block.number;
let base_fee_per_gas = block.base_fee_per_gas;
let block_number = block.number();
let base_fee_per_gas = block.base_fee_per_gas();
block
.transactions_with_sender()