mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-10 07:48:19 -05:00
refactor: EmptyBodyStorage block reader logic (#18508)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
6
Cargo.lock
generated
6
Cargo.lock
generated
@@ -9518,14 +9518,8 @@ name = "reth-optimism-storage"
|
||||
version = "1.7.0"
|
||||
dependencies = [
|
||||
"alloy-consensus",
|
||||
"alloy-primitives",
|
||||
"reth-chainspec",
|
||||
"reth-codecs",
|
||||
"reth-db-api",
|
||||
"reth-node-api",
|
||||
"reth-optimism-primitives",
|
||||
"reth-primitives-traits",
|
||||
"reth-provider",
|
||||
"reth-prune-types",
|
||||
"reth-stages-types",
|
||||
"reth-storage-api",
|
||||
|
||||
@@ -12,16 +12,10 @@ workspace = true
|
||||
|
||||
[dependencies]
|
||||
# reth
|
||||
reth-node-api.workspace = true
|
||||
reth-chainspec.workspace = true
|
||||
reth-primitives-traits.workspace = true
|
||||
reth-optimism-primitives = { workspace = true, features = ["serde", "reth-codec"] }
|
||||
reth-storage-api = { workspace = true, features = ["db-api"] }
|
||||
reth-db-api.workspace = true
|
||||
reth-provider.workspace = true
|
||||
|
||||
# ethereum
|
||||
alloy-primitives.workspace = true
|
||||
alloy-consensus.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
@@ -33,11 +27,8 @@ reth-stages-types.workspace = true
|
||||
default = ["std"]
|
||||
std = [
|
||||
"reth-storage-api/std",
|
||||
"alloy-primitives/std",
|
||||
"reth-prune-types/std",
|
||||
"reth-stages-types/std",
|
||||
"alloy-consensus/std",
|
||||
"reth-chainspec/std",
|
||||
"reth-optimism-primitives/std",
|
||||
"reth-primitives-traits/std",
|
||||
]
|
||||
|
||||
@@ -1,111 +1,6 @@
|
||||
use alloc::{vec, vec::Vec};
|
||||
use alloy_consensus::{BlockBody, Header};
|
||||
use alloy_primitives::BlockNumber;
|
||||
use core::marker::PhantomData;
|
||||
use reth_chainspec::{ChainSpecProvider, EthChainSpec, EthereumHardforks};
|
||||
use reth_db_api::transaction::{DbTx, DbTxMut};
|
||||
use reth_node_api::{FullNodePrimitives, FullSignedTx};
|
||||
use alloy_consensus::Header;
|
||||
use reth_optimism_primitives::OpTransactionSigned;
|
||||
use reth_primitives_traits::{Block, FullBlockHeader, SignedTransaction};
|
||||
use reth_provider::{
|
||||
providers::{ChainStorage, NodeTypesForProvider},
|
||||
DatabaseProvider,
|
||||
};
|
||||
use reth_storage_api::{
|
||||
errors::ProviderResult, BlockBodyReader, BlockBodyWriter, ChainStorageReader,
|
||||
ChainStorageWriter, DBProvider, ReadBodyInput, StorageLocation,
|
||||
};
|
||||
use reth_storage_api::EmptyBodyStorage;
|
||||
|
||||
/// Optimism storage implementation.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct OpStorage<T = OpTransactionSigned, H = Header>(PhantomData<(T, H)>);
|
||||
|
||||
impl<T, H> Default for OpStorage<T, H> {
|
||||
fn default() -> Self {
|
||||
Self(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<N, T, H> ChainStorage<N> for OpStorage<T, H>
|
||||
where
|
||||
T: FullSignedTx,
|
||||
H: FullBlockHeader,
|
||||
N: FullNodePrimitives<
|
||||
Block = alloy_consensus::Block<T, H>,
|
||||
BlockHeader = H,
|
||||
BlockBody = alloy_consensus::BlockBody<T, H>,
|
||||
SignedTx = T,
|
||||
>,
|
||||
{
|
||||
fn reader<TX, Types>(&self) -> impl ChainStorageReader<DatabaseProvider<TX, Types>, N>
|
||||
where
|
||||
TX: DbTx + 'static,
|
||||
Types: NodeTypesForProvider<Primitives = N>,
|
||||
{
|
||||
self
|
||||
}
|
||||
|
||||
fn writer<TX, Types>(&self) -> impl ChainStorageWriter<DatabaseProvider<TX, Types>, N>
|
||||
where
|
||||
TX: DbTxMut + DbTx + 'static,
|
||||
Types: NodeTypesForProvider<Primitives = N>,
|
||||
{
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider, T, H> BlockBodyWriter<Provider, alloy_consensus::BlockBody<T, H>> for OpStorage<T, H>
|
||||
where
|
||||
Provider: DBProvider<Tx: DbTxMut>,
|
||||
T: SignedTransaction,
|
||||
H: FullBlockHeader,
|
||||
{
|
||||
fn write_block_bodies(
|
||||
&self,
|
||||
_provider: &Provider,
|
||||
_bodies: Vec<(u64, Option<alloy_consensus::BlockBody<T, H>>)>,
|
||||
_write_to: StorageLocation,
|
||||
) -> ProviderResult<()> {
|
||||
// noop
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn remove_block_bodies_above(
|
||||
&self,
|
||||
_provider: &Provider,
|
||||
_block: BlockNumber,
|
||||
_remove_from: StorageLocation,
|
||||
) -> ProviderResult<()> {
|
||||
// noop
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider, T, H> BlockBodyReader<Provider> for OpStorage<T, H>
|
||||
where
|
||||
Provider: ChainSpecProvider<ChainSpec: EthChainSpec + EthereumHardforks> + DBProvider,
|
||||
T: SignedTransaction,
|
||||
H: FullBlockHeader,
|
||||
{
|
||||
type Block = alloy_consensus::Block<T, H>;
|
||||
|
||||
fn read_block_bodies(
|
||||
&self,
|
||||
provider: &Provider,
|
||||
inputs: Vec<ReadBodyInput<'_, Self::Block>>,
|
||||
) -> ProviderResult<Vec<<Self::Block as Block>::Body>> {
|
||||
let chain_spec = provider.chain_spec();
|
||||
|
||||
Ok(inputs
|
||||
.into_iter()
|
||||
.map(|(header, transactions)| BlockBody {
|
||||
transactions,
|
||||
ommers: vec![],
|
||||
// after shanghai the body should have an empty withdrawals list
|
||||
withdrawals: chain_spec
|
||||
.is_shanghai_active_at_timestamp(header.timestamp())
|
||||
.then(Default::default),
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
pub type OpStorage<T = OpTransactionSigned, H = Header> = EmptyBodyStorage<T, H>;
|
||||
|
||||
@@ -9,67 +9,26 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
mod chain;
|
||||
pub use chain::OpStorage;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use reth_codecs::{test_utils::UnusedBits, validate_bitflag_backwards_compat};
|
||||
use reth_db_api::models::{
|
||||
CompactClientVersion, CompactU256, CompactU64, StoredBlockBodyIndices,
|
||||
StoredBlockWithdrawals,
|
||||
};
|
||||
use reth_primitives_traits::Account;
|
||||
|
||||
use reth_prune_types::{PruneCheckpoint, PruneMode, PruneSegment};
|
||||
use reth_stages_types::{
|
||||
AccountHashingCheckpoint, CheckpointBlockRange, EntitiesCheckpoint, ExecutionCheckpoint,
|
||||
HeadersCheckpoint, IndexHistoryCheckpoint, StageCheckpoint, StageUnitCheckpoint,
|
||||
StorageHashingCheckpoint,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_ensure_backwards_compatibility() {
|
||||
assert_eq!(Account::bitflag_encoded_bytes(), 2);
|
||||
assert_eq!(AccountHashingCheckpoint::bitflag_encoded_bytes(), 1);
|
||||
assert_eq!(CheckpointBlockRange::bitflag_encoded_bytes(), 1);
|
||||
assert_eq!(CompactClientVersion::bitflag_encoded_bytes(), 0);
|
||||
assert_eq!(CompactU256::bitflag_encoded_bytes(), 1);
|
||||
assert_eq!(CompactU64::bitflag_encoded_bytes(), 1);
|
||||
assert_eq!(EntitiesCheckpoint::bitflag_encoded_bytes(), 1);
|
||||
assert_eq!(ExecutionCheckpoint::bitflag_encoded_bytes(), 0);
|
||||
assert_eq!(HeadersCheckpoint::bitflag_encoded_bytes(), 0);
|
||||
assert_eq!(IndexHistoryCheckpoint::bitflag_encoded_bytes(), 0);
|
||||
assert_eq!(PruneCheckpoint::bitflag_encoded_bytes(), 1);
|
||||
assert_eq!(PruneMode::bitflag_encoded_bytes(), 1);
|
||||
assert_eq!(PruneSegment::bitflag_encoded_bytes(), 1);
|
||||
assert_eq!(StageCheckpoint::bitflag_encoded_bytes(), 1);
|
||||
assert_eq!(StageUnitCheckpoint::bitflag_encoded_bytes(), 1);
|
||||
assert_eq!(StoredBlockBodyIndices::bitflag_encoded_bytes(), 1);
|
||||
assert_eq!(StoredBlockWithdrawals::bitflag_encoded_bytes(), 0);
|
||||
assert_eq!(StorageHashingCheckpoint::bitflag_encoded_bytes(), 1);
|
||||
|
||||
// In case of failure, refer to the documentation of the
|
||||
// [`validate_bitflag_backwards_compat`] macro for detailed instructions on handling
|
||||
// it.
|
||||
validate_bitflag_backwards_compat!(Account, UnusedBits::NotZero);
|
||||
validate_bitflag_backwards_compat!(AccountHashingCheckpoint, UnusedBits::NotZero);
|
||||
validate_bitflag_backwards_compat!(CheckpointBlockRange, UnusedBits::Zero);
|
||||
validate_bitflag_backwards_compat!(CompactClientVersion, UnusedBits::Zero);
|
||||
validate_bitflag_backwards_compat!(CompactU256, UnusedBits::NotZero);
|
||||
validate_bitflag_backwards_compat!(CompactU64, UnusedBits::NotZero);
|
||||
validate_bitflag_backwards_compat!(EntitiesCheckpoint, UnusedBits::Zero);
|
||||
validate_bitflag_backwards_compat!(ExecutionCheckpoint, UnusedBits::Zero);
|
||||
validate_bitflag_backwards_compat!(HeadersCheckpoint, UnusedBits::Zero);
|
||||
validate_bitflag_backwards_compat!(IndexHistoryCheckpoint, UnusedBits::Zero);
|
||||
|
||||
validate_bitflag_backwards_compat!(PruneCheckpoint, UnusedBits::NotZero);
|
||||
validate_bitflag_backwards_compat!(PruneMode, UnusedBits::Zero);
|
||||
validate_bitflag_backwards_compat!(PruneSegment, UnusedBits::Zero);
|
||||
validate_bitflag_backwards_compat!(StageCheckpoint, UnusedBits::NotZero);
|
||||
validate_bitflag_backwards_compat!(StageUnitCheckpoint, UnusedBits::Zero);
|
||||
validate_bitflag_backwards_compat!(StoredBlockBodyIndices, UnusedBits::Zero);
|
||||
validate_bitflag_backwards_compat!(StoredBlockWithdrawals, UnusedBits::Zero);
|
||||
validate_bitflag_backwards_compat!(StorageHashingCheckpoint, UnusedBits::NotZero);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use reth_db_api::transaction::{DbTx, DbTxMut};
|
||||
use reth_node_types::FullNodePrimitives;
|
||||
|
||||
use reth_primitives_traits::{FullBlockHeader, FullSignedTx};
|
||||
use reth_storage_api::{ChainStorageReader, ChainStorageWriter, EthStorage};
|
||||
use reth_storage_api::{ChainStorageReader, ChainStorageWriter, EmptyBodyStorage, EthStorage};
|
||||
|
||||
/// Trait that provides access to implementations of [`ChainStorage`]
|
||||
pub trait ChainStorage<Primitives: FullNodePrimitives>: Send + Sync {
|
||||
@@ -47,3 +47,31 @@ where
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<N, T, H> ChainStorage<N> for EmptyBodyStorage<T, H>
|
||||
where
|
||||
T: FullSignedTx,
|
||||
H: FullBlockHeader,
|
||||
N: FullNodePrimitives<
|
||||
Block = alloy_consensus::Block<T, H>,
|
||||
BlockHeader = H,
|
||||
BlockBody = alloy_consensus::BlockBody<T, H>,
|
||||
SignedTx = T,
|
||||
>,
|
||||
{
|
||||
fn reader<TX, Types>(&self) -> impl ChainStorageReader<DatabaseProvider<TX, Types>, N>
|
||||
where
|
||||
TX: DbTx + 'static,
|
||||
Types: NodeTypesForProvider<Primitives = N>,
|
||||
{
|
||||
self
|
||||
}
|
||||
|
||||
fn writer<TX, Types>(&self) -> impl ChainStorageWriter<DatabaseProvider<TX, Types>, N>
|
||||
where
|
||||
TX: DbTxMut + DbTx + 'static,
|
||||
Types: NodeTypesForProvider<Primitives = N>,
|
||||
{
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,6 @@ serde = [
|
||||
"reth-stages-types/serde",
|
||||
"reth-trie-common/serde",
|
||||
"revm-database/serde",
|
||||
"reth-ethereum-primitives/serde",
|
||||
"alloy-eips/serde",
|
||||
"alloy-primitives/serde",
|
||||
"alloy-consensus/serde",
|
||||
@@ -73,7 +72,6 @@ serde = [
|
||||
]
|
||||
|
||||
serde-bincode-compat = [
|
||||
"reth-ethereum-primitives/serde-bincode-compat",
|
||||
"reth-execution-types/serde-bincode-compat",
|
||||
"reth-primitives-traits/serde-bincode-compat",
|
||||
"reth-trie-common/serde-bincode-compat",
|
||||
|
||||
@@ -3,7 +3,7 @@ use alloc::vec::Vec;
|
||||
use alloy_consensus::Header;
|
||||
use alloy_primitives::BlockNumber;
|
||||
use core::marker::PhantomData;
|
||||
use reth_chainspec::{ChainSpecProvider, EthereumHardforks};
|
||||
use reth_chainspec::{ChainSpecProvider, EthChainSpec, EthereumHardforks};
|
||||
use reth_db_api::{
|
||||
cursor::{DbCursorRO, DbCursorRW},
|
||||
models::StoredBlockOmmers,
|
||||
@@ -193,3 +193,75 @@ where
|
||||
Ok(bodies)
|
||||
}
|
||||
}
|
||||
|
||||
/// A noop storage for chains that don’t have custom body storage.
|
||||
///
|
||||
/// This will never read nor write additional body content such as withdrawals or ommers.
|
||||
/// But will respect the optionality of withdrawals if activated and fill them if the corresponding
|
||||
/// hardfork is activated.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct EmptyBodyStorage<T, H>(PhantomData<(T, H)>);
|
||||
|
||||
impl<T, H> Default for EmptyBodyStorage<T, H> {
|
||||
fn default() -> Self {
|
||||
Self(PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider, T, H> BlockBodyWriter<Provider, alloy_consensus::BlockBody<T, H>>
|
||||
for EmptyBodyStorage<T, H>
|
||||
where
|
||||
Provider: DBProvider<Tx: DbTxMut>,
|
||||
T: SignedTransaction,
|
||||
H: FullBlockHeader,
|
||||
{
|
||||
fn write_block_bodies(
|
||||
&self,
|
||||
_provider: &Provider,
|
||||
_bodies: Vec<(u64, Option<alloy_consensus::BlockBody<T, H>>)>,
|
||||
_write_to: StorageLocation,
|
||||
) -> ProviderResult<()> {
|
||||
// noop
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn remove_block_bodies_above(
|
||||
&self,
|
||||
_provider: &Provider,
|
||||
_block: BlockNumber,
|
||||
_remove_from: StorageLocation,
|
||||
) -> ProviderResult<()> {
|
||||
// noop
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Provider, T, H> BlockBodyReader<Provider> for EmptyBodyStorage<T, H>
|
||||
where
|
||||
Provider: ChainSpecProvider<ChainSpec: EthChainSpec + EthereumHardforks> + DBProvider,
|
||||
T: SignedTransaction,
|
||||
H: FullBlockHeader,
|
||||
{
|
||||
type Block = alloy_consensus::Block<T, H>;
|
||||
|
||||
fn read_block_bodies(
|
||||
&self,
|
||||
provider: &Provider,
|
||||
inputs: Vec<ReadBodyInput<'_, Self::Block>>,
|
||||
) -> ProviderResult<Vec<<Self::Block as Block>::Body>> {
|
||||
let chain_spec = provider.chain_spec();
|
||||
|
||||
Ok(inputs
|
||||
.into_iter()
|
||||
.map(|(header, transactions)| {
|
||||
alloy_consensus::BlockBody {
|
||||
transactions,
|
||||
ommers: vec![], // Empty storage never has ommers
|
||||
withdrawals: chain_spec
|
||||
.is_shanghai_active_at_timestamp(header.timestamp())
|
||||
.then(Default::default),
|
||||
}
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user