perf(rpc): improve gas price perf by skipping hash (#2657)

This commit is contained in:
Matthias Seitz
2023-05-13 18:34:06 +02:00
committed by GitHub
parent a0b6b207a6
commit 4d0406b383
7 changed files with 135 additions and 25 deletions

View File

@@ -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<DB: Database, C: Consensus, EF: ExecutorFactory> BlockchainTreeViewer
self.tree.read().block_indices().block_number_to_block_hashes().clone()
}
fn header_by_hash(&self, hash: BlockHash) -> Option<SealedHeader> {
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<SealedBlock> {
trace!(target: "blockchain_tree", ?block_hash, "Returning block by hash");
self.tree.read().block_by_hash(block_hash).cloned()

View File

@@ -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<BlockNumber, HashSet<BlockHash>>;
/// 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<SealedHeader>;
/// 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<SealedBlock> {
self.block_by_hash(self.pending_block_num_hash()?.hash)
}
/// 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

@@ -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<U256> {
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

View File

@@ -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<SealedHeader> {
self.tree.header_by_hash(hash)
}
fn block_by_hash(&self, block_hash: BlockHash) -> Option<SealedBlock> {
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<Instant> {
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<Instant> {
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<Option<Header>> {
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<Option<SealedHeader>> {
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<Option<SealedHeader>> {
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<Option<Header>> {
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<Option<Vec<Header>>> {
match id {
BlockId::Number(num) => self.ommers_by_number_or_tag(num),

View File

@@ -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<Option<SealedHeader>> {
self.header_by_id(id)?.map_or_else(|| Ok(None), |h| Ok(Some(h.seal_slow())))
}
fn header_by_id(&self, id: BlockId) -> Result<Option<Header>> {
match self.block_by_id(id)? {
None => Ok(None),
Some(block) => Ok(Some(block.header)),
}
}
fn ommers_by_id(&self, id: BlockId) -> Result<Option<Vec<Header>>> {
match id {
BlockId::Number(num) => self.ommers_by_number_or_tag(num),

View File

@@ -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<Option<SealedHeader>> {
Ok(None)
}
fn header_by_id(&self, _id: BlockId) -> Result<Option<Header>> {
Ok(None)
}
fn ommers_by_id(&self, _id: BlockId) -> Result<Option<Vec<Header>>> {
Ok(None)
}

View File

@@ -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<Option<Block>>;
/// 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<Option<Header>> {
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<Option<SealedHeader>> {
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<Option<SealedHeader>>;
/// 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<Option<Header>>;
/// Returns the ommers with the matching tag from the database.
fn ommers_by_number_or_tag(&self, id: BlockNumberOrTag) -> Result<Option<Vec<Header>>> {
self.convert_block_number(id)?.map_or_else(|| Ok(None), |num| self.ommers(num.into()))