mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-27 08:08:15 -05:00
Pending receipt (#10597)
Co-authored-by: Emilia Hane <emiliaha95@gmail.com> Co-authored-by: Federico Gimenez <fgimenez@users.noreply.github.com> Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
@@ -4,11 +4,11 @@ use reth_chainspec::ChainSpec;
|
||||
use reth_evm::ConfigureEvm;
|
||||
use reth_node_api::FullNodeComponents;
|
||||
use reth_primitives::{
|
||||
revm_primitives::BlockEnv, BlockHashOrNumber, BlockNumber, SealedBlockWithSenders, B256,
|
||||
revm_primitives::BlockEnv, BlockNumber, Receipt, SealedBlockWithSenders, B256,
|
||||
};
|
||||
use reth_provider::{
|
||||
BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, ExecutionOutcome,
|
||||
StateProviderFactory,
|
||||
ReceiptProvider, StateProviderFactory,
|
||||
};
|
||||
use reth_rpc_eth_api::{
|
||||
helpers::{LoadPendingBlock, SpawnBlocking},
|
||||
@@ -50,17 +50,28 @@ where
|
||||
}
|
||||
|
||||
/// Returns the locally built pending block
|
||||
async fn local_pending_block(&self) -> Result<Option<SealedBlockWithSenders>, Self::Error> {
|
||||
async fn local_pending_block(
|
||||
&self,
|
||||
) -> Result<Option<(SealedBlockWithSenders, Vec<Receipt>)>, Self::Error> {
|
||||
// See: <https://github.com/ethereum-optimism/op-geth/blob/f2e69450c6eec9c35d56af91389a1c47737206ca/miner/worker.go#L367-L375>
|
||||
let latest = self
|
||||
.provider()
|
||||
.latest_header()
|
||||
.map_err(Self::Error::from_eth_err)?
|
||||
.ok_or_else(|| EthApiError::UnknownBlockNumber)?;
|
||||
let (_, block_hash) = latest.split();
|
||||
self.provider()
|
||||
.sealed_block_with_senders(BlockHashOrNumber::from(block_hash), Default::default())
|
||||
.map_err(Self::Error::from_eth_err)
|
||||
let block = self
|
||||
.provider()
|
||||
.block_with_senders(latest.hash().into(), Default::default())
|
||||
.map_err(Self::Error::from_eth_err)?
|
||||
.ok_or_else(|| EthApiError::UnknownBlockNumber)?
|
||||
.seal(latest.hash());
|
||||
|
||||
let receipts = self
|
||||
.provider()
|
||||
.receipts_by_block(block.hash().into())
|
||||
.map_err(Self::Error::from_eth_err)?
|
||||
.ok_or_else(|| EthApiError::UnknownBlockNumber)?;
|
||||
Ok(Some((block, receipts)))
|
||||
}
|
||||
|
||||
fn receipts_root(
|
||||
|
||||
@@ -145,10 +145,19 @@ pub trait EthBlocks: LoadBlock {
|
||||
{
|
||||
async move {
|
||||
if block_id.is_pending() {
|
||||
return Ok(LoadBlock::provider(self)
|
||||
// First, try to get the pending block from the provider, in case we already
|
||||
// received the actual pending block from the CL.
|
||||
if let Some((block, receipts)) = LoadBlock::provider(self)
|
||||
.pending_block_and_receipts()
|
||||
.map_err(Self::Error::from_eth_err)?
|
||||
.map(|(sb, receipts)| (sb, Arc::new(receipts))))
|
||||
{
|
||||
return Ok(Some((block, Arc::new(receipts))));
|
||||
}
|
||||
|
||||
// If no pending block from provider, build the pending block locally.
|
||||
if let Some((block, receipts)) = self.local_pending_block().await? {
|
||||
return Ok(Some((block.block, Arc::new(receipts))));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(block_hash) = LoadBlock::provider(self)
|
||||
@@ -243,8 +252,12 @@ pub trait LoadBlock: LoadPendingBlock + SpawnBlocking {
|
||||
return if maybe_pending.is_some() {
|
||||
Ok(maybe_pending)
|
||||
} else {
|
||||
self.local_pending_block().await
|
||||
}
|
||||
// If no pending block from provider, try to get local pending block
|
||||
return match self.local_pending_block().await? {
|
||||
Some((block, _)) => Ok(Some(block)),
|
||||
None => Ok(None),
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
let block_hash = match LoadPendingBlock::provider(self)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use crate::{EthApiTypes, FromEthApiError, FromEvmError};
|
||||
use futures::Future;
|
||||
use reth_chainspec::{ChainSpec, EthereumHardforks};
|
||||
use reth_evm::{
|
||||
@@ -23,7 +24,7 @@ use reth_primitives::{
|
||||
};
|
||||
use reth_provider::{
|
||||
BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, ProviderError,
|
||||
StateProviderFactory,
|
||||
ReceiptProvider, StateProviderFactory,
|
||||
};
|
||||
use reth_revm::{
|
||||
database::StateProviderDatabase, state_change::post_block_withdrawals_balance_increments,
|
||||
@@ -34,8 +35,6 @@ use revm::{db::states::bundle_state::BundleRetention, DatabaseCommit, State};
|
||||
use tokio::sync::Mutex;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::{EthApiTypes, FromEthApiError, FromEvmError};
|
||||
|
||||
use super::SpawnBlocking;
|
||||
|
||||
/// Loads a pending block from database.
|
||||
@@ -125,16 +124,26 @@ pub trait LoadPendingBlock: EthApiTypes {
|
||||
/// Returns the locally built pending block
|
||||
fn local_pending_block(
|
||||
&self,
|
||||
) -> impl Future<Output = Result<Option<SealedBlockWithSenders>, Self::Error>> + Send
|
||||
) -> impl Future<Output = Result<Option<(SealedBlockWithSenders, Vec<Receipt>)>, Self::Error>> + Send
|
||||
where
|
||||
Self: SpawnBlocking,
|
||||
{
|
||||
async move {
|
||||
let pending = self.pending_block_env_and_cfg()?;
|
||||
if pending.origin.is_actual_pending() {
|
||||
return Ok(pending.origin.into_actual_pending())
|
||||
if let Some(block) = pending.origin.clone().into_actual_pending() {
|
||||
// we have the real pending block, so we should also have its receipts
|
||||
if let Some(receipts) = self
|
||||
.provider()
|
||||
.receipts_by_block(block.hash().into())
|
||||
.map_err(Self::Error::from_eth_err)?
|
||||
{
|
||||
return Ok(Some((block, receipts)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we couldn't find the real pending block, so we need to build it ourselves
|
||||
let mut lock = self.pending_block().lock().await;
|
||||
|
||||
let now = Instant::now();
|
||||
@@ -146,12 +155,12 @@ pub trait LoadPendingBlock: EthApiTypes {
|
||||
pending.origin.header().hash() == pending_block.block.parent_hash &&
|
||||
now <= pending_block.expires_at
|
||||
{
|
||||
return Ok(Some(pending_block.block.clone()))
|
||||
return Ok(Some((pending_block.block.clone(), pending_block.receipts.clone())))
|
||||
}
|
||||
}
|
||||
|
||||
// no pending block from the CL yet, so we need to build it ourselves via txpool
|
||||
let pending_block = match self
|
||||
let (sealed_block, receipts) = match self
|
||||
.spawn_blocking_io(move |this| {
|
||||
// we rebuild the block
|
||||
this.build_block(pending)
|
||||
@@ -166,9 +175,13 @@ pub trait LoadPendingBlock: EthApiTypes {
|
||||
};
|
||||
|
||||
let now = Instant::now();
|
||||
*lock = Some(PendingBlock::new(pending_block.clone(), now + Duration::from_secs(1)));
|
||||
*lock = Some(PendingBlock::new(
|
||||
now + Duration::from_secs(1),
|
||||
sealed_block.clone(),
|
||||
receipts.clone(),
|
||||
));
|
||||
|
||||
Ok(Some(pending_block))
|
||||
Ok(Some((sealed_block, receipts)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +220,10 @@ pub trait LoadPendingBlock: EthApiTypes {
|
||||
///
|
||||
/// After Cancun, if the origin is the actual pending block, the block includes the EIP-4788 pre
|
||||
/// block contract call using the parent beacon block root received from the CL.
|
||||
fn build_block(&self, env: PendingBlockEnv) -> Result<SealedBlockWithSenders, Self::Error>
|
||||
fn build_block(
|
||||
&self,
|
||||
env: PendingBlockEnv,
|
||||
) -> Result<(SealedBlockWithSenders, Vec<Receipt>), Self::Error>
|
||||
where
|
||||
EthApiError: From<ProviderError>,
|
||||
{
|
||||
@@ -382,7 +398,7 @@ pub trait LoadPendingBlock: EthApiTypes {
|
||||
|
||||
let execution_outcome = ExecutionOutcome::new(
|
||||
db.take_bundle(),
|
||||
vec![receipts].into(),
|
||||
vec![receipts.clone()].into(),
|
||||
block_number,
|
||||
Vec::new(),
|
||||
);
|
||||
@@ -438,8 +454,11 @@ pub trait LoadPendingBlock: EthApiTypes {
|
||||
requests_root,
|
||||
};
|
||||
|
||||
// Convert Vec<Option<Receipt>> to Vec<Receipt>
|
||||
let receipts: Vec<Receipt> = receipts.into_iter().flatten().collect();
|
||||
|
||||
// seal the block
|
||||
let block = Block { header, body: executed_txs, ommers: vec![], withdrawals, requests };
|
||||
Ok(SealedBlockWithSenders { block: block.seal_slow(), senders })
|
||||
Ok((SealedBlockWithSenders { block: block.seal_slow(), senders }, receipts))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
use std::time::Instant;
|
||||
|
||||
use derive_more::Constructor;
|
||||
use reth_primitives::{BlockId, BlockNumberOrTag, SealedBlockWithSenders, SealedHeader, B256};
|
||||
use reth_primitives::{
|
||||
BlockId, BlockNumberOrTag, Receipt, SealedBlockWithSenders, SealedHeader, B256,
|
||||
};
|
||||
use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg};
|
||||
|
||||
/// Configured [`BlockEnv`] and [`CfgEnvWithHandlerCfg`] for a pending block
|
||||
/// Configured [`BlockEnv`] and [`CfgEnvWithHandlerCfg`] for a pending block.
|
||||
#[derive(Debug, Clone, Constructor)]
|
||||
pub struct PendingBlockEnv {
|
||||
/// Configured [`CfgEnvWithHandlerCfg`] for the pending block.
|
||||
@@ -79,11 +81,13 @@ impl PendingBlockEnvOrigin {
|
||||
}
|
||||
}
|
||||
|
||||
/// In memory pending block for `pending` tag
|
||||
/// Locally built pending block for `pending` tag.
|
||||
#[derive(Debug, Constructor)]
|
||||
pub struct PendingBlock {
|
||||
/// The cached pending block
|
||||
pub block: SealedBlockWithSenders,
|
||||
/// Timestamp when the pending block is considered outdated
|
||||
/// Timestamp when the pending block is considered outdated.
|
||||
pub expires_at: Instant,
|
||||
/// The locally built pending block.
|
||||
pub block: SealedBlockWithSenders,
|
||||
/// The receipts for the pending block
|
||||
pub receipts: Vec<Receipt>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user