diff --git a/crates/blockchain-tree/src/shareable.rs b/crates/blockchain-tree/src/shareable.rs index f7a02ec875..d950d6c049 100644 --- a/crates/blockchain-tree/src/shareable.rs +++ b/crates/blockchain-tree/src/shareable.rs @@ -7,7 +7,9 @@ use reth_interfaces::{ consensus::Consensus, Error, }; -use reth_primitives::{BlockHash, BlockNumHash, BlockNumber, SealedBlock, SealedBlockWithSenders}; +use reth_primitives::{ + BlockHash, BlockNumHash, BlockNumber, SealedBlock, SealedBlockWithSenders, SealedHeader, +}; use reth_provider::{ BlockchainTreePendingStateProvider, CanonStateSubscriptions, ExecutorFactory, PostStateDataProvider, @@ -85,6 +87,11 @@ impl BlockchainTreeViewer self.tree.read().block_indices().block_number_to_block_hashes().clone() } + fn header_by_hash(&self, hash: BlockHash) -> Option { + trace!(target: "blockchain_tree", ?hash, "Returning header by hash"); + self.tree.read().block_by_hash(hash).map(|b| b.header.clone()) + } + fn block_by_hash(&self, block_hash: BlockHash) -> Option { trace!(target: "blockchain_tree", ?block_hash, "Returning block by hash"); self.tree.read().block_by_hash(block_hash).cloned() diff --git a/crates/interfaces/src/blockchain_tree.rs b/crates/interfaces/src/blockchain_tree.rs index 03d69c50bb..80d308e31f 100644 --- a/crates/interfaces/src/blockchain_tree.rs +++ b/crates/interfaces/src/blockchain_tree.rs @@ -1,5 +1,7 @@ use crate::{executor::Error as ExecutionError, Error}; -use reth_primitives::{BlockHash, BlockNumHash, BlockNumber, SealedBlock, SealedBlockWithSenders}; +use reth_primitives::{ + BlockHash, BlockNumHash, BlockNumber, SealedBlock, SealedBlockWithSenders, SealedHeader, +}; use std::collections::{BTreeMap, HashSet}; /// * [BlockchainTreeEngine::insert_block]: Connect block to chain, execute it and if valid insert @@ -90,6 +92,11 @@ pub trait BlockchainTreeViewer: Send + Sync { /// Caution: This will not return blocks from the canonical chain. fn blocks(&self) -> BTreeMap>; + /// Returns the header with matching hash from the tree, if it exists. + /// + /// Caution: This will not return headers from the canonical chain. + fn header_by_hash(&self, hash: BlockHash) -> Option; + /// Returns the block with matching hash from the tree, if it exists. /// /// Caution: This will not return blocks from the canonical chain. @@ -124,4 +131,9 @@ pub trait BlockchainTreeViewer: Send + Sync { fn pending_block(&self) -> Option { self.block_by_hash(self.pending_block_num_hash()?.hash) } + + /// 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/eth/gas_oracle.rs b/crates/rpc/rpc/src/eth/gas_oracle.rs index 76bdfb4057..3e21513211 100644 --- a/crates/rpc/rpc/src/eth/gas_oracle.rs +++ b/crates/rpc/rpc/src/eth/gas_oracle.rs @@ -4,7 +4,7 @@ use crate::eth::{ cache::EthStateCache, error::{EthApiError, EthResult, InvalidTransactionError}, }; -use reth_primitives::{constants::GWEI_TO_WEI, BlockId, BlockNumberOrTag, H256, U256}; +use reth_primitives::{constants::GWEI_TO_WEI, BlockNumberOrTag, H256, U256}; use reth_provider::BlockProviderIdExt; use serde::{Deserialize, Serialize}; use tokio::sync::Mutex; @@ -82,7 +82,7 @@ where mut oracle_config: GasPriceOracleConfig, cache: EthStateCache, ) -> Self { - // sanitize the perentile to be less than 100 + // sanitize the percentile to be less than 100 if oracle_config.percentile > 100 { warn!(prev_percentile=?oracle_config.percentile, "Invalid configured gas price percentile, using 100 instead"); oracle_config.percentile = 100; @@ -93,14 +93,11 @@ where /// Suggests a gas price estimate based on recent blocks, using the configured percentile. pub async fn suggest_tip_cap(&self) -> EthResult { - let block = self + let header = self .client - .block_by_id(BlockId::Number(BlockNumberOrTag::Latest))? + .sealed_header_by_number_or_tag(BlockNumberOrTag::Latest)? .ok_or(EthApiError::UnknownBlockNumber)?; - // seal for the block hash - let header = block.header.seal_slow(); - let mut last_price = self.last_price.lock().await; // if we have stored a last price, then we check whether or not it was for the same head diff --git a/crates/storage/provider/src/providers/mod.rs b/crates/storage/provider/src/providers/mod.rs index 924d4b0674..cc3b0bec8b 100644 --- a/crates/storage/provider/src/providers/mod.rs +++ b/crates/storage/provider/src/providers/mod.rs @@ -12,9 +12,9 @@ use reth_interfaces::{ Error, Result, }; use reth_primitives::{ - Block, BlockHash, BlockHashOrNumber, BlockId, BlockNumHash, BlockNumber, ChainInfo, Header, - Receipt, SealedBlock, SealedBlockWithSenders, SealedHeader, TransactionMeta, TransactionSigned, - TxHash, TxNumber, Withdrawal, H256, U256, + Block, BlockHash, BlockHashOrNumber, BlockId, BlockNumHash, BlockNumber, BlockNumberOrTag, + ChainInfo, Header, Receipt, SealedBlock, SealedBlockWithSenders, SealedHeader, TransactionMeta, + TransactionSigned, TxHash, TxNumber, Withdrawal, H256, U256, }; use reth_revm_primitives::primitives::{BlockEnv, CfgEnv}; pub use state::{ @@ -405,6 +405,10 @@ where self.tree.blocks() } + fn header_by_hash(&self, hash: BlockHash) -> Option { + self.tree.header_by_hash(hash) + } + fn block_by_hash(&self, block_hash: BlockHash) -> Option { self.tree.block_by_hash(block_hash) } @@ -441,20 +445,20 @@ where self.chain_info.on_forkchoice_update_received(); } - fn set_finalized(&self, header: SealedHeader) { - self.chain_info.set_finalized(header); - } - - fn set_safe(&self, header: SealedHeader) { - self.chain_info.set_safe(header); + fn last_received_update_timestamp(&self) -> Option { + self.chain_info.last_forkchoice_update_received_at() } fn set_canonical_head(&self, header: SealedHeader) { self.chain_info.set_canonical_head(header); } - fn last_received_update_timestamp(&self) -> Option { - self.chain_info.last_forkchoice_update_received_at() + fn set_safe(&self, header: SealedHeader) { + self.chain_info.set_safe(header); + } + + fn set_finalized(&self, header: SealedHeader) { + self.chain_info.set_finalized(header); } } @@ -481,6 +485,50 @@ where } } + fn header_by_number_or_tag(&self, id: BlockNumberOrTag) -> Result> { + match id { + BlockNumberOrTag::Latest => Ok(Some(self.chain_info.get_canonical_head().unseal())), + BlockNumberOrTag::Finalized => { + Ok(self.chain_info.get_finalized_header().map(|h| h.unseal())) + } + BlockNumberOrTag::Safe => Ok(self.chain_info.get_safe_header().map(|h| h.unseal())), + BlockNumberOrTag::Earliest => self.header_by_number(0), + BlockNumberOrTag::Pending => Ok(self.tree.pending_header().map(|h| h.unseal())), + BlockNumberOrTag::Number(num) => self.header_by_number(num), + } + } + + fn sealed_header_by_number_or_tag(&self, id: BlockNumberOrTag) -> Result> { + match id { + BlockNumberOrTag::Latest => Ok(Some(self.chain_info.get_canonical_head())), + BlockNumberOrTag::Finalized => Ok(self.chain_info.get_finalized_header()), + BlockNumberOrTag::Safe => Ok(self.chain_info.get_safe_header()), + BlockNumberOrTag::Earliest => { + self.header_by_number(0)?.map_or_else(|| Ok(None), |h| Ok(Some(h.seal_slow()))) + } + BlockNumberOrTag::Pending => Ok(self.tree.pending_header()), + BlockNumberOrTag::Number(num) => { + self.header_by_number(num)?.map_or_else(|| Ok(None), |h| Ok(Some(h.seal_slow()))) + } + } + } + + fn sealed_header_by_id(&self, id: BlockId) -> Result> { + match id { + BlockId::Number(num) => self.sealed_header_by_number_or_tag(num), + BlockId::Hash(hash) => { + self.header(&hash.block_hash)?.map_or_else(|| Ok(None), |h| Ok(Some(h.seal_slow()))) + } + } + } + + fn header_by_id(&self, id: BlockId) -> Result> { + match id { + BlockId::Number(num) => self.header_by_number_or_tag(num), + BlockId::Hash(hash) => self.header(&hash.block_hash), + } + } + fn ommers_by_id(&self, id: BlockId) -> Result>> { match id { BlockId::Number(num) => self.ommers_by_number_or_tag(num), diff --git a/crates/storage/provider/src/test_utils/mock.rs b/crates/storage/provider/src/test_utils/mock.rs index 3b2172e011..1dc1b17851 100644 --- a/crates/storage/provider/src/test_utils/mock.rs +++ b/crates/storage/provider/src/test_utils/mock.rs @@ -8,8 +8,8 @@ use parking_lot::Mutex; use reth_interfaces::Result; use reth_primitives::{ keccak256, Account, Address, Block, BlockHash, BlockHashOrNumber, BlockId, BlockNumber, - Bytecode, Bytes, ChainInfo, Header, Receipt, SealedBlock, StorageKey, StorageValue, - TransactionMeta, TransactionSigned, TxHash, TxNumber, H256, U256, + Bytecode, Bytes, ChainInfo, Header, Receipt, SealedBlock, SealedHeader, StorageKey, + StorageValue, TransactionMeta, TransactionSigned, TxHash, TxNumber, H256, U256, }; use reth_revm_primitives::primitives::{BlockEnv, CfgEnv}; use std::{ @@ -306,6 +306,17 @@ impl BlockProviderIdExt for MockEthProvider { } } + fn sealed_header_by_id(&self, id: BlockId) -> Result> { + self.header_by_id(id)?.map_or_else(|| Ok(None), |h| Ok(Some(h.seal_slow()))) + } + + fn header_by_id(&self, id: BlockId) -> Result> { + match self.block_by_id(id)? { + None => Ok(None), + Some(block) => Ok(Some(block.header)), + } + } + fn ommers_by_id(&self, id: BlockId) -> Result>> { match id { BlockId::Number(num) => self.ommers_by_number_or_tag(num), diff --git a/crates/storage/provider/src/test_utils/noop.rs b/crates/storage/provider/src/test_utils/noop.rs index d3bf077cac..318dbaee89 100644 --- a/crates/storage/provider/src/test_utils/noop.rs +++ b/crates/storage/provider/src/test_utils/noop.rs @@ -7,8 +7,8 @@ use crate::{ use reth_interfaces::Result; use reth_primitives::{ Account, Address, Block, BlockHash, BlockHashOrNumber, BlockId, BlockNumber, Bytecode, Bytes, - ChainInfo, Header, Receipt, SealedBlock, StorageKey, StorageValue, TransactionMeta, - TransactionSigned, TxHash, TxNumber, H256, KECCAK_EMPTY, U256, + ChainInfo, Header, Receipt, SealedBlock, SealedHeader, StorageKey, StorageValue, + TransactionMeta, TransactionSigned, TxHash, TxNumber, H256, KECCAK_EMPTY, U256, }; use reth_revm_primitives::primitives::{BlockEnv, CfgEnv}; use std::ops::RangeBounds; @@ -66,6 +66,14 @@ impl BlockProviderIdExt for NoopProvider { Ok(None) } + fn sealed_header_by_id(&self, _id: BlockId) -> Result> { + Ok(None) + } + + fn header_by_id(&self, _id: BlockId) -> Result> { + Ok(None) + } + fn ommers_by_id(&self, _id: BlockId) -> Result>> { Ok(None) } diff --git a/crates/storage/provider/src/traits/block.rs b/crates/storage/provider/src/traits/block.rs index ec06997356..68a4f65a89 100644 --- a/crates/storage/provider/src/traits/block.rs +++ b/crates/storage/provider/src/traits/block.rs @@ -3,7 +3,7 @@ use crate::{ }; use reth_interfaces::Result; use reth_primitives::{ - Block, BlockHashOrNumber, BlockId, BlockNumberOrTag, Header, SealedBlock, H256, + Block, BlockHashOrNumber, BlockId, BlockNumberOrTag, Header, SealedBlock, SealedHeader, H256, }; /// A helper enum that represents the origin of the requested block. @@ -107,6 +107,33 @@ pub trait BlockProviderIdExt: BlockProvider + BlockIdProvider { /// Returns `None` if block is not found. fn block_by_id(&self, id: BlockId) -> Result>; + /// Returns the header with matching tag from the database + /// + /// Returns `None` if header is not found. + fn header_by_number_or_tag(&self, id: BlockNumberOrTag) -> Result> { + self.convert_block_number(id)? + .map_or_else(|| Ok(None), |num| self.header_by_hash_or_number(num.into())) + } + + /// Returns the header with matching tag from the database + /// + /// Returns `None` if header is not found. + fn sealed_header_by_number_or_tag(&self, id: BlockNumberOrTag) -> Result> { + self.convert_block_number(id)? + .map_or_else(|| Ok(None), |num| self.header_by_hash_or_number(num.into()))? + .map_or_else(|| Ok(None), |h| Ok(Some(h.seal_slow()))) + } + + /// Returns the sealed header with the matching `BlockId` from the database. + /// + /// Returns `None` if header is not found. + fn sealed_header_by_id(&self, id: BlockId) -> Result>; + + /// Returns the header with the matching `BlockId` from the database. + /// + /// Returns `None` if header is not found. + fn header_by_id(&self, id: BlockId) -> Result>; + /// Returns the ommers with the matching tag from the database. fn ommers_by_number_or_tag(&self, id: BlockNumberOrTag) -> Result>> { self.convert_block_number(id)?.map_or_else(|| Ok(None), |num| self.ommers(num.into()))