feat: relax provider bounds (#12857)

This commit is contained in:
Arsenii Kulikov
2024-11-26 20:26:36 +04:00
committed by GitHub
parent d51b347c81
commit 2ce741709f
37 changed files with 365 additions and 236 deletions

View File

@ -57,7 +57,7 @@ pub struct BlockchainProvider2<N: NodeTypesWithDB> {
pub(crate) database: ProviderFactory<N>,
/// Tracks the chain info wrt forkchoice updates and in memory canonical
/// state.
pub(crate) canonical_in_memory_state: CanonicalInMemoryState,
pub(crate) canonical_in_memory_state: CanonicalInMemoryState<N::Primitives>,
}
impl<N: NodeTypesWithDB> Clone for BlockchainProvider2<N> {
@ -117,7 +117,7 @@ impl<N: ProviderNodeTypes> BlockchainProvider2<N> {
}
/// Gets a clone of `canonical_in_memory_state`.
pub fn canonical_in_memory_state(&self) -> CanonicalInMemoryState {
pub fn canonical_in_memory_state(&self) -> CanonicalInMemoryState<N::Primitives> {
self.canonical_in_memory_state.clone()
}
@ -132,8 +132,8 @@ impl<N: ProviderNodeTypes> BlockchainProvider2<N> {
/// This uses a given [`BlockState`] to initialize a state provider for that block.
fn block_state_provider(
&self,
state: &BlockState,
) -> ProviderResult<MemoryOverlayStateProvider> {
state: &BlockState<N::Primitives>,
) -> ProviderResult<MemoryOverlayStateProvider<N::Primitives>> {
let anchor_hash = state.anchor().hash;
let latest_historical = self.database.history_by_block_hash(anchor_hash)?;
Ok(state.state_provider(latest_historical))
@ -647,7 +647,7 @@ impl<N: ProviderNodeTypes> StateProviderFactory for BlockchainProvider2<N> {
}
}
impl<N: NodeTypesWithDB> CanonChainTracker for BlockchainProvider2<N>
impl<N: ProviderNodeTypes> CanonChainTracker for BlockchainProvider2<N>
where
Self: BlockReader,
{
@ -721,7 +721,7 @@ impl<N: NodeTypesWithDB<Primitives = EthPrimitives>> CanonStateSubscriptions
}
}
impl<N: NodeTypesWithDB> ForkChoiceSubscriptions for BlockchainProvider2<N> {
impl<N: ProviderNodeTypes> ForkChoiceSubscriptions for BlockchainProvider2<N> {
fn subscribe_safe_block(&self) -> ForkChoiceNotifications {
let receiver = self.canonical_in_memory_state.subscribe_safe_block();
ForkChoiceNotifications(receiver)
@ -2347,7 +2347,7 @@ mod tests {
(block_range, |block: &SealedBlock| block.clone().unseal()),
(block_with_senders_range, |block: &SealedBlock| block
.clone()
.unseal()
.unseal::<reth_primitives::Block>()
.with_senders_unchecked(vec![])),
(sealed_block_with_senders_range, |block: &SealedBlock| block
.clone()
@ -2542,7 +2542,7 @@ mod tests {
block_with_senders,
|block: &SealedBlock, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
(BlockHashOrNumber::Number(block.number), TransactionVariant::WithHash),
block.clone().unseal().with_recovered_senders()
block.clone().unseal::<reth_primitives::Block>().with_recovered_senders()
),
(BlockHashOrNumber::Number(u64::MAX), TransactionVariant::WithHash)
),
@ -2551,7 +2551,7 @@ mod tests {
block_with_senders,
|block: &SealedBlock, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
(BlockHashOrNumber::Hash(block.hash()), TransactionVariant::WithHash),
block.clone().unseal().with_recovered_senders()
block.clone().unseal::<reth_primitives::Block>().with_recovered_senders()
),
(BlockHashOrNumber::Hash(B256::random()), TransactionVariant::WithHash)
),
@ -2561,7 +2561,12 @@ mod tests {
|block: &SealedBlock, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
(BlockHashOrNumber::Number(block.number), TransactionVariant::WithHash),
Some(
block.clone().unseal().with_recovered_senders().unwrap().seal(block.hash())
block
.clone()
.unseal::<reth_primitives::Block>()
.with_recovered_senders()
.unwrap()
.seal(block.hash())
)
),
(BlockHashOrNumber::Number(u64::MAX), TransactionVariant::WithHash)
@ -2572,7 +2577,12 @@ mod tests {
|block: &SealedBlock, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
(BlockHashOrNumber::Hash(block.hash()), TransactionVariant::WithHash),
Some(
block.clone().unseal().with_recovered_senders().unwrap().seal(block.hash())
block
.clone()
.unseal::<reth_primitives::Block>()
.with_recovered_senders()
.unwrap()
.seal(block.hash())
)
),
(BlockHashOrNumber::Hash(B256::random()), TransactionVariant::WithHash)

View File

@ -8,6 +8,7 @@ use crate::{
};
use alloy_consensus::Header;
use alloy_eips::{
eip2718::Encodable2718,
eip4895::{Withdrawal, Withdrawals},
BlockHashOrNumber, BlockId, BlockNumHash, BlockNumberOrTag, HashOrNumber,
};
@ -48,13 +49,14 @@ use tracing::trace;
/// CAUTION: Avoid holding this provider for too long or the inner database transaction will
/// time-out.
#[derive(Debug)]
#[doc(hidden)] // triggers ICE for `cargo docs`
pub struct ConsistentProvider<N: ProviderNodeTypes> {
/// Storage provider.
storage_provider: <ProviderFactory<N> as DatabaseProviderFactory>::Provider,
/// Head block at time of [`Self`] creation
head_block: Option<Arc<BlockState>>,
head_block: Option<Arc<BlockState<N::Primitives>>>,
/// In-memory canonical state. This is not a snapshot, and can change! Use with caution.
canonical_in_memory_state: CanonicalInMemoryState,
canonical_in_memory_state: CanonicalInMemoryState<N::Primitives>,
}
impl<N: ProviderNodeTypes> ConsistentProvider<N> {
@ -65,7 +67,7 @@ impl<N: ProviderNodeTypes> ConsistentProvider<N> {
/// view of memory and database.
pub fn new(
storage_provider_factory: ProviderFactory<N>,
state: CanonicalInMemoryState,
state: CanonicalInMemoryState<N::Primitives>,
) -> ProviderResult<Self> {
// Each one provides a snapshot at the time of instantiation, but its order matters.
//
@ -307,7 +309,7 @@ impl<N: ProviderNodeTypes> ConsistentProvider<N> {
RangeInclusive<BlockNumber>,
&mut P,
) -> ProviderResult<Vec<T>>,
G: Fn(&BlockState, &mut P) -> Option<T>,
G: Fn(&BlockState<N::Primitives>, &mut P) -> Option<T>,
P: FnMut(&T) -> bool,
{
// Each one provides a snapshot at the time of instantiation, but its order matters.
@ -399,8 +401,8 @@ impl<N: ProviderNodeTypes> ConsistentProvider<N> {
/// This uses a given [`BlockState`] to initialize a state provider for that block.
fn block_state_provider_ref(
&self,
state: &BlockState,
) -> ProviderResult<MemoryOverlayStateProviderRef<'_>> {
state: &BlockState<N::Primitives>,
) -> ProviderResult<MemoryOverlayStateProviderRef<'_, N::Primitives>> {
let anchor_hash = state.anchor().hash;
let latest_historical = self.history_by_block_hash_ref(anchor_hash)?;
let in_memory = state.chain().map(|block_state| block_state.block()).collect();
@ -423,7 +425,7 @@ impl<N: ProviderNodeTypes> ConsistentProvider<N> {
&DatabaseProviderRO<N::DB, N>,
RangeInclusive<TxNumber>,
) -> ProviderResult<Vec<R>>,
M: Fn(RangeInclusive<usize>, &BlockState) -> ProviderResult<Vec<R>>,
M: Fn(RangeInclusive<usize>, &BlockState<N::Primitives>) -> ProviderResult<Vec<R>>,
{
let in_mem_chain = self.head_block.iter().flat_map(|b| b.chain()).collect::<Vec<_>>();
let provider = &self.storage_provider;
@ -445,7 +447,7 @@ impl<N: ProviderNodeTypes> ConsistentProvider<N> {
let (start, end) = self.convert_range_bounds(range, || {
in_mem_chain
.iter()
.map(|b| b.block_ref().block().body.transactions.len() as u64)
.map(|b| b.block_ref().block().body.transactions().len() as u64)
.sum::<u64>() +
last_block_body_index.last_tx_num()
});
@ -477,7 +479,7 @@ impl<N: ProviderNodeTypes> ConsistentProvider<N> {
// Iterate from the lowest block to the highest in-memory chain
for block_state in in_mem_chain.iter().rev() {
let block_tx_count = block_state.block_ref().block().body.transactions.len();
let block_tx_count = block_state.block_ref().block().body.transactions().len();
let remaining = (tx_range.end() - tx_range.start() + 1) as usize;
// If the transaction range start is equal or higher than the next block first
@ -519,7 +521,7 @@ impl<N: ProviderNodeTypes> ConsistentProvider<N> {
) -> ProviderResult<Option<R>>
where
S: FnOnce(&DatabaseProviderRO<N::DB, N>) -> ProviderResult<Option<R>>,
M: Fn(usize, TxNumber, &BlockState) -> ProviderResult<Option<R>>,
M: Fn(usize, TxNumber, &BlockState<N::Primitives>) -> ProviderResult<Option<R>>,
{
let in_mem_chain = self.head_block.iter().flat_map(|b| b.chain()).collect::<Vec<_>>();
let provider = &self.storage_provider;
@ -551,10 +553,10 @@ impl<N: ProviderNodeTypes> ConsistentProvider<N> {
let executed_block = block_state.block_ref();
let block = executed_block.block();
for tx_index in 0..block.body.transactions.len() {
for tx_index in 0..block.body.transactions().len() {
match id {
HashOrNumber::Hash(tx_hash) => {
if tx_hash == block.body.transactions[tx_index].hash() {
if tx_hash == block.body.transactions()[tx_index].trie_hash() {
return fetch_from_block_state(tx_index, in_memory_tx_num, block_state)
}
}
@ -586,7 +588,7 @@ impl<N: ProviderNodeTypes> ConsistentProvider<N> {
) -> ProviderResult<R>
where
S: FnOnce(&DatabaseProviderRO<N::DB, N>) -> ProviderResult<R>,
M: Fn(&BlockState) -> ProviderResult<R>,
M: Fn(&BlockState<N::Primitives>) -> ProviderResult<R>,
{
if let Some(Some(block_state)) = self.head_block.as_ref().map(|b| b.block_on_chain(id)) {
return fetch_from_block_state(block_state)
@ -839,7 +841,7 @@ impl<N: ProviderNodeTypes> BlockReader for ConsistentProvider<N> {
return Ok(Some(Vec::new()))
}
Ok(Some(block_state.block_ref().block().body.ommers.clone()))
Ok(block_state.block_ref().block().body.ommers().map(|o| o.to_vec()))
},
)
}
@ -865,7 +867,7 @@ impl<N: ProviderNodeTypes> BlockReader for ConsistentProvider<N> {
// Iterate from the lowest block in memory until our target block
for state in block_state.chain().collect::<Vec<_>>().into_iter().rev() {
let block_tx_count = state.block_ref().block.body.transactions.len() as u64;
let block_tx_count = state.block_ref().block.body.transactions().len() as u64;
if state.block_ref().block().number == number {
stored_indices.tx_count = block_tx_count;
} else {
@ -962,7 +964,7 @@ impl<N: ProviderNodeTypes> TransactionsProvider for ConsistentProvider<N> {
.block_ref()
.block()
.body
.transactions
.transactions()
.get(tx_index)
.cloned()
.map(Into::into))
@ -982,7 +984,7 @@ impl<N: ProviderNodeTypes> TransactionsProvider for ConsistentProvider<N> {
.block_ref()
.block()
.body
.transactions
.transactions()
.get(tx_index)
.cloned()
.map(Into::into))
@ -1050,11 +1052,7 @@ impl<N: ProviderNodeTypes> TransactionsProvider for ConsistentProvider<N> {
range,
|db_provider, db_range| db_provider.transactions_by_tx_range(db_range),
|index_range, block_state| {
Ok(block_state.block_ref().block().body.transactions[index_range]
.iter()
.cloned()
.map(Into::into)
.collect())
Ok(block_state.block_ref().block().body.transactions()[index_range].to_vec())
},
)
}
@ -1098,12 +1096,13 @@ impl<N: ProviderNodeTypes> ReceiptProvider for ConsistentProvider<N> {
// assuming 1:1 correspondence between transactions and receipts
debug_assert_eq!(
block.body.transactions.len(),
block.body.transactions().len(),
receipts.len(),
"Mismatch between transaction and receipt count"
);
if let Some(tx_index) = block.body.transactions.iter().position(|tx| tx.hash() == hash)
if let Some(tx_index) =
block.body.transactions().iter().position(|tx| tx.trie_hash() == hash)
{
// safe to use tx_index for receipts due to 1:1 correspondence
return Ok(receipts.get(tx_index).cloned());
@ -1181,7 +1180,7 @@ impl<N: ProviderNodeTypes> WithdrawalsProvider for ConsistentProvider<N> {
self.get_in_memory_or_storage_by_block(
id,
|db_provider| db_provider.withdrawals_by_block(id, timestamp),
|block_state| Ok(block_state.block_ref().block().body.withdrawals.clone()),
|block_state| Ok(block_state.block_ref().block().body.withdrawals().cloned()),
)
}
@ -1196,8 +1195,8 @@ impl<N: ProviderNodeTypes> WithdrawalsProvider for ConsistentProvider<N> {
.block_ref()
.block()
.body
.withdrawals
.clone()
.withdrawals()
.cloned()
.and_then(|mut w| w.pop()))
},
)

View File

@ -47,7 +47,7 @@ use reth_execution_types::{Chain, ExecutionOutcome};
use reth_network_p2p::headers::downloader::SyncTarget;
use reth_node_types::{BlockTy, BodyTy, NodeTypes, TxTy};
use reth_primitives::{
Account, Block, BlockExt, BlockWithSenders, Bytecode, GotExpected, Receipt, SealedBlock,
Account, BlockExt, BlockWithSenders, Bytecode, GotExpected, Receipt, SealedBlock,
SealedBlockFor, SealedBlockWithSenders, SealedHeader, StaticFileSegment, StorageEntry,
TransactionMeta, TransactionSignedNoHash,
};
@ -1229,7 +1229,7 @@ impl<TX: DbTx + 'static, N: NodeTypesForProvider> BlockReader for DatabaseProvid
.pop()
.ok_or(ProviderError::InvalidStorageOutput)?;
return Ok(Some(Block { header, body }))
return Ok(Some(Self::Block::new(header, body)))
}
}

View File

@ -21,12 +21,13 @@ use reth_blockchain_tree_api::{
};
use reth_chain_state::{ChainInfoTracker, ForkChoiceNotifications, ForkChoiceSubscriptions};
use reth_chainspec::{ChainInfo, EthereumHardforks};
use reth_db::table::Value;
use reth_db_api::models::{AccountBeforeTx, StoredBlockBodyIndices};
use reth_evm::ConfigureEvmEnv;
use reth_node_types::{BlockTy, FullNodePrimitives, NodeTypes, NodeTypesWithDB, TxTy};
use reth_primitives::{
Account, BlockWithSenders, Receipt, SealedBlock, SealedBlockFor, SealedBlockWithSenders,
SealedHeader, TransactionMeta, TransactionSigned,
Account, BlockWithSenders, EthPrimitives, Receipt, SealedBlock, SealedBlockFor,
SealedBlockWithSenders, SealedHeader, TransactionMeta,
};
use reth_prune_types::{PruneCheckpoint, PruneSegment};
use reth_stages_types::{StageCheckpoint, StageId};
@ -77,10 +78,8 @@ where
ChainSpec: EthereumHardforks,
Storage: ChainStorage<Self::Primitives>,
Primitives: FullNodePrimitives<
SignedTx = TransactionSigned,
SignedTx: Value,
BlockHeader = alloy_consensus::Header,
BlockBody = reth_primitives::BlockBody,
Block = reth_primitives::Block,
Receipt = reth_primitives::Receipt,
>,
>,
@ -92,10 +91,8 @@ impl<T> NodeTypesForProvider for T where
ChainSpec: EthereumHardforks,
Storage: ChainStorage<T::Primitives>,
Primitives: FullNodePrimitives<
SignedTx = TransactionSigned,
SignedTx: Value,
BlockHeader = alloy_consensus::Header,
BlockBody = reth_primitives::BlockBody,
Block = reth_primitives::Block,
Receipt = reth_primitives::Receipt,
>,
>
@ -108,9 +105,18 @@ where
Self: NodeTypesForProvider + NodeTypesWithDB,
{
}
impl<T> ProviderNodeTypes for T where T: NodeTypesForProvider + NodeTypesWithDB {}
/// A helper trait with requirements for [`NodeTypesForProvider`] to be used within legacy
/// blockchain tree.
pub trait NodeTypesForTree: NodeTypesForProvider<Primitives = EthPrimitives> {}
impl<T> NodeTypesForTree for T where T: NodeTypesForProvider<Primitives = EthPrimitives> {}
/// Helper trait with requirements for [`ProviderNodeTypes`] to be used within legacy blockchain
/// tree.
pub trait TreeNodeTypes: ProviderNodeTypes + NodeTypesForTree {}
impl<T> TreeNodeTypes for T where T: ProviderNodeTypes + NodeTypesForTree {}
/// The main type for interacting with the blockchain.
///
/// This type serves as the main entry point for interacting with the blockchain and provides data
@ -342,7 +348,7 @@ impl<N: ProviderNodeTypes> BlockIdReader for BlockchainProvider<N> {
}
}
impl<N: ProviderNodeTypes> BlockReader for BlockchainProvider<N> {
impl<N: TreeNodeTypes> BlockReader for BlockchainProvider<N> {
type Block = BlockTy<N>;
fn find_block_by_hash(