mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: ChainStorageReader (#12836)
This commit is contained in:
@ -57,13 +57,13 @@ revm.workspace = true
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
test-utils = [
|
test-utils = [
|
||||||
"alloy-signer",
|
"alloy-signer",
|
||||||
"alloy-signer-local",
|
"alloy-signer-local",
|
||||||
"rand",
|
"rand",
|
||||||
"revm",
|
"revm",
|
||||||
"reth-chainspec/test-utils",
|
"reth-chainspec/test-utils",
|
||||||
"reth-primitives/test-utils",
|
"reth-primitives/test-utils",
|
||||||
"reth-trie/test-utils",
|
"reth-primitives-traits/test-utils",
|
||||||
"revm?/test-utils",
|
"reth-trie/test-utils",
|
||||||
"reth-primitives-traits/test-utils"
|
"revm?/test-utils",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -15,6 +15,7 @@ use reth_primitives::{
|
|||||||
BlockWithSenders, NodePrimitives, Receipts, SealedBlock, SealedBlockWithSenders, SealedHeader,
|
BlockWithSenders, NodePrimitives, Receipts, SealedBlock, SealedBlockWithSenders, SealedHeader,
|
||||||
TransactionMeta, TransactionSigned,
|
TransactionMeta, TransactionSigned,
|
||||||
};
|
};
|
||||||
|
use reth_primitives_traits::BlockBody as _;
|
||||||
use reth_storage_api::StateProviderBox;
|
use reth_storage_api::StateProviderBox;
|
||||||
use reth_trie::{updates::TrieUpdates, HashedPostState};
|
use reth_trie::{updates::TrieUpdates, HashedPostState};
|
||||||
use std::{collections::BTreeMap, sync::Arc, time::Instant};
|
use std::{collections::BTreeMap, sync::Arc, time::Instant};
|
||||||
@ -547,8 +548,13 @@ where
|
|||||||
/// Returns a `TransactionSigned` for the given `TxHash` if found.
|
/// Returns a `TransactionSigned` for the given `TxHash` if found.
|
||||||
pub fn transaction_by_hash(&self, hash: TxHash) -> Option<TransactionSigned> {
|
pub fn transaction_by_hash(&self, hash: TxHash) -> Option<TransactionSigned> {
|
||||||
for block_state in self.canonical_chain() {
|
for block_state in self.canonical_chain() {
|
||||||
if let Some(tx) =
|
if let Some(tx) = block_state
|
||||||
block_state.block_ref().block().body.transactions().find(|tx| tx.hash() == hash)
|
.block_ref()
|
||||||
|
.block()
|
||||||
|
.body
|
||||||
|
.transactions()
|
||||||
|
.iter()
|
||||||
|
.find(|tx| tx.hash() == hash)
|
||||||
{
|
{
|
||||||
return Some(tx.clone())
|
return Some(tx.clone())
|
||||||
}
|
}
|
||||||
@ -568,6 +574,7 @@ where
|
|||||||
.block()
|
.block()
|
||||||
.body
|
.body
|
||||||
.transactions()
|
.transactions()
|
||||||
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|(_, tx)| tx.hash() == tx_hash)
|
.find(|(_, tx)| tx.hash() == tx_hash)
|
||||||
{
|
{
|
||||||
@ -748,6 +755,7 @@ impl<N: NodePrimitives> BlockState<N> {
|
|||||||
.block()
|
.block()
|
||||||
.body
|
.body
|
||||||
.transactions()
|
.transactions()
|
||||||
|
.iter()
|
||||||
.find(|tx| tx.hash() == hash)
|
.find(|tx| tx.hash() == hash)
|
||||||
.cloned()
|
.cloned()
|
||||||
})
|
})
|
||||||
@ -764,6 +772,7 @@ impl<N: NodePrimitives> BlockState<N> {
|
|||||||
.block()
|
.block()
|
||||||
.body
|
.body
|
||||||
.transactions()
|
.transactions()
|
||||||
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|(_, tx)| tx.hash() == tx_hash)
|
.find(|(_, tx)| tx.hash() == tx_hash)
|
||||||
.map(|(index, tx)| {
|
.map(|(index, tx)| {
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use alloy_consensus::Header;
|
use alloy_consensus::Header;
|
||||||
use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig};
|
use reth_basic_payload_builder::{BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig};
|
||||||
use reth_chainspec::{EthChainSpec, Hardforks};
|
use reth_chainspec::{EthChainSpec, EthereumHardforks, Hardforks};
|
||||||
use reth_db::transaction::{DbTx, DbTxMut};
|
use reth_db::transaction::{DbTx, DbTxMut};
|
||||||
use reth_evm::{execute::BasicBlockExecutorProvider, ConfigureEvm};
|
use reth_evm::{execute::BasicBlockExecutorProvider, ConfigureEvm};
|
||||||
use reth_network::{NetworkConfig, NetworkHandle, NetworkManager, PeersInfo};
|
use reth_network::{NetworkConfig, NetworkHandle, NetworkManager, PeersInfo};
|
||||||
@ -32,8 +32,8 @@ use reth_optimism_rpc::{
|
|||||||
use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService};
|
use reth_payload_builder::{PayloadBuilderHandle, PayloadBuilderService};
|
||||||
use reth_primitives::BlockBody;
|
use reth_primitives::BlockBody;
|
||||||
use reth_provider::{
|
use reth_provider::{
|
||||||
providers::ChainStorage, BlockBodyWriter, CanonStateSubscriptions, DBProvider, EthStorage,
|
providers::ChainStorage, BlockBodyReader, BlockBodyWriter, CanonStateSubscriptions,
|
||||||
ProviderResult,
|
ChainSpecProvider, DBProvider, EthStorage, ProviderResult, ReadBodyInput,
|
||||||
};
|
};
|
||||||
use reth_rpc_server_types::RethRpcModule;
|
use reth_rpc_server_types::RethRpcModule;
|
||||||
use reth_tracing::tracing::{debug, info};
|
use reth_tracing::tracing::{debug, info};
|
||||||
@ -72,7 +72,31 @@ impl<Provider: DBProvider<Tx: DbTxMut>> BlockBodyWriter<Provider, BlockBody> for
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Provider: DBProvider + ChainSpecProvider<ChainSpec: EthereumHardforks>>
|
||||||
|
BlockBodyReader<Provider> for OpStorage
|
||||||
|
{
|
||||||
|
type Block = reth_primitives::Block;
|
||||||
|
|
||||||
|
fn read_block_bodies(
|
||||||
|
&self,
|
||||||
|
provider: &Provider,
|
||||||
|
inputs: Vec<ReadBodyInput<'_, Self::Block>>,
|
||||||
|
) -> ProviderResult<Vec<BlockBody>> {
|
||||||
|
self.0.read_block_bodies(provider, inputs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ChainStorage<OpPrimitives> for OpStorage {
|
impl ChainStorage<OpPrimitives> for OpStorage {
|
||||||
|
fn reader<TX, Types>(
|
||||||
|
&self,
|
||||||
|
) -> impl reth_provider::ChainStorageReader<reth_provider::DatabaseProvider<TX, Types>, OpPrimitives>
|
||||||
|
where
|
||||||
|
TX: DbTx + 'static,
|
||||||
|
Types: reth_provider::providers::NodeTypesForProvider<Primitives = OpPrimitives>,
|
||||||
|
{
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn writer<TX, Types>(
|
fn writer<TX, Types>(
|
||||||
&self,
|
&self,
|
||||||
) -> impl reth_provider::ChainStorageWriter<reth_provider::DatabaseProvider<TX, Types>, OpPrimitives>
|
) -> impl reth_provider::ChainStorageWriter<reth_provider::DatabaseProvider<TX, Types>, OpPrimitives>
|
||||||
@ -83,6 +107,7 @@ impl ChainStorage<OpPrimitives> for OpStorage {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type configuration for a regular Optimism node.
|
/// Type configuration for a regular Optimism node.
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
|
|||||||
@ -661,12 +661,6 @@ impl BlockBody {
|
|||||||
pub fn blob_versioned_hashes(&self) -> Vec<&B256> {
|
pub fn blob_versioned_hashes(&self) -> Vec<&B256> {
|
||||||
self.blob_versioned_hashes_iter().collect()
|
self.blob_versioned_hashes_iter().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over all transactions.
|
|
||||||
#[inline]
|
|
||||||
pub fn transactions(&self) -> impl Iterator<Item = &TransactionSigned> + '_ {
|
|
||||||
self.transactions.iter()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InMemorySize for BlockBody {
|
impl InMemorySize for BlockBody {
|
||||||
|
|||||||
@ -148,6 +148,7 @@ impl PruneInput {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use alloy_primitives::B256;
|
use alloy_primitives::B256;
|
||||||
|
use reth_primitives_traits::BlockBody;
|
||||||
use reth_provider::{
|
use reth_provider::{
|
||||||
providers::BlockchainProvider2,
|
providers::BlockchainProvider2,
|
||||||
test_utils::{create_test_provider_factory, MockEthProvider},
|
test_utils::{create_test_provider_factory, MockEthProvider},
|
||||||
@ -245,7 +246,7 @@ mod tests {
|
|||||||
|
|
||||||
// Calculate the total number of transactions
|
// Calculate the total number of transactions
|
||||||
let num_txs =
|
let num_txs =
|
||||||
blocks.iter().map(|block| block.body.transactions().count() as u64).sum::<u64>();
|
blocks.iter().map(|block| block.body.transactions().len() as u64).sum::<u64>();
|
||||||
|
|
||||||
assert_eq!(range, 0..=num_txs - 1);
|
assert_eq!(range, 0..=num_txs - 1);
|
||||||
}
|
}
|
||||||
@ -292,7 +293,7 @@ mod tests {
|
|||||||
|
|
||||||
// Calculate the total number of transactions
|
// Calculate the total number of transactions
|
||||||
let num_txs =
|
let num_txs =
|
||||||
blocks.iter().map(|block| block.body.transactions().count() as u64).sum::<u64>();
|
blocks.iter().map(|block| block.body.transactions().len() as u64).sum::<u64>();
|
||||||
|
|
||||||
assert_eq!(range, 0..=num_txs - 1,);
|
assert_eq!(range, 0..=num_txs - 1,);
|
||||||
}
|
}
|
||||||
@ -327,7 +328,7 @@ mod tests {
|
|||||||
// Get the last tx number
|
// Get the last tx number
|
||||||
// Calculate the total number of transactions
|
// Calculate the total number of transactions
|
||||||
let num_txs =
|
let num_txs =
|
||||||
blocks.iter().map(|block| block.body.transactions().count() as u64).sum::<u64>();
|
blocks.iter().map(|block| block.body.transactions().len() as u64).sum::<u64>();
|
||||||
let max_range = num_txs - 1;
|
let max_range = num_txs - 1;
|
||||||
|
|
||||||
// Create a prune input with a previous checkpoint that is the last tx number
|
// Create a prune input with a previous checkpoint that is the last tx number
|
||||||
|
|||||||
@ -133,6 +133,8 @@ pub enum ProviderError {
|
|||||||
StorageLockError(StorageLockError),
|
StorageLockError(StorageLockError),
|
||||||
/// Storage writer error.
|
/// Storage writer error.
|
||||||
UnifiedStorageWriterError(UnifiedStorageWriterError),
|
UnifiedStorageWriterError(UnifiedStorageWriterError),
|
||||||
|
/// Received invalid output from configured storage implementation.
|
||||||
|
InvalidStorageOutput,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<DatabaseError> for ProviderError {
|
impl From<DatabaseError> for ProviderError {
|
||||||
|
|||||||
@ -30,6 +30,7 @@ use reth_primitives::{
|
|||||||
Account, Block, BlockWithSenders, Receipt, SealedBlock, SealedBlockWithSenders, SealedHeader,
|
Account, Block, BlockWithSenders, Receipt, SealedBlock, SealedBlockWithSenders, SealedHeader,
|
||||||
StorageEntry, TransactionMeta, TransactionSigned, TransactionSignedNoHash,
|
StorageEntry, TransactionMeta, TransactionSigned, TransactionSignedNoHash,
|
||||||
};
|
};
|
||||||
|
use reth_primitives_traits::BlockBody as _;
|
||||||
use reth_prune_types::{PruneCheckpoint, PruneSegment};
|
use reth_prune_types::{PruneCheckpoint, PruneSegment};
|
||||||
use reth_stages_types::{StageCheckpoint, StageId};
|
use reth_stages_types::{StageCheckpoint, StageId};
|
||||||
use reth_storage_api::{DBProvider, StorageChangeSetReader};
|
use reth_storage_api::{DBProvider, StorageChangeSetReader};
|
||||||
@ -796,6 +797,7 @@ mod tests {
|
|||||||
use reth_primitives::{
|
use reth_primitives::{
|
||||||
BlockExt, Receipt, SealedBlock, StaticFileSegment, TransactionSignedNoHash,
|
BlockExt, Receipt, SealedBlock, StaticFileSegment, TransactionSignedNoHash,
|
||||||
};
|
};
|
||||||
|
use reth_primitives_traits::BlockBody as _;
|
||||||
use reth_storage_api::{
|
use reth_storage_api::{
|
||||||
BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt, BlockSource,
|
BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt, BlockSource,
|
||||||
ChangeSetReader, DatabaseProviderFactory, HeaderProvider, ReceiptProvider,
|
ChangeSetReader, DatabaseProviderFactory, HeaderProvider, ReceiptProvider,
|
||||||
|
|||||||
@ -977,7 +977,7 @@ impl<N: ProviderNodeTypes> TransactionsProvider for ConsistentProvider<N> {
|
|||||||
|
|
||||||
fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Transaction>> {
|
fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Transaction>> {
|
||||||
if let Some(tx) = self.head_block.as_ref().and_then(|b| b.transaction_on_chain(hash)) {
|
if let Some(tx) = self.head_block.as_ref().and_then(|b| b.transaction_on_chain(hash)) {
|
||||||
return Ok(Some(tx.into()))
|
return Ok(Some(tx))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.storage_provider.transaction_by_hash(hash)
|
self.storage_provider.transaction_by_hash(hash)
|
||||||
@ -990,7 +990,7 @@ impl<N: ProviderNodeTypes> TransactionsProvider for ConsistentProvider<N> {
|
|||||||
if let Some((tx, meta)) =
|
if let Some((tx, meta)) =
|
||||||
self.head_block.as_ref().and_then(|b| b.transaction_meta_on_chain(tx_hash))
|
self.head_block.as_ref().and_then(|b| b.transaction_meta_on_chain(tx_hash))
|
||||||
{
|
{
|
||||||
return Ok(Some((tx.into(), meta)))
|
return Ok(Some((tx, meta)))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.storage_provider.transaction_by_hash_with_meta(tx_hash)
|
self.storage_provider.transaction_by_hash_with_meta(tx_hash)
|
||||||
@ -1011,18 +1011,7 @@ impl<N: ProviderNodeTypes> TransactionsProvider for ConsistentProvider<N> {
|
|||||||
self.get_in_memory_or_storage_by_block(
|
self.get_in_memory_or_storage_by_block(
|
||||||
id,
|
id,
|
||||||
|provider| provider.transactions_by_block(id),
|
|provider| provider.transactions_by_block(id),
|
||||||
|block_state| {
|
|block_state| Ok(Some(block_state.block_ref().block().body.transactions.clone())),
|
||||||
Ok(Some(
|
|
||||||
block_state
|
|
||||||
.block_ref()
|
|
||||||
.block()
|
|
||||||
.body
|
|
||||||
.transactions
|
|
||||||
.iter()
|
|
||||||
.map(|tx| tx.clone().into())
|
|
||||||
.collect(),
|
|
||||||
))
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1033,18 +1022,7 @@ impl<N: ProviderNodeTypes> TransactionsProvider for ConsistentProvider<N> {
|
|||||||
self.get_in_memory_or_storage_by_block_range_while(
|
self.get_in_memory_or_storage_by_block_range_while(
|
||||||
range,
|
range,
|
||||||
|db_provider, range, _| db_provider.transactions_by_block_range(range),
|
|db_provider, range, _| db_provider.transactions_by_block_range(range),
|
||||||
|block_state, _| {
|
|block_state, _| Some(block_state.block_ref().block().body.transactions.clone()),
|
||||||
Some(
|
|
||||||
block_state
|
|
||||||
.block_ref()
|
|
||||||
.block()
|
|
||||||
.body
|
|
||||||
.transactions
|
|
||||||
.iter()
|
|
||||||
.map(|tx| tx.clone().into())
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
|_| true,
|
|_| true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,25 +1,41 @@
|
|||||||
use crate::{providers::NodeTypes, DatabaseProvider};
|
use crate::{providers::NodeTypesForProvider, DatabaseProvider};
|
||||||
use reth_db::transaction::{DbTx, DbTxMut};
|
use reth_db::transaction::{DbTx, DbTxMut};
|
||||||
use reth_node_types::FullNodePrimitives;
|
use reth_node_types::FullNodePrimitives;
|
||||||
use reth_primitives::EthPrimitives;
|
use reth_primitives::EthPrimitives;
|
||||||
use reth_storage_api::{ChainStorageWriter, EthStorage};
|
use reth_storage_api::{ChainStorageReader, ChainStorageWriter, EthStorage};
|
||||||
|
|
||||||
/// Trait that provides access to implementations of [`ChainStorage`]
|
/// Trait that provides access to implementations of [`ChainStorage`]
|
||||||
pub trait ChainStorage<Primitives: FullNodePrimitives>: Send + Sync {
|
pub trait ChainStorage<Primitives: FullNodePrimitives>: Send + Sync {
|
||||||
|
/// Provides access to the chain reader.
|
||||||
|
fn reader<TX, Types>(&self) -> impl ChainStorageReader<DatabaseProvider<TX, Types>, Primitives>
|
||||||
|
where
|
||||||
|
TX: DbTx + 'static,
|
||||||
|
Types: NodeTypesForProvider<Primitives = Primitives>;
|
||||||
|
|
||||||
/// Provides access to the chain writer.
|
/// Provides access to the chain writer.
|
||||||
fn writer<TX, Types>(&self) -> impl ChainStorageWriter<DatabaseProvider<TX, Types>, Primitives>
|
fn writer<TX, Types>(&self) -> impl ChainStorageWriter<DatabaseProvider<TX, Types>, Primitives>
|
||||||
where
|
where
|
||||||
TX: DbTxMut + DbTx + 'static,
|
TX: DbTxMut + DbTx + 'static,
|
||||||
Types: NodeTypes<Primitives = Primitives>;
|
Types: NodeTypesForProvider<Primitives = Primitives>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChainStorage<EthPrimitives> for EthStorage {
|
impl ChainStorage<EthPrimitives> for EthStorage {
|
||||||
|
fn reader<TX, Types>(
|
||||||
|
&self,
|
||||||
|
) -> impl ChainStorageReader<DatabaseProvider<TX, Types>, EthPrimitives>
|
||||||
|
where
|
||||||
|
TX: DbTx + 'static,
|
||||||
|
Types: NodeTypesForProvider<Primitives = EthPrimitives>,
|
||||||
|
{
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn writer<TX, Types>(
|
fn writer<TX, Types>(
|
||||||
&self,
|
&self,
|
||||||
) -> impl ChainStorageWriter<DatabaseProvider<TX, Types>, EthPrimitives>
|
) -> impl ChainStorageWriter<DatabaseProvider<TX, Types>, EthPrimitives>
|
||||||
where
|
where
|
||||||
TX: DbTxMut + DbTx + 'static,
|
TX: DbTxMut + DbTx + 'static,
|
||||||
Types: NodeTypes<Primitives = EthPrimitives>,
|
Types: NodeTypesForProvider<Primitives = EthPrimitives>,
|
||||||
{
|
{
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,12 +50,14 @@ use reth_node_types::{BlockTy, NodeTypes, TxTy};
|
|||||||
use reth_primitives::{
|
use reth_primitives::{
|
||||||
Account, Block, BlockBody, BlockExt, BlockWithSenders, Bytecode, GotExpected, Receipt,
|
Account, Block, BlockBody, BlockExt, BlockWithSenders, Bytecode, GotExpected, Receipt,
|
||||||
SealedBlock, SealedBlockWithSenders, SealedHeader, StaticFileSegment, StorageEntry,
|
SealedBlock, SealedBlockWithSenders, SealedHeader, StaticFileSegment, StorageEntry,
|
||||||
TransactionMeta, TransactionSigned, TransactionSignedNoHash,
|
TransactionMeta, TransactionSignedNoHash,
|
||||||
};
|
};
|
||||||
use reth_primitives_traits::{BlockBody as _, SignedTransaction};
|
use reth_primitives_traits::{BlockBody as _, SignedTransaction};
|
||||||
use reth_prune_types::{PruneCheckpoint, PruneModes, PruneSegment};
|
use reth_prune_types::{PruneCheckpoint, PruneModes, PruneSegment};
|
||||||
use reth_stages_types::{StageCheckpoint, StageId};
|
use reth_stages_types::{StageCheckpoint, StageId};
|
||||||
use reth_storage_api::{StateProvider, StorageChangeSetReader, TryIntoHistoricalStateProvider};
|
use reth_storage_api::{
|
||||||
|
BlockBodyReader, StateProvider, StorageChangeSetReader, TryIntoHistoricalStateProvider,
|
||||||
|
};
|
||||||
use reth_storage_errors::provider::{ProviderResult, RootMismatch};
|
use reth_storage_errors::provider::{ProviderResult, RootMismatch};
|
||||||
use reth_trie::{
|
use reth_trie::{
|
||||||
prefix_set::{PrefixSet, PrefixSetMut, TriePrefixSets},
|
prefix_set::{PrefixSet, PrefixSetMut, TriePrefixSets},
|
||||||
@ -517,21 +519,11 @@ impl<TX: DbTx + 'static, N: NodeTypesForProvider> DatabaseProvider<TX, N> {
|
|||||||
N::ChainSpec: EthereumHardforks,
|
N::ChainSpec: EthereumHardforks,
|
||||||
H: AsRef<Header>,
|
H: AsRef<Header>,
|
||||||
HF: FnOnce(BlockNumber) -> ProviderResult<Option<H>>,
|
HF: FnOnce(BlockNumber) -> ProviderResult<Option<H>>,
|
||||||
BF: FnOnce(
|
BF: FnOnce(H, BlockBody, Vec<Address>) -> ProviderResult<Option<B>>,
|
||||||
H,
|
|
||||||
Vec<TransactionSigned>,
|
|
||||||
Vec<Address>,
|
|
||||||
Vec<Header>,
|
|
||||||
Option<Withdrawals>,
|
|
||||||
) -> ProviderResult<Option<B>>,
|
|
||||||
{
|
{
|
||||||
let Some(block_number) = self.convert_hash_or_number(id)? else { return Ok(None) };
|
let Some(block_number) = self.convert_hash_or_number(id)? else { return Ok(None) };
|
||||||
let Some(header) = header_by_number(block_number)? else { return Ok(None) };
|
let Some(header) = header_by_number(block_number)? else { return Ok(None) };
|
||||||
|
|
||||||
let ommers = self.ommers(block_number.into())?.unwrap_or_default();
|
|
||||||
let withdrawals =
|
|
||||||
self.withdrawals_by_block(block_number.into(), header.as_ref().timestamp)?;
|
|
||||||
|
|
||||||
// Get the block body
|
// Get the block body
|
||||||
//
|
//
|
||||||
// If the body indices are not found, this means that the transactions either do not exist
|
// If the body indices are not found, this means that the transactions either do not exist
|
||||||
@ -548,9 +540,14 @@ impl<TX: DbTx + 'static, N: NodeTypesForProvider> DatabaseProvider<TX, N> {
|
|||||||
(self.transactions_by_tx_range(tx_range.clone())?, self.senders_by_tx_range(tx_range)?)
|
(self.transactions_by_tx_range(tx_range.clone())?, self.senders_by_tx_range(tx_range)?)
|
||||||
};
|
};
|
||||||
|
|
||||||
let body = transactions.into_iter().map(Into::into).collect();
|
let body = self
|
||||||
|
.storage
|
||||||
|
.reader()
|
||||||
|
.read_block_bodies(self, vec![(header.as_ref(), transactions)])?
|
||||||
|
.pop()
|
||||||
|
.ok_or(ProviderError::InvalidStorageOutput)?;
|
||||||
|
|
||||||
construct_block(header, body, senders, ommers, withdrawals)
|
construct_block(header, body, senders)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a range of blocks from the database.
|
/// Returns a range of blocks from the database.
|
||||||
@ -572,7 +569,7 @@ impl<TX: DbTx + 'static, N: NodeTypesForProvider> DatabaseProvider<TX, N> {
|
|||||||
N::ChainSpec: EthereumHardforks,
|
N::ChainSpec: EthereumHardforks,
|
||||||
H: AsRef<Header>,
|
H: AsRef<Header>,
|
||||||
HF: FnOnce(RangeInclusive<BlockNumber>) -> ProviderResult<Vec<H>>,
|
HF: FnOnce(RangeInclusive<BlockNumber>) -> ProviderResult<Vec<H>>,
|
||||||
F: FnMut(H, Range<TxNumber>, Vec<Header>, Option<Withdrawals>) -> ProviderResult<R>,
|
F: FnMut(H, BlockBody, Range<TxNumber>) -> ProviderResult<R>,
|
||||||
{
|
{
|
||||||
if range.is_empty() {
|
if range.is_empty() {
|
||||||
return Ok(Vec::new())
|
return Ok(Vec::new())
|
||||||
@ -582,50 +579,41 @@ impl<TX: DbTx + 'static, N: NodeTypesForProvider> DatabaseProvider<TX, N> {
|
|||||||
let mut blocks = Vec::with_capacity(len);
|
let mut blocks = Vec::with_capacity(len);
|
||||||
|
|
||||||
let headers = headers_range(range)?;
|
let headers = headers_range(range)?;
|
||||||
let mut ommers_cursor = self.tx.cursor_read::<tables::BlockOmmers>()?;
|
let mut tx_cursor = self.tx.cursor_read::<tables::Transactions<TxTy<N>>>()?;
|
||||||
let mut withdrawals_cursor = self.tx.cursor_read::<tables::BlockWithdrawals>()?;
|
|
||||||
let mut block_body_cursor = self.tx.cursor_read::<tables::BlockBodyIndices>()?;
|
let mut block_body_cursor = self.tx.cursor_read::<tables::BlockBodyIndices>()?;
|
||||||
|
|
||||||
|
let mut present_headers = Vec::new();
|
||||||
for header in headers {
|
for header in headers {
|
||||||
let header_ref = header.as_ref();
|
|
||||||
// If the body indices are not found, this means that the transactions either do
|
// If the body indices are not found, this means that the transactions either do
|
||||||
// not exist in the database yet, or they do exit but are
|
// not exist in the database yet, or they do exit but are
|
||||||
// not indexed. If they exist but are not indexed, we don't
|
// not indexed. If they exist but are not indexed, we don't
|
||||||
// have enough information to return the block anyways, so
|
// have enough information to return the block anyways, so
|
||||||
// we skip the block.
|
// we skip the block.
|
||||||
if let Some((_, block_body_indices)) =
|
if let Some((_, block_body_indices)) =
|
||||||
block_body_cursor.seek_exact(header_ref.number)?
|
block_body_cursor.seek_exact(header.as_ref().number)?
|
||||||
{
|
{
|
||||||
let tx_range = block_body_indices.tx_num_range();
|
let tx_range = block_body_indices.tx_num_range();
|
||||||
|
present_headers.push((header, tx_range));
|
||||||
// If we are past shanghai, then all blocks should have a withdrawal list,
|
|
||||||
// even if empty
|
|
||||||
let withdrawals =
|
|
||||||
if self.chain_spec.is_shanghai_active_at_timestamp(header_ref.timestamp) {
|
|
||||||
withdrawals_cursor
|
|
||||||
.seek_exact(header_ref.number)?
|
|
||||||
.map(|(_, w)| w.withdrawals)
|
|
||||||
.unwrap_or_default()
|
|
||||||
.into()
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let ommers =
|
|
||||||
if self.chain_spec.final_paris_total_difficulty(header_ref.number).is_some() {
|
|
||||||
Vec::new()
|
|
||||||
} else {
|
|
||||||
ommers_cursor
|
|
||||||
.seek_exact(header_ref.number)?
|
|
||||||
.map(|(_, o)| o.ommers)
|
|
||||||
.unwrap_or_default()
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Ok(b) = assemble_block(header, tx_range, ommers, withdrawals) {
|
|
||||||
blocks.push(b);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut inputs = Vec::new();
|
||||||
|
for (header, tx_range) in &present_headers {
|
||||||
|
let transactions = if tx_range.is_empty() {
|
||||||
|
Vec::new()
|
||||||
|
} else {
|
||||||
|
self.transactions_by_tx_range_with_cursor(tx_range.clone(), &mut tx_cursor)?
|
||||||
|
};
|
||||||
|
|
||||||
|
inputs.push((header.as_ref(), transactions));
|
||||||
|
}
|
||||||
|
|
||||||
|
let bodies = self.storage.reader().read_block_bodies(self, inputs)?;
|
||||||
|
|
||||||
|
for ((header, tx_range), body) in present_headers.into_iter().zip(bodies) {
|
||||||
|
blocks.push(assemble_block(header, body, tx_range)?);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(blocks)
|
Ok(blocks)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -649,34 +637,22 @@ impl<TX: DbTx + 'static, N: NodeTypesForProvider> DatabaseProvider<TX, N> {
|
|||||||
N::ChainSpec: EthereumHardforks,
|
N::ChainSpec: EthereumHardforks,
|
||||||
H: AsRef<Header>,
|
H: AsRef<Header>,
|
||||||
HF: Fn(RangeInclusive<BlockNumber>) -> ProviderResult<Vec<H>>,
|
HF: Fn(RangeInclusive<BlockNumber>) -> ProviderResult<Vec<H>>,
|
||||||
BF: Fn(
|
BF: Fn(H, BlockBody, Vec<Address>) -> ProviderResult<B>,
|
||||||
H,
|
|
||||||
Vec<TransactionSigned>,
|
|
||||||
Vec<Header>,
|
|
||||||
Option<Withdrawals>,
|
|
||||||
Vec<Address>,
|
|
||||||
) -> ProviderResult<B>,
|
|
||||||
{
|
{
|
||||||
let mut tx_cursor = self.tx.cursor_read::<tables::Transactions<TxTy<N>>>()?;
|
|
||||||
let mut senders_cursor = self.tx.cursor_read::<tables::TransactionSenders>()?;
|
let mut senders_cursor = self.tx.cursor_read::<tables::TransactionSenders>()?;
|
||||||
|
|
||||||
self.block_range(range, headers_range, |header, tx_range, ommers, withdrawals| {
|
self.block_range(range, headers_range, |header, body, tx_range| {
|
||||||
let (body, senders) = if tx_range.is_empty() {
|
let senders = if tx_range.is_empty() {
|
||||||
(Vec::new(), Vec::new())
|
Vec::new()
|
||||||
} else {
|
} else {
|
||||||
let body = self
|
|
||||||
.transactions_by_tx_range_with_cursor(tx_range.clone(), &mut tx_cursor)?
|
|
||||||
.into_iter()
|
|
||||||
.map(Into::into)
|
|
||||||
.collect::<Vec<TransactionSigned>>();
|
|
||||||
// fetch senders from the senders table
|
// fetch senders from the senders table
|
||||||
let known_senders =
|
let known_senders =
|
||||||
senders_cursor
|
senders_cursor
|
||||||
.walk_range(tx_range.clone())?
|
.walk_range(tx_range.clone())?
|
||||||
.collect::<Result<HashMap<_, _>, _>>()?;
|
.collect::<Result<HashMap<_, _>, _>>()?;
|
||||||
|
|
||||||
let mut senders = Vec::with_capacity(body.len());
|
let mut senders = Vec::with_capacity(body.transactions.len());
|
||||||
for (tx_num, tx) in tx_range.zip(body.iter()) {
|
for (tx_num, tx) in tx_range.zip(body.transactions()) {
|
||||||
match known_senders.get(&tx_num) {
|
match known_senders.get(&tx_num) {
|
||||||
None => {
|
None => {
|
||||||
// recover the sender from the transaction if not found
|
// recover the sender from the transaction if not found
|
||||||
@ -689,10 +665,10 @@ impl<TX: DbTx + 'static, N: NodeTypesForProvider> DatabaseProvider<TX, N> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(body, senders)
|
senders
|
||||||
};
|
};
|
||||||
|
|
||||||
assemble_block(header, body, ommers, withdrawals, senders)
|
assemble_block(header, body, senders)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1230,21 +1206,22 @@ impl<TX: DbTx + 'static, N: NodeTypesForProvider> BlockReader for DatabaseProvid
|
|||||||
fn block(&self, id: BlockHashOrNumber) -> ProviderResult<Option<Block>> {
|
fn block(&self, id: BlockHashOrNumber) -> ProviderResult<Option<Block>> {
|
||||||
if let Some(number) = self.convert_hash_or_number(id)? {
|
if let Some(number) = self.convert_hash_or_number(id)? {
|
||||||
if let Some(header) = self.header_by_number(number)? {
|
if let Some(header) = self.header_by_number(number)? {
|
||||||
let withdrawals = self.withdrawals_by_block(number.into(), header.timestamp)?;
|
|
||||||
let ommers = self.ommers(number.into())?.unwrap_or_default();
|
|
||||||
// If the body indices are not found, this means that the transactions either do not
|
// If the body indices are not found, this means that the transactions either do not
|
||||||
// exist in the database yet, or they do exit but are not indexed.
|
// exist in the database yet, or they do exit but are not indexed.
|
||||||
// If they exist but are not indexed, we don't have enough
|
// If they exist but are not indexed, we don't have enough
|
||||||
// information to return the block anyways, so we return `None`.
|
// information to return the block anyways, so we return `None`.
|
||||||
let transactions = match self.transactions_by_block(number.into())? {
|
let Some(transactions) = self.transactions_by_block(number.into())? else {
|
||||||
Some(transactions) => transactions.into_iter().map(Into::into).collect(),
|
return Ok(None)
|
||||||
None => return Ok(None),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return Ok(Some(Block {
|
let body = self
|
||||||
header,
|
.storage
|
||||||
body: BlockBody { transactions, ommers, withdrawals },
|
.reader()
|
||||||
}))
|
.read_block_bodies(self, vec![(&header, transactions)])?
|
||||||
|
.pop()
|
||||||
|
.ok_or(ProviderError::InvalidStorageOutput)?;
|
||||||
|
|
||||||
|
return Ok(Some(Block { header, body }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1303,8 +1280,8 @@ impl<TX: DbTx + 'static, N: NodeTypesForProvider> BlockReader for DatabaseProvid
|
|||||||
id,
|
id,
|
||||||
transaction_kind,
|
transaction_kind,
|
||||||
|block_number| self.header_by_number(block_number),
|
|block_number| self.header_by_number(block_number),
|
||||||
|header, transactions, senders, ommers, withdrawals| {
|
|header, body, senders| {
|
||||||
Block { header, body: BlockBody { transactions, ommers, withdrawals } }
|
Block { header, body }
|
||||||
// Note: we're using unchecked here because we know the block contains valid txs
|
// Note: we're using unchecked here because we know the block contains valid txs
|
||||||
// wrt to its height and can ignore the s value check so pre
|
// wrt to its height and can ignore the s value check so pre
|
||||||
// EIP-2 txs are allowed
|
// EIP-2 txs are allowed
|
||||||
@ -1324,8 +1301,8 @@ impl<TX: DbTx + 'static, N: NodeTypesForProvider> BlockReader for DatabaseProvid
|
|||||||
id,
|
id,
|
||||||
transaction_kind,
|
transaction_kind,
|
||||||
|block_number| self.sealed_header(block_number),
|
|block_number| self.sealed_header(block_number),
|
||||||
|header, transactions, senders, ommers, withdrawals| {
|
|header, body, senders| {
|
||||||
SealedBlock { header, body: BlockBody { transactions, ommers, withdrawals } }
|
SealedBlock { header, body }
|
||||||
// Note: we're using unchecked here because we know the block contains valid txs
|
// Note: we're using unchecked here because we know the block contains valid txs
|
||||||
// wrt to its height and can ignore the s value check so pre
|
// wrt to its height and can ignore the s value check so pre
|
||||||
// EIP-2 txs are allowed
|
// EIP-2 txs are allowed
|
||||||
@ -1337,21 +1314,10 @@ impl<TX: DbTx + 'static, N: NodeTypesForProvider> BlockReader for DatabaseProvid
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn block_range(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Block>> {
|
fn block_range(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Block>> {
|
||||||
let mut tx_cursor = self.tx.cursor_read::<tables::Transactions<TxTy<N>>>()?;
|
|
||||||
self.block_range(
|
self.block_range(
|
||||||
range,
|
range,
|
||||||
|range| self.headers_range(range),
|
|range| self.headers_range(range),
|
||||||
|header, tx_range, ommers, withdrawals| {
|
|header, body, _| Ok(Block { header, body }),
|
||||||
let transactions = if tx_range.is_empty() {
|
|
||||||
Vec::new()
|
|
||||||
} else {
|
|
||||||
self.transactions_by_tx_range_with_cursor(tx_range, &mut tx_cursor)?
|
|
||||||
.into_iter()
|
|
||||||
.map(Into::into)
|
|
||||||
.collect()
|
|
||||||
};
|
|
||||||
Ok(Block { header, body: BlockBody { transactions, ommers, withdrawals } })
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1362,8 +1328,8 @@ impl<TX: DbTx + 'static, N: NodeTypesForProvider> BlockReader for DatabaseProvid
|
|||||||
self.block_with_senders_range(
|
self.block_with_senders_range(
|
||||||
range,
|
range,
|
||||||
|range| self.headers_range(range),
|
|range| self.headers_range(range),
|
||||||
|header, transactions, ommers, withdrawals, senders| {
|
|header, body, senders| {
|
||||||
Block { header, body: BlockBody { transactions, ommers, withdrawals } }
|
Block { header, body }
|
||||||
.try_with_senders_unchecked(senders)
|
.try_with_senders_unchecked(senders)
|
||||||
.map_err(|_| ProviderError::SenderRecoveryError)
|
.map_err(|_| ProviderError::SenderRecoveryError)
|
||||||
},
|
},
|
||||||
@ -1377,12 +1343,9 @@ impl<TX: DbTx + 'static, N: NodeTypesForProvider> BlockReader for DatabaseProvid
|
|||||||
self.block_with_senders_range(
|
self.block_with_senders_range(
|
||||||
range,
|
range,
|
||||||
|range| self.sealed_headers_range(range),
|
|range| self.sealed_headers_range(range),
|
||||||
|header, transactions, ommers, withdrawals, senders| {
|
|header, body, senders| {
|
||||||
SealedBlockWithSenders::new(
|
SealedBlockWithSenders::new(SealedBlock { header, body }, senders)
|
||||||
SealedBlock { header, body: BlockBody { transactions, ommers, withdrawals } },
|
.ok_or(ProviderError::SenderRecoveryError)
|
||||||
senders,
|
|
||||||
)
|
|
||||||
.ok_or(ProviderError::SenderRecoveryError)
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,6 @@ use reth_blockchain_tree_api::{
|
|||||||
};
|
};
|
||||||
use reth_chain_state::{ChainInfoTracker, ForkChoiceNotifications, ForkChoiceSubscriptions};
|
use reth_chain_state::{ChainInfoTracker, ForkChoiceNotifications, ForkChoiceSubscriptions};
|
||||||
use reth_chainspec::{ChainInfo, EthereumHardforks};
|
use reth_chainspec::{ChainInfo, EthereumHardforks};
|
||||||
use reth_db::table::Value;
|
|
||||||
use reth_db_api::models::{AccountBeforeTx, StoredBlockBodyIndices};
|
use reth_db_api::models::{AccountBeforeTx, StoredBlockBodyIndices};
|
||||||
use reth_evm::ConfigureEvmEnv;
|
use reth_evm::ConfigureEvmEnv;
|
||||||
use reth_node_types::{FullNodePrimitives, NodeTypes, NodeTypesWithDB, TxTy};
|
use reth_node_types::{FullNodePrimitives, NodeTypes, NodeTypesWithDB, TxTy};
|
||||||
@ -77,8 +76,9 @@ where
|
|||||||
ChainSpec: EthereumHardforks,
|
ChainSpec: EthereumHardforks,
|
||||||
Storage: ChainStorage<Self::Primitives>,
|
Storage: ChainStorage<Self::Primitives>,
|
||||||
Primitives: FullNodePrimitives<
|
Primitives: FullNodePrimitives<
|
||||||
SignedTx: Value + From<TransactionSigned> + Into<TransactionSigned>,
|
SignedTx = TransactionSigned,
|
||||||
BlockHeader = alloy_consensus::Header,
|
BlockHeader = alloy_consensus::Header,
|
||||||
|
BlockBody = reth_primitives::BlockBody,
|
||||||
>,
|
>,
|
||||||
>,
|
>,
|
||||||
{
|
{
|
||||||
@ -89,8 +89,9 @@ impl<T> NodeTypesForProvider for T where
|
|||||||
ChainSpec: EthereumHardforks,
|
ChainSpec: EthereumHardforks,
|
||||||
Storage: ChainStorage<T::Primitives>,
|
Storage: ChainStorage<T::Primitives>,
|
||||||
Primitives: FullNodePrimitives<
|
Primitives: FullNodePrimitives<
|
||||||
SignedTx: Value + From<TransactionSigned> + Into<TransactionSigned>,
|
SignedTx = TransactionSigned,
|
||||||
BlockHeader = alloy_consensus::Header,
|
BlockHeader = alloy_consensus::Header,
|
||||||
|
BlockBody = reth_primitives::BlockBody,
|
||||||
>,
|
>,
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
use crate::DBProvider;
|
use crate::DBProvider;
|
||||||
use alloy_primitives::BlockNumber;
|
use alloy_primitives::BlockNumber;
|
||||||
|
use reth_chainspec::{ChainSpecProvider, EthereumHardforks};
|
||||||
use reth_db::{
|
use reth_db::{
|
||||||
cursor::DbCursorRW,
|
cursor::{DbCursorRO, DbCursorRW},
|
||||||
models::{StoredBlockOmmers, StoredBlockWithdrawals},
|
models::{StoredBlockOmmers, StoredBlockWithdrawals},
|
||||||
tables,
|
tables,
|
||||||
transaction::DbTxMut,
|
transaction::{DbTx, DbTxMut},
|
||||||
DbTxUnwindExt,
|
DbTxUnwindExt,
|
||||||
};
|
};
|
||||||
use reth_primitives_traits::{Block, BlockBody, FullNodePrimitives};
|
use reth_primitives_traits::{Block, BlockBody, FullNodePrimitives};
|
||||||
@ -41,6 +42,38 @@ impl<T, Provider, Primitives: FullNodePrimitives> ChainStorageWriter<Provider, P
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Input for reading a block body. Contains a header of block being read and a list of pre-fetched
|
||||||
|
/// transactions.
|
||||||
|
pub type ReadBodyInput<'a, B> =
|
||||||
|
(&'a <B as Block>::Header, Vec<<<B as Block>::Body as BlockBody>::Transaction>);
|
||||||
|
|
||||||
|
/// Trait that implements how block bodies are read from the storage.
|
||||||
|
///
|
||||||
|
/// Note: Within the current abstraction, transactions persistence is handled separately, thus this
|
||||||
|
/// trait is provided with transactions read beforehand and is expected to construct the block body
|
||||||
|
/// from those transactions and additional data read from elsewhere.
|
||||||
|
#[auto_impl::auto_impl(&, Arc)]
|
||||||
|
pub trait BlockBodyReader<Provider> {
|
||||||
|
/// The block type.
|
||||||
|
type Block: Block;
|
||||||
|
|
||||||
|
/// Receives a list of block headers along with block transactions and returns the block bodies.
|
||||||
|
fn read_block_bodies(
|
||||||
|
&self,
|
||||||
|
provider: &Provider,
|
||||||
|
inputs: Vec<ReadBodyInput<'_, Self::Block>>,
|
||||||
|
) -> ProviderResult<Vec<<Self::Block as Block>::Body>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trait that implements how chain-specific types are read from storage.
|
||||||
|
pub trait ChainStorageReader<Provider, Primitives: FullNodePrimitives>:
|
||||||
|
BlockBodyReader<Provider, Block = Primitives::Block>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
impl<T, Provider, Primitives: FullNodePrimitives> ChainStorageReader<Provider, Primitives> for T where
|
||||||
|
T: BlockBodyReader<Provider, Block = Primitives::Block>
|
||||||
|
{
|
||||||
|
}
|
||||||
/// Ethereum storage implementation.
|
/// Ethereum storage implementation.
|
||||||
#[derive(Debug, Default, Clone, Copy)]
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
pub struct EthStorage;
|
pub struct EthStorage;
|
||||||
@ -89,3 +122,47 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Provider> BlockBodyReader<Provider> for EthStorage
|
||||||
|
where
|
||||||
|
Provider: DBProvider + ChainSpecProvider<ChainSpec: EthereumHardforks>,
|
||||||
|
{
|
||||||
|
type Block = reth_primitives::Block;
|
||||||
|
|
||||||
|
fn read_block_bodies(
|
||||||
|
&self,
|
||||||
|
provider: &Provider,
|
||||||
|
inputs: Vec<ReadBodyInput<'_, Self::Block>>,
|
||||||
|
) -> ProviderResult<Vec<<Self::Block as Block>::Body>> {
|
||||||
|
// TODO: Ideally storage should hold its own copy of chain spec
|
||||||
|
let chain_spec = provider.chain_spec();
|
||||||
|
|
||||||
|
let mut ommers_cursor = provider.tx_ref().cursor_read::<tables::BlockOmmers>()?;
|
||||||
|
let mut withdrawals_cursor = provider.tx_ref().cursor_read::<tables::BlockWithdrawals>()?;
|
||||||
|
|
||||||
|
let mut bodies = Vec::with_capacity(inputs.len());
|
||||||
|
|
||||||
|
for (header, transactions) in inputs {
|
||||||
|
// If we are past shanghai, then all blocks should have a withdrawal list,
|
||||||
|
// even if empty
|
||||||
|
let withdrawals = if chain_spec.is_shanghai_active_at_timestamp(header.timestamp) {
|
||||||
|
withdrawals_cursor
|
||||||
|
.seek_exact(header.number)?
|
||||||
|
.map(|(_, w)| w.withdrawals)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.into()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let ommers = if chain_spec.final_paris_total_difficulty(header.number).is_some() {
|
||||||
|
Vec::new()
|
||||||
|
} else {
|
||||||
|
ommers_cursor.seek_exact(header.number)?.map(|(_, o)| o.ommers).unwrap_or_default()
|
||||||
|
};
|
||||||
|
|
||||||
|
bodies.push(reth_primitives::BlockBody { transactions, ommers, withdrawals });
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(bodies)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use alloy_primitives::{BlockNumber, B256};
|
use alloy_primitives::{BlockNumber, B256};
|
||||||
use reth_execution_types::ChainBlocks;
|
use reth_execution_types::ChainBlocks;
|
||||||
|
use reth_primitives_traits::BlockBody as _;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
/// The type that is used to track canonical blob transactions.
|
/// The type that is used to track canonical blob transactions.
|
||||||
@ -42,6 +43,7 @@ impl BlobStoreCanonTracker {
|
|||||||
let iter = block
|
let iter = block
|
||||||
.body
|
.body
|
||||||
.transactions()
|
.transactions()
|
||||||
|
.iter()
|
||||||
.filter(|tx| tx.transaction.is_eip4844())
|
.filter(|tx| tx.transaction.is_eip4844())
|
||||||
.map(|tx| tx.hash());
|
.map(|tx| tx.hash());
|
||||||
(*num, iter)
|
(*num, iter)
|
||||||
|
|||||||
Reference in New Issue
Block a user