feat: make StaticFileProvider generic over NodePrimitives (#12565)

This commit is contained in:
Arsenii Kulikov
2024-11-15 14:42:58 +04:00
committed by GitHub
parent cd9da550da
commit 72a52d5ea5
38 changed files with 324 additions and 222 deletions

1
Cargo.lock generated
View File

@ -8140,6 +8140,7 @@ dependencies = [
"reqwest", "reqwest",
"reth-db-api", "reth-db-api",
"reth-metrics", "reth-metrics",
"reth-primitives-traits",
"reth-provider", "reth-provider",
"reth-tasks", "reth-tasks",
"socket2", "socket2",

View File

@ -109,7 +109,7 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> Environmen
&self, &self,
config: &Config, config: &Config,
db: Arc<DatabaseEnv>, db: Arc<DatabaseEnv>,
static_file_provider: StaticFileProvider, static_file_provider: StaticFileProvider<N::Primitives>,
) -> eyre::Result<ProviderFactory<NodeTypesWithDBAdapter<N, Arc<DatabaseEnv>>>> { ) -> eyre::Result<ProviderFactory<NodeTypesWithDBAdapter<N, Arc<DatabaseEnv>>>> {
let has_receipt_pruning = config.prune.as_ref().map_or(false, |a| a.has_receipts_pruning()); let has_receipt_pruning = config.prune.as_ref().map_or(false, |a| a.has_receipts_pruning());
let prune_modes = let prune_modes =

View File

@ -9,7 +9,9 @@ use reth_db::{mdbx, static_file::iter_static_files, DatabaseEnv, TableViewer, Ta
use reth_db_api::database::Database; use reth_db_api::database::Database;
use reth_db_common::DbTool; use reth_db_common::DbTool;
use reth_fs_util as fs; use reth_fs_util as fs;
use reth_node_builder::{NodeTypesWithDB, NodeTypesWithDBAdapter, NodeTypesWithEngine}; use reth_node_builder::{
NodePrimitives, NodeTypesWithDB, NodeTypesWithDBAdapter, NodeTypesWithEngine,
};
use reth_node_core::dirs::{ChainPath, DataDirPath}; use reth_node_core::dirs::{ChainPath, DataDirPath};
use reth_provider::providers::{ProviderNodeTypes, StaticFileProvider}; use reth_provider::providers::{ProviderNodeTypes, StaticFileProvider};
use reth_static_file_types::SegmentRangeInclusive; use reth_static_file_types::SegmentRangeInclusive;
@ -49,7 +51,7 @@ impl Command {
println!("\n"); println!("\n");
} }
let static_files_stats_table = self.static_files_stats_table(data_dir)?; let static_files_stats_table = self.static_files_stats_table::<N::Primitives>(data_dir)?;
println!("{static_files_stats_table}"); println!("{static_files_stats_table}");
println!("\n"); println!("\n");
@ -143,7 +145,7 @@ impl Command {
Ok(table) Ok(table)
} }
fn static_files_stats_table( fn static_files_stats_table<N: NodePrimitives>(
&self, &self,
data_dir: ChainPath<DataDirPath>, data_dir: ChainPath<DataDirPath>,
) -> eyre::Result<ComfyTable> { ) -> eyre::Result<ComfyTable> {
@ -173,7 +175,8 @@ impl Command {
} }
let static_files = iter_static_files(data_dir.static_files())?; let static_files = iter_static_files(data_dir.static_files())?;
let static_file_provider = StaticFileProvider::read_only(data_dir.static_files(), false)?; let static_file_provider =
StaticFileProvider::<N>::read_only(data_dir.static_files(), false)?;
let mut total_data_size = 0; let mut total_data_size = 0;
let mut total_index_size = 0; let mut total_index_size = 0;

View File

@ -97,7 +97,6 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> InitStateC
if last_block_number == 0 { if last_block_number == 0 {
without_evm::setup_without_evm( without_evm::setup_without_evm(
&provider_rw, &provider_rw,
&static_file_provider,
// &header, // &header,
// header_hash, // header_hash,
SealedHeader::new(header, header_hash), SealedHeader::new(header, header_hash),

View File

@ -2,11 +2,13 @@ use alloy_primitives::{BlockNumber, B256, U256};
use alloy_rlp::Decodable; use alloy_rlp::Decodable;
use alloy_consensus::Header; use alloy_consensus::Header;
use reth_node_builder::NodePrimitives;
use reth_primitives::{ use reth_primitives::{
BlockBody, SealedBlock, SealedBlockWithSenders, SealedHeader, StaticFileSegment, BlockBody, SealedBlock, SealedBlockWithSenders, SealedHeader, StaticFileSegment,
}; };
use reth_provider::{ use reth_provider::{
providers::StaticFileProvider, BlockWriter, StageCheckpointWriter, StaticFileWriter, providers::StaticFileProvider, BlockWriter, StageCheckpointWriter, StaticFileProviderFactory,
StaticFileWriter,
}; };
use reth_stages::{StageCheckpoint, StageId}; use reth_stages::{StageCheckpoint, StageId};
@ -27,21 +29,21 @@ pub(crate) fn read_header_from_file(path: PathBuf) -> Result<Header, eyre::Error
/// first valid block. /// first valid block.
pub fn setup_without_evm<Provider>( pub fn setup_without_evm<Provider>(
provider_rw: &Provider, provider_rw: &Provider,
static_file_provider: &StaticFileProvider,
header: SealedHeader, header: SealedHeader,
total_difficulty: U256, total_difficulty: U256,
) -> Result<(), eyre::Error> ) -> Result<(), eyre::Error>
where where
Provider: StageCheckpointWriter + BlockWriter, Provider: StaticFileProviderFactory + StageCheckpointWriter + BlockWriter,
{ {
info!(target: "reth::cli", "Setting up dummy EVM chain before importing state."); info!(target: "reth::cli", "Setting up dummy EVM chain before importing state.");
let static_file_provider = provider_rw.static_file_provider();
// Write EVM dummy data up to `header - 1` block // Write EVM dummy data up to `header - 1` block
append_dummy_chain(static_file_provider, header.number - 1)?; append_dummy_chain(&static_file_provider, header.number - 1)?;
info!(target: "reth::cli", "Appending first valid block."); info!(target: "reth::cli", "Appending first valid block.");
append_first_block(provider_rw, static_file_provider, &header, total_difficulty)?; append_first_block(provider_rw, &header, total_difficulty)?;
for stage in StageId::ALL { for stage in StageId::ALL {
provider_rw.save_stage_checkpoint(stage, StageCheckpoint::new(header.number))?; provider_rw.save_stage_checkpoint(stage, StageCheckpoint::new(header.number))?;
@ -56,17 +58,21 @@ where
/// ///
/// By appending it, static file writer also verifies that all segments are at the same /// By appending it, static file writer also verifies that all segments are at the same
/// height. /// height.
fn append_first_block( fn append_first_block<Provider>(
provider_rw: impl BlockWriter, provider_rw: &Provider,
sf_provider: &StaticFileProvider,
header: &SealedHeader, header: &SealedHeader,
total_difficulty: U256, total_difficulty: U256,
) -> Result<(), eyre::Error> { ) -> Result<(), eyre::Error>
where
Provider: BlockWriter + StaticFileProviderFactory,
{
provider_rw.insert_block( provider_rw.insert_block(
SealedBlockWithSenders::new(SealedBlock::new(header.clone(), BlockBody::default()), vec![]) SealedBlockWithSenders::new(SealedBlock::new(header.clone(), BlockBody::default()), vec![])
.expect("no senders or txes"), .expect("no senders or txes"),
)?; )?;
let sf_provider = provider_rw.static_file_provider();
sf_provider.latest_writer(StaticFileSegment::Headers)?.append_header( sf_provider.latest_writer(StaticFileSegment::Headers)?.append_header(
header, header,
total_difficulty, total_difficulty,
@ -85,8 +91,8 @@ fn append_first_block(
/// * Headers: It will push an empty block. /// * Headers: It will push an empty block.
/// * Transactions: It will not push any tx, only increments the end block range. /// * Transactions: It will not push any tx, only increments the end block range.
/// * Receipts: It will not push any receipt, only increments the end block range. /// * Receipts: It will not push any receipt, only increments the end block range.
fn append_dummy_chain( fn append_dummy_chain<N: NodePrimitives>(
sf_provider: &StaticFileProvider, sf_provider: &StaticFileProvider<N>,
target_height: BlockNumber, target_height: BlockNumber,
) -> Result<(), eyre::Error> { ) -> Result<(), eyre::Error> {
let (tx, rx) = std::sync::mpsc::channel(); let (tx, rx) = std::sync::mpsc::channel();

View File

@ -12,7 +12,9 @@ use reth_db_common::{
}; };
use reth_node_builder::NodeTypesWithEngine; use reth_node_builder::NodeTypesWithEngine;
use reth_node_core::args::StageEnum; use reth_node_core::args::StageEnum;
use reth_provider::{writer::UnifiedStorageWriter, StaticFileProviderFactory}; use reth_provider::{
writer::UnifiedStorageWriter, DatabaseProviderFactory, StaticFileProviderFactory,
};
use reth_prune::PruneSegment; use reth_prune::PruneSegment;
use reth_stages::StageId; use reth_stages::StageId;
use reth_static_file_types::StaticFileSegment; use reth_static_file_types::StaticFileSegment;
@ -33,8 +35,6 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> Command<C>
) -> eyre::Result<()> { ) -> eyre::Result<()> {
let Environment { provider_factory, .. } = self.env.init::<N>(AccessRights::RW)?; let Environment { provider_factory, .. } = self.env.init::<N>(AccessRights::RW)?;
let static_file_provider = provider_factory.static_file_provider();
let tool = DbTool::new(provider_factory)?; let tool = DbTool::new(provider_factory)?;
let static_file_segment = match self.stage { let static_file_segment = match self.stage {
@ -60,7 +60,7 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> Command<C>
} }
} }
let provider_rw = tool.provider_factory.provider_rw()?; let provider_rw = tool.provider_factory.database_provider_rw()?;
let tx = provider_rw.tx_ref(); let tx = provider_rw.tx_ref();
match self.stage { match self.stage {
@ -71,7 +71,7 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> Command<C>
tx.clear::<tables::HeaderNumbers>()?; tx.clear::<tables::HeaderNumbers>()?;
reset_stage_checkpoint(tx, StageId::Headers)?; reset_stage_checkpoint(tx, StageId::Headers)?;
insert_genesis_header(&provider_rw.0, &static_file_provider, &self.env.chain)?; insert_genesis_header(&provider_rw, &self.env.chain)?;
} }
StageEnum::Bodies => { StageEnum::Bodies => {
tx.clear::<tables::BlockBodyIndices>()?; tx.clear::<tables::BlockBodyIndices>()?;
@ -83,7 +83,7 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> Command<C>
tx.clear::<tables::BlockWithdrawals>()?; tx.clear::<tables::BlockWithdrawals>()?;
reset_stage_checkpoint(tx, StageId::Bodies)?; reset_stage_checkpoint(tx, StageId::Bodies)?;
insert_genesis_header(&provider_rw.0, &static_file_provider, &self.env.chain)?; insert_genesis_header(&provider_rw, &self.env.chain)?;
} }
StageEnum::Senders => { StageEnum::Senders => {
tx.clear::<tables::TransactionSenders>()?; tx.clear::<tables::TransactionSenders>()?;
@ -104,7 +104,7 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> Command<C>
reset_stage_checkpoint(tx, StageId::Execution)?; reset_stage_checkpoint(tx, StageId::Execution)?;
let alloc = &self.env.chain.genesis().alloc; let alloc = &self.env.chain.genesis().alloc;
insert_genesis_state(&provider_rw.0, alloc.iter())?; insert_genesis_state(&provider_rw, alloc.iter())?;
} }
StageEnum::AccountHashing => { StageEnum::AccountHashing => {
tx.clear::<tables::HashedAccounts>()?; tx.clear::<tables::HashedAccounts>()?;
@ -142,20 +142,20 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> Command<C>
reset_stage_checkpoint(tx, StageId::IndexAccountHistory)?; reset_stage_checkpoint(tx, StageId::IndexAccountHistory)?;
reset_stage_checkpoint(tx, StageId::IndexStorageHistory)?; reset_stage_checkpoint(tx, StageId::IndexStorageHistory)?;
insert_genesis_history(&provider_rw.0, self.env.chain.genesis().alloc.iter())?; insert_genesis_history(&provider_rw, self.env.chain.genesis().alloc.iter())?;
} }
StageEnum::TxLookup => { StageEnum::TxLookup => {
tx.clear::<tables::TransactionHashNumbers>()?; tx.clear::<tables::TransactionHashNumbers>()?;
reset_prune_checkpoint(tx, PruneSegment::TransactionLookup)?; reset_prune_checkpoint(tx, PruneSegment::TransactionLookup)?;
reset_stage_checkpoint(tx, StageId::TransactionLookup)?; reset_stage_checkpoint(tx, StageId::TransactionLookup)?;
insert_genesis_header(&provider_rw.0, &static_file_provider, &self.env.chain)?; insert_genesis_header(&provider_rw, &self.env.chain)?;
} }
} }
tx.put::<tables::StageCheckpoints>(StageId::Finish.to_string(), Default::default())?; tx.put::<tables::StageCheckpoints>(StageId::Finish.to_string(), Default::default())?;
UnifiedStorageWriter::commit_unwind(provider_rw, static_file_provider)?; UnifiedStorageWriter::commit_unwind(provider_rw)?;
Ok(()) Ok(())
} }

View File

@ -329,10 +329,7 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> Command<C>
} }
if self.commit { if self.commit {
UnifiedStorageWriter::commit_unwind( UnifiedStorageWriter::commit_unwind(provider_rw)?;
provider_rw,
provider_factory.static_file_provider(),
)?;
provider_rw = provider_factory.database_provider_rw()?; provider_rw = provider_factory.database_provider_rw()?;
} }
} }
@ -355,7 +352,7 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> Command<C>
provider_rw.save_stage_checkpoint(exec_stage.id(), checkpoint)?; provider_rw.save_stage_checkpoint(exec_stage.id(), checkpoint)?;
} }
if self.commit { if self.commit {
UnifiedStorageWriter::commit(provider_rw, provider_factory.static_file_provider())?; UnifiedStorageWriter::commit(provider_rw)?;
provider_rw = provider_factory.database_provider_rw()?; provider_rw = provider_factory.database_provider_rw()?;
} }

View File

@ -120,7 +120,7 @@ impl<N: ProviderNodeTypes> PersistenceService<N> {
let new_tip_hash = provider_rw.block_hash(new_tip_num)?; let new_tip_hash = provider_rw.block_hash(new_tip_num)?;
UnifiedStorageWriter::from(&provider_rw, &sf_provider).remove_blocks_above(new_tip_num)?; UnifiedStorageWriter::from(&provider_rw, &sf_provider).remove_blocks_above(new_tip_num)?;
UnifiedStorageWriter::commit_unwind(provider_rw, sf_provider)?; UnifiedStorageWriter::commit_unwind(provider_rw)?;
debug!(target: "engine::persistence", ?new_tip_num, ?new_tip_hash, "Removed blocks from disk"); debug!(target: "engine::persistence", ?new_tip_num, ?new_tip_hash, "Removed blocks from disk");
self.metrics.remove_blocks_above_duration_seconds.record(start_time.elapsed()); self.metrics.remove_blocks_above_duration_seconds.record(start_time.elapsed());
@ -142,7 +142,7 @@ impl<N: ProviderNodeTypes> PersistenceService<N> {
let static_file_provider = self.provider.static_file_provider(); let static_file_provider = self.provider.static_file_provider();
UnifiedStorageWriter::from(&provider_rw, &static_file_provider).save_blocks(&blocks)?; UnifiedStorageWriter::from(&provider_rw, &static_file_provider).save_blocks(&blocks)?;
UnifiedStorageWriter::commit(provider_rw, static_file_provider)?; UnifiedStorageWriter::commit(provider_rw)?;
} }
self.metrics.save_blocks_duration_seconds.record(start_time.elapsed()); self.metrics.save_blocks_duration_seconds.record(start_time.elapsed());
Ok(last_block_hash_num) Ok(last_block_hash_num)

View File

@ -495,7 +495,7 @@ where
} }
/// Returns the static file provider to interact with the static files. /// Returns the static file provider to interact with the static files.
pub fn static_file_provider(&self) -> StaticFileProvider { pub fn static_file_provider(&self) -> StaticFileProvider<T::Primitives> {
self.right().static_file_provider() self.right().static_file_provider()
} }
@ -766,7 +766,7 @@ where
} }
/// Returns the static file provider to interact with the static files. /// Returns the static file provider to interact with the static files.
pub fn static_file_provider(&self) -> StaticFileProvider { pub fn static_file_provider(&self) -> StaticFileProvider<<T::Types as NodeTypes>::Primitives> {
self.provider_factory().static_file_provider() self.provider_factory().static_file_provider()
} }

View File

@ -9,6 +9,7 @@ repository.workspace = true
[dependencies] [dependencies]
reth-db-api.workspace = true reth-db-api.workspace = true
reth-primitives-traits.workspace = true
reth-provider.workspace = true reth-provider.workspace = true
reth-metrics.workspace = true reth-metrics.workspace = true
reth-tasks.workspace = true reth-tasks.workspace = true

View File

@ -1,7 +1,12 @@
use metrics_process::Collector; use metrics_process::Collector;
use reth_db_api::database_metrics::DatabaseMetrics; use reth_db_api::database_metrics::DatabaseMetrics;
use reth_primitives_traits::NodePrimitives;
use reth_provider::providers::StaticFileProvider; use reth_provider::providers::StaticFileProvider;
use std::{fmt, sync::Arc}; use std::{
fmt::{self},
sync::Arc,
};
pub(crate) trait Hook: Fn() + Send + Sync {} pub(crate) trait Hook: Fn() + Send + Sync {}
impl<T: Fn() + Send + Sync> Hook for T {} impl<T: Fn() + Send + Sync> Hook for T {}
@ -22,10 +27,11 @@ pub struct Hooks {
impl Hooks { impl Hooks {
/// Create a new set of hooks /// Create a new set of hooks
pub fn new<Metrics: DatabaseMetrics + 'static + Send + Sync>( pub fn new<Metrics, N>(db: Metrics, static_file_provider: StaticFileProvider<N>) -> Self
db: Metrics, where
static_file_provider: StaticFileProvider, Metrics: DatabaseMetrics + 'static + Send + Sync,
) -> Self { N: NodePrimitives,
{
let hooks: Vec<Box<dyn Hook<Output = ()>>> = vec![ let hooks: Vec<Box<dyn Hook<Output = ()>>> = vec![
Box::new(move || db.report_metrics()), Box::new(move || db.report_metrics()),
Box::new(move || { Box::new(move || {

View File

@ -150,7 +150,7 @@ where
} }
} }
let provider = provider_factory.provider_rw()?; let provider = provider_factory.database_provider_rw()?;
let mut total_decoded_receipts = 0; let mut total_decoded_receipts = 0;
let mut total_receipts = 0; let mut total_receipts = 0;
let mut total_filtered_out_dup_txns = 0; let mut total_filtered_out_dup_txns = 0;
@ -247,7 +247,7 @@ where
provider provider
.save_stage_checkpoint(StageId::Execution, StageCheckpoint::new(highest_block_receipts))?; .save_stage_checkpoint(StageId::Execution, StageCheckpoint::new(highest_block_receipts))?;
UnifiedStorageWriter::commit(provider, static_file_provider)?; UnifiedStorageWriter::commit(provider)?;
Ok(ImportReceiptsResult { total_decoded_receipts, total_filtered_out_dup_txns }) Ok(ImportReceiptsResult { total_decoded_receipts, total_filtered_out_dup_txns })
} }

View File

@ -54,7 +54,6 @@ impl<C: ChainSpecParser<ChainSpec = OpChainSpec>> InitStateCommandOp<C> {
if last_block_number == 0 { if last_block_number == 0 {
reth_cli_commands::init_state::without_evm::setup_without_evm( reth_cli_commands::init_state::without_evm::setup_without_evm(
&provider_rw, &provider_rw,
&static_file_provider,
SealedHeader::new(BEDROCK_HEADER, BEDROCK_HEADER_HASH), SealedHeader::new(BEDROCK_HEADER, BEDROCK_HEADER_HASH),
BEDROCK_HEADER_TTD, BEDROCK_HEADER_TTD,
)?; )?;

View File

@ -3,7 +3,7 @@ use core::fmt;
use crate::{BlockBody, FullBlock, FullReceipt, FullSignedTx, FullTxType}; use crate::{BlockBody, FullBlock, FullReceipt, FullSignedTx, FullTxType};
/// Configures all the primitive types of the node. /// Configures all the primitive types of the node.
pub trait NodePrimitives: Send + Sync + Unpin + Clone + Default + fmt::Debug { pub trait NodePrimitives: Send + Sync + Unpin + Clone + Default + fmt::Debug + 'static {
/// Block primitive. /// Block primitive.
type Block: Send + Sync + Unpin + Clone + Default + fmt::Debug + 'static; type Block: Send + Sync + Unpin + Clone + Default + fmt::Debug + 'static;
/// Signed version of the transaction type. /// Signed version of the transaction type.
@ -22,7 +22,7 @@ impl NodePrimitives for () {
} }
/// Helper trait that sets trait bounds on [`NodePrimitives`]. /// Helper trait that sets trait bounds on [`NodePrimitives`].
pub trait FullNodePrimitives: Send + Sync + Unpin + Clone + Default + fmt::Debug { pub trait FullNodePrimitives: Send + Sync + Unpin + Clone + Default + fmt::Debug + 'static {
/// Block primitive. /// Block primitive.
type Block: FullBlock<Body: BlockBody<Transaction = Self::SignedTx>>; type Block: FullBlock<Body: BlockBody<Transaction = Self::SignedTx>>;
/// Signed version of the transaction type. /// Signed version of the transaction type.

View File

@ -76,8 +76,11 @@ impl PrunerBuilder {
/// Builds a [Pruner] from the current configuration with the given provider factory. /// Builds a [Pruner] from the current configuration with the given provider factory.
pub fn build_with_provider_factory<PF>(self, provider_factory: PF) -> Pruner<PF::ProviderRW, PF> pub fn build_with_provider_factory<PF>(self, provider_factory: PF) -> Pruner<PF::ProviderRW, PF>
where where
PF: DatabaseProviderFactory<ProviderRW: PruneCheckpointWriter + BlockReader> PF: DatabaseProviderFactory<
+ StaticFileProviderFactory, ProviderRW: PruneCheckpointWriter + BlockReader + StaticFileProviderFactory,
> + StaticFileProviderFactory<
Primitives = <PF::ProviderRW as StaticFileProviderFactory>::Primitives,
>,
{ {
let segments = let segments =
SegmentSet::from_components(provider_factory.static_file_provider(), self.segments); SegmentSet::from_components(provider_factory.static_file_provider(), self.segments);
@ -93,10 +96,16 @@ impl PrunerBuilder {
} }
/// Builds a [Pruner] from the current configuration with the given static file provider. /// Builds a [Pruner] from the current configuration with the given static file provider.
pub fn build<Provider>(self, static_file_provider: StaticFileProvider) -> Pruner<Provider, ()> pub fn build<Provider>(
self,
static_file_provider: StaticFileProvider<Provider::Primitives>,
) -> Pruner<Provider, ()>
where where
Provider: Provider: StaticFileProviderFactory
DBProvider<Tx: DbTxMut> + BlockReader + PruneCheckpointWriter + TransactionsProvider, + DBProvider<Tx: DbTxMut>
+ BlockReader
+ PruneCheckpointWriter
+ TransactionsProvider,
{ {
let segments = SegmentSet::<Provider>::from_components(static_file_provider, self.segments); let segments = SegmentSet::<Provider>::from_components(static_file_provider, self.segments);

View File

@ -5,7 +5,7 @@ use crate::segments::{
use reth_db::transaction::DbTxMut; use reth_db::transaction::DbTxMut;
use reth_provider::{ use reth_provider::{
providers::StaticFileProvider, BlockReader, DBProvider, PruneCheckpointWriter, providers::StaticFileProvider, BlockReader, DBProvider, PruneCheckpointWriter,
TransactionsProvider, StaticFileProviderFactory, TransactionsProvider,
}; };
use reth_prune_types::PruneModes; use reth_prune_types::PruneModes;
@ -45,12 +45,16 @@ impl<Provider> SegmentSet<Provider> {
impl<Provider> SegmentSet<Provider> impl<Provider> SegmentSet<Provider>
where where
Provider: DBProvider<Tx: DbTxMut> + TransactionsProvider + PruneCheckpointWriter + BlockReader, Provider: StaticFileProviderFactory
+ DBProvider<Tx: DbTxMut>
+ TransactionsProvider
+ PruneCheckpointWriter
+ BlockReader,
{ {
/// Creates a [`SegmentSet`] from an existing components, such as [`StaticFileProvider`] and /// Creates a [`SegmentSet`] from an existing components, such as [`StaticFileProvider`] and
/// [`PruneModes`]. /// [`PruneModes`].
pub fn from_components( pub fn from_components(
static_file_provider: StaticFileProvider, static_file_provider: StaticFileProvider<Provider::Primitives>,
prune_modes: PruneModes, prune_modes: PruneModes,
) -> Self { ) -> Self {
let PruneModes { let PruneModes {

View File

@ -12,7 +12,7 @@ use reth_db::{
tables, tables,
transaction::DbTxMut, transaction::DbTxMut,
}; };
use reth_provider::{providers::StaticFileProvider, DBProvider}; use reth_provider::{providers::StaticFileProvider, DBProvider, StaticFileProviderFactory};
use reth_prune_types::{ use reth_prune_types::{
PruneLimiter, PruneMode, PruneProgress, PrunePurpose, PruneSegment, SegmentOutput, PruneLimiter, PruneMode, PruneProgress, PrunePurpose, PruneSegment, SegmentOutput,
SegmentOutputCheckpoint, SegmentOutputCheckpoint,
@ -24,17 +24,19 @@ use tracing::trace;
const HEADER_TABLES_TO_PRUNE: usize = 3; const HEADER_TABLES_TO_PRUNE: usize = 3;
#[derive(Debug)] #[derive(Debug)]
pub struct Headers { pub struct Headers<N> {
static_file_provider: StaticFileProvider, static_file_provider: StaticFileProvider<N>,
} }
impl Headers { impl<N> Headers<N> {
pub const fn new(static_file_provider: StaticFileProvider) -> Self { pub const fn new(static_file_provider: StaticFileProvider<N>) -> Self {
Self { static_file_provider } Self { static_file_provider }
} }
} }
impl<Provider: DBProvider<Tx: DbTxMut>> Segment<Provider> for Headers { impl<Provider: StaticFileProviderFactory + DBProvider<Tx: DbTxMut>> Segment<Provider>
for Headers<Provider::Primitives>
{
fn segment(&self) -> PruneSegment { fn segment(&self) -> PruneSegment {
PruneSegment::Headers PruneSegment::Headers
} }

View File

@ -5,25 +5,29 @@ use crate::{
use reth_db::transaction::DbTxMut; use reth_db::transaction::DbTxMut;
use reth_provider::{ use reth_provider::{
errors::provider::ProviderResult, providers::StaticFileProvider, BlockReader, DBProvider, errors::provider::ProviderResult, providers::StaticFileProvider, BlockReader, DBProvider,
PruneCheckpointWriter, TransactionsProvider, PruneCheckpointWriter, StaticFileProviderFactory, TransactionsProvider,
}; };
use reth_prune_types::{PruneCheckpoint, PruneMode, PrunePurpose, PruneSegment, SegmentOutput}; use reth_prune_types::{PruneCheckpoint, PruneMode, PrunePurpose, PruneSegment, SegmentOutput};
use reth_static_file_types::StaticFileSegment; use reth_static_file_types::StaticFileSegment;
#[derive(Debug)] #[derive(Debug)]
pub struct Receipts { pub struct Receipts<N> {
static_file_provider: StaticFileProvider, static_file_provider: StaticFileProvider<N>,
} }
impl Receipts { impl<N> Receipts<N> {
pub const fn new(static_file_provider: StaticFileProvider) -> Self { pub const fn new(static_file_provider: StaticFileProvider<N>) -> Self {
Self { static_file_provider } Self { static_file_provider }
} }
} }
impl<Provider> Segment<Provider> for Receipts impl<Provider> Segment<Provider> for Receipts<Provider::Primitives>
where where
Provider: DBProvider<Tx: DbTxMut> + PruneCheckpointWriter + TransactionsProvider + BlockReader, Provider: StaticFileProviderFactory
+ DBProvider<Tx: DbTxMut>
+ PruneCheckpointWriter
+ TransactionsProvider
+ BlockReader,
{ {
fn segment(&self) -> PruneSegment { fn segment(&self) -> PruneSegment {
PruneSegment::Receipts PruneSegment::Receipts

View File

@ -4,7 +4,10 @@ use crate::{
PrunerError, PrunerError,
}; };
use reth_db::{tables, transaction::DbTxMut}; use reth_db::{tables, transaction::DbTxMut};
use reth_provider::{providers::StaticFileProvider, BlockReader, DBProvider, TransactionsProvider}; use reth_provider::{
providers::StaticFileProvider, BlockReader, DBProvider, StaticFileProviderFactory,
TransactionsProvider,
};
use reth_prune_types::{ use reth_prune_types::{
PruneMode, PruneProgress, PrunePurpose, PruneSegment, SegmentOutput, SegmentOutputCheckpoint, PruneMode, PruneProgress, PrunePurpose, PruneSegment, SegmentOutput, SegmentOutputCheckpoint,
}; };
@ -12,19 +15,20 @@ use reth_static_file_types::StaticFileSegment;
use tracing::trace; use tracing::trace;
#[derive(Debug)] #[derive(Debug)]
pub struct Transactions { pub struct Transactions<N> {
static_file_provider: StaticFileProvider, static_file_provider: StaticFileProvider<N>,
} }
impl Transactions { impl<N> Transactions<N> {
pub const fn new(static_file_provider: StaticFileProvider) -> Self { pub const fn new(static_file_provider: StaticFileProvider<N>) -> Self {
Self { static_file_provider } Self { static_file_provider }
} }
} }
impl<Provider> Segment<Provider> for Transactions impl<Provider> Segment<Provider> for Transactions<Provider::Primitives>
where where
Provider: DBProvider<Tx: DbTxMut> + TransactionsProvider + BlockReader, Provider:
DBProvider<Tx: DbTxMut> + TransactionsProvider + BlockReader + StaticFileProviderFactory,
{ {
fn segment(&self) -> PruneSegment { fn segment(&self) -> PruneSegment {
PruneSegment::Transactions PruneSegment::Transactions

View File

@ -9,7 +9,7 @@ use reth_primitives_traits::constants::BEACON_CONSENSUS_REORG_UNWIND_DEPTH;
use reth_provider::{ use reth_provider::{
providers::ProviderNodeTypes, writer::UnifiedStorageWriter, ChainStateBlockReader, providers::ProviderNodeTypes, writer::UnifiedStorageWriter, ChainStateBlockReader,
ChainStateBlockWriter, DatabaseProviderFactory, ProviderFactory, StageCheckpointReader, ChainStateBlockWriter, DatabaseProviderFactory, ProviderFactory, StageCheckpointReader,
StageCheckpointWriter, StaticFileProviderFactory, StageCheckpointWriter,
}; };
use reth_prune::PrunerBuilder; use reth_prune::PrunerBuilder;
use reth_static_file::StaticFileProducer; use reth_static_file::StaticFileProducer;
@ -358,10 +358,7 @@ impl<N: ProviderNodeTypes> Pipeline<N> {
))?; ))?;
} }
UnifiedStorageWriter::commit_unwind( UnifiedStorageWriter::commit_unwind(provider_rw)?;
provider_rw,
self.provider_factory.static_file_provider(),
)?;
stage.post_unwind_commit()?; stage.post_unwind_commit()?;
@ -469,10 +466,7 @@ impl<N: ProviderNodeTypes> Pipeline<N> {
result: out.clone(), result: out.clone(),
}); });
UnifiedStorageWriter::commit( UnifiedStorageWriter::commit(provider_rw)?;
provider_rw,
self.provider_factory.static_file_provider(),
)?;
stage.post_execute_commit()?; stage.post_execute_commit()?;
@ -533,7 +527,7 @@ fn on_stage_error<N: ProviderNodeTypes>(
prev_checkpoint.unwrap_or_default(), prev_checkpoint.unwrap_or_default(),
)?; )?;
UnifiedStorageWriter::commit(provider_rw, factory.static_file_provider())?; UnifiedStorageWriter::commit(provider_rw)?;
// We unwind because of a validation error. If the unwind itself // We unwind because of a validation error. If the unwind itself
// fails, we bail entirely, // fails, we bail entirely,

View File

@ -311,11 +311,11 @@ where
fn missing_static_data_error<Provider>( fn missing_static_data_error<Provider>(
last_tx_num: TxNumber, last_tx_num: TxNumber,
static_file_provider: &StaticFileProvider, static_file_provider: &StaticFileProvider<Provider::Primitives>,
provider: &Provider, provider: &Provider,
) -> Result<StageError, ProviderError> ) -> Result<StageError, ProviderError>
where where
Provider: BlockReader, Provider: BlockReader + StaticFileProviderFactory,
{ {
let mut last_block = static_file_provider let mut last_block = static_file_provider
.get_highest_static_file_block(StaticFileSegment::Transactions) .get_highest_static_file_block(StaticFileSegment::Transactions)

View File

@ -12,7 +12,7 @@ use reth_evm::{
use reth_execution_types::Chain; use reth_execution_types::Chain;
use reth_exex::{ExExManagerHandle, ExExNotification, ExExNotificationSource}; use reth_exex::{ExExManagerHandle, ExExNotification, ExExNotificationSource};
use reth_primitives::{SealedHeader, StaticFileSegment}; use reth_primitives::{SealedHeader, StaticFileSegment};
use reth_primitives_traits::format_gas_throughput; use reth_primitives_traits::{format_gas_throughput, NodePrimitives};
use reth_provider::{ use reth_provider::{
providers::{StaticFileProvider, StaticFileProviderRWRefMut, StaticFileWriter}, providers::{StaticFileProvider, StaticFileProviderRWRefMut, StaticFileWriter},
writer::UnifiedStorageWriter, writer::UnifiedStorageWriter,
@ -181,7 +181,8 @@ where
+ StatsReader + StatsReader
+ StateChangeWriter + StateChangeWriter
+ BlockHashReader, + BlockHashReader,
for<'a> UnifiedStorageWriter<'a, Provider, StaticFileProviderRWRefMut<'a>>: StateWriter, for<'a> UnifiedStorageWriter<'a, Provider, StaticFileProviderRWRefMut<'a, Provider::Primitives>>:
StateWriter,
{ {
/// Return the id of the stage /// Return the id of the stage
fn id(&self) -> StageId { fn id(&self) -> StageId {
@ -485,8 +486,8 @@ where
} }
} }
fn execution_checkpoint( fn execution_checkpoint<N: NodePrimitives>(
provider: &StaticFileProvider, provider: &StaticFileProvider<N>,
start_block: BlockNumber, start_block: BlockNumber,
max_block: BlockNumber, max_block: BlockNumber,
checkpoint: StageCheckpoint, checkpoint: StageCheckpoint,
@ -552,8 +553,8 @@ fn execution_checkpoint(
}) })
} }
fn calculate_gas_used_from_headers( fn calculate_gas_used_from_headers<N: NodePrimitives>(
provider: &StaticFileProvider, provider: &StaticFileProvider<N>,
range: RangeInclusive<BlockNumber>, range: RangeInclusive<BlockNumber>,
) -> Result<u64, ProviderError> { ) -> Result<u64, ProviderError> {
debug!(target: "sync::stages::execution", ?range, "Calculating gas used from headers"); debug!(target: "sync::stages::execution", ?range, "Calculating gas used from headers");
@ -587,11 +588,11 @@ fn calculate_gas_used_from_headers(
/// (by returning [`StageError`]) until the heights in both the database and static file match. /// (by returning [`StageError`]) until the heights in both the database and static file match.
fn prepare_static_file_producer<'a, 'b, Provider>( fn prepare_static_file_producer<'a, 'b, Provider>(
provider: &'b Provider, provider: &'b Provider,
static_file_provider: &'a StaticFileProvider, static_file_provider: &'a StaticFileProvider<Provider::Primitives>,
start_block: u64, start_block: u64,
) -> Result<StaticFileProviderRWRefMut<'a>, StageError> ) -> Result<StaticFileProviderRWRefMut<'a, Provider::Primitives>, StageError>
where where
Provider: DBProvider + BlockReader + HeaderProvider, Provider: StaticFileProviderFactory + DBProvider + BlockReader + HeaderProvider,
'b: 'a, 'b: 'a,
{ {
// Get next expected receipt number // Get next expected receipt number

View File

@ -296,8 +296,8 @@ mod tests {
) { ) {
// We recreate the static file provider, since consistency heals are done on fetching the // We recreate the static file provider, since consistency heals are done on fetching the
// writer for the first time. // writer for the first time.
let static_file_provider = let mut static_file_provider = db.factory.static_file_provider();
StaticFileProvider::read_write(db.factory.static_file_provider().path()).unwrap(); static_file_provider = StaticFileProvider::read_write(static_file_provider.path()).unwrap();
// Simulate corruption by removing `prune_count` rows from the data file without updating // Simulate corruption by removing `prune_count` rows from the data file without updating
// its offset list and configuration. // its offset list and configuration.
@ -314,9 +314,10 @@ mod tests {
// We recreate the static file provider, since consistency heals are done on fetching the // We recreate the static file provider, since consistency heals are done on fetching the
// writer for the first time. // writer for the first time.
let mut static_file_provider = db.factory.static_file_provider();
static_file_provider = StaticFileProvider::read_write(static_file_provider.path()).unwrap();
assert_eq!( assert_eq!(
StaticFileProvider::read_write(db.factory.static_file_provider().path()) static_file_provider
.unwrap()
.check_consistency(&db.factory.database_provider_ro().unwrap(), is_full_node,), .check_consistency(&db.factory.database_provider_ro().unwrap(), is_full_node,),
Ok(expected) Ok(expected)
); );

View File

@ -24,7 +24,7 @@ use reth_provider::{
}; };
use reth_storage_errors::provider::ProviderResult; use reth_storage_errors::provider::ProviderResult;
use reth_testing_utils::generators::ChangeSet; use reth_testing_utils::generators::ChangeSet;
use std::{collections::BTreeMap, path::Path}; use std::{collections::BTreeMap, fmt::Debug, path::Path};
use tempfile::TempDir; use tempfile::TempDir;
/// Test database that is used for testing stage implementations. /// Test database that is used for testing stage implementations.
@ -142,7 +142,7 @@ impl TestStageDB {
/// Insert header to static file if `writer` exists, otherwise to DB. /// Insert header to static file if `writer` exists, otherwise to DB.
pub fn insert_header<TX: DbTx + DbTxMut>( pub fn insert_header<TX: DbTx + DbTxMut>(
writer: Option<&mut StaticFileProviderRWRefMut<'_>>, writer: Option<&mut StaticFileProviderRWRefMut<'_, ()>>,
tx: &TX, tx: &TX,
header: &SealedHeader, header: &SealedHeader,
td: U256, td: U256,

View File

@ -10,9 +10,7 @@ use reth_db_api::{transaction::DbTxMut, DatabaseError};
use reth_etl::Collector; use reth_etl::Collector;
use reth_primitives::{Account, Bytecode, GotExpected, Receipts, StaticFileSegment, StorageEntry}; use reth_primitives::{Account, Bytecode, GotExpected, Receipts, StaticFileSegment, StorageEntry};
use reth_provider::{ use reth_provider::{
errors::provider::ProviderResult, errors::provider::ProviderResult, providers::StaticFileWriter, writer::UnifiedStorageWriter,
providers::{StaticFileProvider, StaticFileWriter},
writer::UnifiedStorageWriter,
BlockHashReader, BlockNumReader, BundleStateInit, ChainSpecProvider, DBProvider, BlockHashReader, BlockNumReader, BundleStateInit, ChainSpecProvider, DBProvider,
DatabaseProviderFactory, ExecutionOutcome, HashingWriter, HeaderProvider, HistoryWriter, DatabaseProviderFactory, ExecutionOutcome, HashingWriter, HeaderProvider, HistoryWriter,
OriginalValuesKnown, ProviderError, RevertsInit, StageCheckpointWriter, StateChangeWriter, OriginalValuesKnown, ProviderError, RevertsInit, StageCheckpointWriter, StateChangeWriter,
@ -72,7 +70,8 @@ impl From<DatabaseError> for InitDatabaseError {
pub fn init_genesis<PF>(factory: &PF) -> Result<B256, InitDatabaseError> pub fn init_genesis<PF>(factory: &PF) -> Result<B256, InitDatabaseError>
where where
PF: DatabaseProviderFactory + StaticFileProviderFactory + ChainSpecProvider + BlockHashReader, PF: DatabaseProviderFactory + StaticFileProviderFactory + ChainSpecProvider + BlockHashReader,
PF::ProviderRW: StageCheckpointWriter PF::ProviderRW: StaticFileProviderFactory
+ StageCheckpointWriter
+ HistoryWriter + HistoryWriter
+ HeaderProvider + HeaderProvider
+ HashingWriter + HashingWriter
@ -114,8 +113,7 @@ where
insert_genesis_history(&provider_rw, alloc.iter())?; insert_genesis_history(&provider_rw, alloc.iter())?;
// Insert header // Insert header
let static_file_provider = factory.static_file_provider(); insert_genesis_header(&provider_rw, &chain)?;
insert_genesis_header(&provider_rw, &static_file_provider, &chain)?;
insert_genesis_state(&provider_rw, alloc.iter())?; insert_genesis_state(&provider_rw, alloc.iter())?;
@ -124,6 +122,7 @@ where
provider_rw.save_stage_checkpoint(stage, Default::default())?; provider_rw.save_stage_checkpoint(stage, Default::default())?;
} }
let static_file_provider = provider_rw.static_file_provider();
// Static file segments start empty, so we need to initialize the genesis block. // Static file segments start empty, so we need to initialize the genesis block.
let segment = StaticFileSegment::Receipts; let segment = StaticFileSegment::Receipts;
static_file_provider.latest_writer(segment)?.increment_block(0)?; static_file_provider.latest_writer(segment)?.increment_block(0)?;
@ -133,7 +132,7 @@ where
// `commit_unwind`` will first commit the DB and then the static file provider, which is // `commit_unwind`` will first commit the DB and then the static file provider, which is
// necessary on `init_genesis`. // necessary on `init_genesis`.
UnifiedStorageWriter::commit_unwind(provider_rw, static_file_provider)?; UnifiedStorageWriter::commit_unwind(provider_rw)?;
Ok(hash) Ok(hash)
} }
@ -144,7 +143,11 @@ pub fn insert_genesis_state<'a, 'b, Provider>(
alloc: impl Iterator<Item = (&'a Address, &'b GenesisAccount)>, alloc: impl Iterator<Item = (&'a Address, &'b GenesisAccount)>,
) -> ProviderResult<()> ) -> ProviderResult<()>
where where
Provider: DBProvider<Tx: DbTxMut> + StateChangeWriter + HeaderProvider + AsRef<Provider>, Provider: StaticFileProviderFactory
+ DBProvider<Tx: DbTxMut>
+ StateChangeWriter
+ HeaderProvider
+ AsRef<Provider>,
{ {
insert_state(provider, alloc, 0) insert_state(provider, alloc, 0)
} }
@ -156,7 +159,11 @@ pub fn insert_state<'a, 'b, Provider>(
block: u64, block: u64,
) -> ProviderResult<()> ) -> ProviderResult<()>
where where
Provider: DBProvider<Tx: DbTxMut> + StateChangeWriter + HeaderProvider + AsRef<Provider>, Provider: StaticFileProviderFactory
+ DBProvider<Tx: DbTxMut>
+ StateChangeWriter
+ HeaderProvider
+ AsRef<Provider>,
{ {
let capacity = alloc.size_hint().1.unwrap_or(0); let capacity = alloc.size_hint().1.unwrap_or(0);
let mut state_init: BundleStateInit = HashMap::with_capacity(capacity); let mut state_init: BundleStateInit = HashMap::with_capacity(capacity);
@ -296,14 +303,14 @@ where
/// Inserts header for the genesis state. /// Inserts header for the genesis state.
pub fn insert_genesis_header<Provider, Spec>( pub fn insert_genesis_header<Provider, Spec>(
provider: &Provider, provider: &Provider,
static_file_provider: &StaticFileProvider,
chain: &Spec, chain: &Spec,
) -> ProviderResult<()> ) -> ProviderResult<()>
where where
Provider: DBProvider<Tx: DbTxMut>, Provider: StaticFileProviderFactory + DBProvider<Tx: DbTxMut>,
Spec: EthChainSpec, Spec: EthChainSpec,
{ {
let (header, block_hash) = (chain.genesis_header(), chain.genesis_hash()); let (header, block_hash) = (chain.genesis_header(), chain.genesis_hash());
let static_file_provider = provider.static_file_provider();
match static_file_provider.block_hash(0) { match static_file_provider.block_hash(0) {
Ok(None) | Err(ProviderError::MissingStaticFileBlock(StaticFileSegment::Headers, 0)) => { Ok(None) | Err(ProviderError::MissingStaticFileBlock(StaticFileSegment::Headers, 0)) => {
@ -333,7 +340,8 @@ pub fn init_from_state_dump<Provider>(
etl_config: EtlConfig, etl_config: EtlConfig,
) -> eyre::Result<B256> ) -> eyre::Result<B256>
where where
Provider: DBProvider<Tx: DbTxMut> Provider: StaticFileProviderFactory
+ DBProvider<Tx: DbTxMut>
+ BlockNumReader + BlockNumReader
+ BlockHashReader + BlockHashReader
+ ChainSpecProvider + ChainSpecProvider
@ -457,7 +465,8 @@ fn dump_state<Provider>(
block: u64, block: u64,
) -> Result<(), eyre::Error> ) -> Result<(), eyre::Error>
where where
Provider: DBProvider<Tx: DbTxMut> Provider: StaticFileProviderFactory
+ DBProvider<Tx: DbTxMut>
+ HeaderProvider + HeaderProvider
+ HashingWriter + HashingWriter
+ HistoryWriter + HistoryWriter

View File

@ -163,7 +163,9 @@ impl<N: ProviderNodeTypes> DatabaseProviderFactory for BlockchainProvider2<N> {
} }
impl<N: ProviderNodeTypes> StaticFileProviderFactory for BlockchainProvider2<N> { impl<N: ProviderNodeTypes> StaticFileProviderFactory for BlockchainProvider2<N> {
fn static_file_provider(&self) -> StaticFileProvider { type Primitives = N::Primitives;
fn static_file_provider(&self) -> StaticFileProvider<Self::Primitives> {
self.database.static_file_provider() self.database.static_file_provider()
} }
} }
@ -911,7 +913,7 @@ mod tests {
)?; )?;
// Commit to both storages: database and static files // Commit to both storages: database and static files
UnifiedStorageWriter::commit(provider_rw, factory.static_file_provider())?; UnifiedStorageWriter::commit(provider_rw)?;
let provider = BlockchainProvider2::new(factory)?; let provider = BlockchainProvider2::new(factory)?;
@ -999,8 +1001,7 @@ mod tests {
UnifiedStorageWriter::from(&provider_rw, &hook_provider.static_file_provider()) UnifiedStorageWriter::from(&provider_rw, &hook_provider.static_file_provider())
.save_blocks(&[lowest_memory_block]) .save_blocks(&[lowest_memory_block])
.unwrap(); .unwrap();
UnifiedStorageWriter::commit(provider_rw, hook_provider.static_file_provider()) UnifiedStorageWriter::commit(provider_rw).unwrap();
.unwrap();
// Remove from memory // Remove from memory
hook_provider.canonical_in_memory_state.remove_persisted_blocks(num_hash); hook_provider.canonical_in_memory_state.remove_persisted_blocks(num_hash);

View File

@ -612,7 +612,9 @@ impl<N: ProviderNodeTypes> ConsistentProvider<N> {
} }
impl<N: ProviderNodeTypes> StaticFileProviderFactory for ConsistentProvider<N> { impl<N: ProviderNodeTypes> StaticFileProviderFactory for ConsistentProvider<N> {
fn static_file_provider(&self) -> StaticFileProvider { type Primitives = N::Primitives;
fn static_file_provider(&self) -> StaticFileProvider<N::Primitives> {
self.storage_provider.static_file_provider() self.storage_provider.static_file_provider()
} }
} }

View File

@ -53,7 +53,7 @@ pub struct ProviderFactory<N: NodeTypesWithDB> {
/// Chain spec /// Chain spec
chain_spec: Arc<N::ChainSpec>, chain_spec: Arc<N::ChainSpec>,
/// Static File Provider /// Static File Provider
static_file_provider: StaticFileProvider, static_file_provider: StaticFileProvider<N::Primitives>,
/// Optional pruning configuration /// Optional pruning configuration
prune_modes: PruneModes, prune_modes: PruneModes,
} }
@ -78,7 +78,7 @@ impl<N: NodeTypesWithDB> ProviderFactory<N> {
pub fn new( pub fn new(
db: N::DB, db: N::DB,
chain_spec: Arc<N::ChainSpec>, chain_spec: Arc<N::ChainSpec>,
static_file_provider: StaticFileProvider, static_file_provider: StaticFileProvider<N::Primitives>,
) -> Self { ) -> Self {
Self { db, chain_spec, static_file_provider, prune_modes: PruneModes::none() } Self { db, chain_spec, static_file_provider, prune_modes: PruneModes::none() }
} }
@ -114,7 +114,7 @@ impl<N: NodeTypesWithDB<DB = Arc<DatabaseEnv>>> ProviderFactory<N> {
path: P, path: P,
chain_spec: Arc<N::ChainSpec>, chain_spec: Arc<N::ChainSpec>,
args: DatabaseArguments, args: DatabaseArguments,
static_file_provider: StaticFileProvider, static_file_provider: StaticFileProvider<N::Primitives>,
) -> RethResult<Self> { ) -> RethResult<Self> {
Ok(Self { Ok(Self {
db: Arc::new(init_db(path, args).map_err(RethError::msg)?), db: Arc::new(init_db(path, args).map_err(RethError::msg)?),
@ -202,8 +202,10 @@ impl<N: ProviderNodeTypes> DatabaseProviderFactory for ProviderFactory<N> {
} }
impl<N: NodeTypesWithDB> StaticFileProviderFactory for ProviderFactory<N> { impl<N: NodeTypesWithDB> StaticFileProviderFactory for ProviderFactory<N> {
type Primitives = N::Primitives;
/// Returns static file provider /// Returns static file provider
fn static_file_provider(&self) -> StaticFileProvider { fn static_file_provider(&self) -> StaticFileProvider<Self::Primitives> {
self.static_file_provider.clone() self.static_file_provider.clone()
} }
} }

View File

@ -135,7 +135,7 @@ pub struct DatabaseProvider<TX, N: NodeTypes> {
/// Chain spec /// Chain spec
chain_spec: Arc<N::ChainSpec>, chain_spec: Arc<N::ChainSpec>,
/// Static File provider /// Static File provider
static_file_provider: StaticFileProvider, static_file_provider: StaticFileProvider<N::Primitives>,
/// Pruning configuration /// Pruning configuration
prune_modes: PruneModes, prune_modes: PruneModes,
} }
@ -199,8 +199,10 @@ impl<TX: DbTx + 'static, N: NodeTypes> DatabaseProvider<TX, N> {
} }
impl<TX, N: NodeTypes> StaticFileProviderFactory for DatabaseProvider<TX, N> { impl<TX, N: NodeTypes> StaticFileProviderFactory for DatabaseProvider<TX, N> {
type Primitives = N::Primitives;
/// Returns a static file provider /// Returns a static file provider
fn static_file_provider(&self) -> StaticFileProvider { fn static_file_provider(&self) -> StaticFileProvider<Self::Primitives> {
self.static_file_provider.clone() self.static_file_provider.clone()
} }
} }
@ -220,7 +222,7 @@ impl<TX: DbTxMut, N: NodeTypes> DatabaseProvider<TX, N> {
pub const fn new_rw( pub const fn new_rw(
tx: TX, tx: TX,
chain_spec: Arc<N::ChainSpec>, chain_spec: Arc<N::ChainSpec>,
static_file_provider: StaticFileProvider, static_file_provider: StaticFileProvider<N::Primitives>,
prune_modes: PruneModes, prune_modes: PruneModes,
) -> Self { ) -> Self {
Self { tx, chain_spec, static_file_provider, prune_modes } Self { tx, chain_spec, static_file_provider, prune_modes }
@ -363,7 +365,7 @@ impl<TX: DbTx + 'static, N: NodeTypes> DatabaseProvider<TX, N> {
pub const fn new( pub const fn new(
tx: TX, tx: TX,
chain_spec: Arc<N::ChainSpec>, chain_spec: Arc<N::ChainSpec>,
static_file_provider: StaticFileProvider, static_file_provider: StaticFileProvider<N::Primitives>,
prune_modes: PruneModes, prune_modes: PruneModes,
) -> Self { ) -> Self {
Self { tx, chain_spec, static_file_provider, prune_modes } Self { tx, chain_spec, static_file_provider, prune_modes }

View File

@ -204,7 +204,9 @@ impl<N: ProviderNodeTypes> DatabaseProviderFactory for BlockchainProvider<N> {
} }
impl<N: ProviderNodeTypes> StaticFileProviderFactory for BlockchainProvider<N> { impl<N: ProviderNodeTypes> StaticFileProviderFactory for BlockchainProvider<N> {
fn static_file_provider(&self) -> StaticFileProvider { type Primitives = N::Primitives;
fn static_file_provider(&self) -> StaticFileProvider<Self::Primitives> {
self.database.static_file_provider() self.database.static_file_provider()
} }
} }

View File

@ -12,39 +12,49 @@ use alloy_primitives::{Address, BlockHash, BlockNumber, TxHash, TxNumber, B256,
use reth_chainspec::ChainInfo; use reth_chainspec::ChainInfo;
use reth_db::static_file::{HeaderMask, ReceiptMask, StaticFileCursor, TransactionMask}; use reth_db::static_file::{HeaderMask, ReceiptMask, StaticFileCursor, TransactionMask};
use reth_db_api::models::CompactU256; use reth_db_api::models::CompactU256;
use reth_node_types::NodePrimitives;
use reth_primitives::{ use reth_primitives::{
Receipt, SealedHeader, TransactionMeta, TransactionSigned, TransactionSignedNoHash, Receipt, SealedHeader, TransactionMeta, TransactionSigned, TransactionSignedNoHash,
}; };
use reth_storage_errors::provider::{ProviderError, ProviderResult}; use reth_storage_errors::provider::{ProviderError, ProviderResult};
use std::{ use std::{
fmt::Debug,
ops::{Deref, RangeBounds}, ops::{Deref, RangeBounds},
sync::Arc, sync::Arc,
}; };
/// Provider over a specific `NippyJar` and range. /// Provider over a specific `NippyJar` and range.
#[derive(Debug)] #[derive(Debug)]
pub struct StaticFileJarProvider<'a> { pub struct StaticFileJarProvider<'a, N> {
/// Main static file segment /// Main static file segment
jar: LoadedJarRef<'a>, jar: LoadedJarRef<'a>,
/// Another kind of static file segment to help query data from the main one. /// Another kind of static file segment to help query data from the main one.
auxiliary_jar: Option<Box<Self>>, auxiliary_jar: Option<Box<Self>>,
/// Metrics for the static files.
metrics: Option<Arc<StaticFileProviderMetrics>>, metrics: Option<Arc<StaticFileProviderMetrics>>,
/// Node primitives
_pd: std::marker::PhantomData<N>,
} }
impl<'a> Deref for StaticFileJarProvider<'a> { impl<'a, N: NodePrimitives> Deref for StaticFileJarProvider<'a, N> {
type Target = LoadedJarRef<'a>; type Target = LoadedJarRef<'a>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.jar &self.jar
} }
} }
impl<'a> From<LoadedJarRef<'a>> for StaticFileJarProvider<'a> { impl<'a, N: NodePrimitives> From<LoadedJarRef<'a>> for StaticFileJarProvider<'a, N> {
fn from(value: LoadedJarRef<'a>) -> Self { fn from(value: LoadedJarRef<'a>) -> Self {
StaticFileJarProvider { jar: value, auxiliary_jar: None, metrics: None } StaticFileJarProvider {
jar: value,
auxiliary_jar: None,
metrics: None,
_pd: Default::default(),
}
} }
} }
impl<'a> StaticFileJarProvider<'a> { impl<'a, N: NodePrimitives> StaticFileJarProvider<'a, N> {
/// Provides a cursor for more granular data access. /// Provides a cursor for more granular data access.
pub fn cursor<'b>(&'b self) -> ProviderResult<StaticFileCursor<'a>> pub fn cursor<'b>(&'b self) -> ProviderResult<StaticFileCursor<'a>>
where where
@ -76,7 +86,7 @@ impl<'a> StaticFileJarProvider<'a> {
} }
} }
impl HeaderProvider for StaticFileJarProvider<'_> { impl<N: NodePrimitives> HeaderProvider for StaticFileJarProvider<'_, N> {
fn header(&self, block_hash: &BlockHash) -> ProviderResult<Option<Header>> { fn header(&self, block_hash: &BlockHash) -> ProviderResult<Option<Header>> {
Ok(self Ok(self
.cursor()? .cursor()?
@ -148,7 +158,7 @@ impl HeaderProvider for StaticFileJarProvider<'_> {
} }
} }
impl BlockHashReader for StaticFileJarProvider<'_> { impl<N: NodePrimitives> BlockHashReader for StaticFileJarProvider<'_, N> {
fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> { fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
self.cursor()?.get_one::<HeaderMask<BlockHash>>(number.into()) self.cursor()?.get_one::<HeaderMask<BlockHash>>(number.into())
} }
@ -170,7 +180,7 @@ impl BlockHashReader for StaticFileJarProvider<'_> {
} }
} }
impl BlockNumReader for StaticFileJarProvider<'_> { impl<N: NodePrimitives> BlockNumReader for StaticFileJarProvider<'_, N> {
fn chain_info(&self) -> ProviderResult<ChainInfo> { fn chain_info(&self) -> ProviderResult<ChainInfo> {
// Information on live database // Information on live database
Err(ProviderError::UnsupportedProvider) Err(ProviderError::UnsupportedProvider)
@ -195,7 +205,7 @@ impl BlockNumReader for StaticFileJarProvider<'_> {
} }
} }
impl TransactionsProvider for StaticFileJarProvider<'_> { impl<N: NodePrimitives> TransactionsProvider for StaticFileJarProvider<'_, N> {
fn transaction_id(&self, hash: TxHash) -> ProviderResult<Option<TxNumber>> { fn transaction_id(&self, hash: TxHash) -> ProviderResult<Option<TxNumber>> {
let mut cursor = self.cursor()?; let mut cursor = self.cursor()?;
@ -291,7 +301,7 @@ impl TransactionsProvider for StaticFileJarProvider<'_> {
} }
} }
impl ReceiptProvider for StaticFileJarProvider<'_> { impl<N: NodePrimitives> ReceiptProvider for StaticFileJarProvider<'_, N> {
fn receipt(&self, num: TxNumber) -> ProviderResult<Option<Receipt>> { fn receipt(&self, num: TxNumber) -> ProviderResult<Option<Receipt>> {
self.cursor()?.get_one::<ReceiptMask<Receipt>>(num.into()) self.cursor()?.get_one::<ReceiptMask<Receipt>>(num.into())
} }

View File

@ -29,6 +29,7 @@ use reth_db_api::{
transaction::DbTx, transaction::DbTx,
}; };
use reth_nippy_jar::{NippyJar, NippyJarChecker, CONFIG_FILE_EXTENSION}; use reth_nippy_jar::{NippyJar, NippyJarChecker, CONFIG_FILE_EXTENSION};
use reth_node_types::NodePrimitives;
use reth_primitives::{ use reth_primitives::{
static_file::{ static_file::{
find_fixed_range, HighestStaticFiles, SegmentHeader, SegmentRangeInclusive, find_fixed_range, HighestStaticFiles, SegmentHeader, SegmentRangeInclusive,
@ -42,6 +43,8 @@ use reth_storage_api::DBProvider;
use reth_storage_errors::provider::{ProviderError, ProviderResult}; use reth_storage_errors::provider::{ProviderError, ProviderResult};
use std::{ use std::{
collections::{hash_map::Entry, BTreeMap, HashMap}, collections::{hash_map::Entry, BTreeMap, HashMap},
fmt::Debug,
marker::PhantomData,
ops::{Deref, Range, RangeBounds, RangeInclusive}, ops::{Deref, Range, RangeBounds, RangeInclusive},
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::{mpsc, Arc}, sync::{mpsc, Arc},
@ -77,10 +80,16 @@ impl StaticFileAccess {
} }
/// [`StaticFileProvider`] manages all existing [`StaticFileJarProvider`]. /// [`StaticFileProvider`] manages all existing [`StaticFileJarProvider`].
#[derive(Debug, Clone)] #[derive(Debug)]
pub struct StaticFileProvider(pub(crate) Arc<StaticFileProviderInner>); pub struct StaticFileProvider<N>(pub(crate) Arc<StaticFileProviderInner<N>>);
impl StaticFileProvider { impl<N> Clone for StaticFileProvider<N> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<N: NodePrimitives> StaticFileProvider<N> {
/// Creates a new [`StaticFileProvider`]. /// Creates a new [`StaticFileProvider`].
fn new(path: impl AsRef<Path>, access: StaticFileAccess) -> ProviderResult<Self> { fn new(path: impl AsRef<Path>, access: StaticFileAccess) -> ProviderResult<Self> {
let provider = Self(Arc::new(StaticFileProviderInner::new(path, access)?)); let provider = Self(Arc::new(StaticFileProviderInner::new(path, access)?));
@ -191,8 +200,8 @@ impl StaticFileProvider {
} }
} }
impl Deref for StaticFileProvider { impl<N: NodePrimitives> Deref for StaticFileProvider<N> {
type Target = StaticFileProviderInner; type Target = StaticFileProviderInner<N>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.0 &self.0
@ -201,7 +210,7 @@ impl Deref for StaticFileProvider {
/// [`StaticFileProviderInner`] manages all existing [`StaticFileJarProvider`]. /// [`StaticFileProviderInner`] manages all existing [`StaticFileJarProvider`].
#[derive(Debug)] #[derive(Debug)]
pub struct StaticFileProviderInner { pub struct StaticFileProviderInner<N> {
/// Maintains a map which allows for concurrent access to different `NippyJars`, over different /// Maintains a map which allows for concurrent access to different `NippyJars`, over different
/// segments and ranges. /// segments and ranges.
map: DashMap<(BlockNumber, StaticFileSegment), LoadedJar>, map: DashMap<(BlockNumber, StaticFileSegment), LoadedJar>,
@ -212,7 +221,8 @@ pub struct StaticFileProviderInner {
/// Directory where `static_files` are located /// Directory where `static_files` are located
path: PathBuf, path: PathBuf,
/// Maintains a writer set of [`StaticFileSegment`]. /// Maintains a writer set of [`StaticFileSegment`].
writers: StaticFileWriters, writers: StaticFileWriters<N>,
/// Metrics for the static files.
metrics: Option<Arc<StaticFileProviderMetrics>>, metrics: Option<Arc<StaticFileProviderMetrics>>,
/// Access rights of the provider. /// Access rights of the provider.
access: StaticFileAccess, access: StaticFileAccess,
@ -220,9 +230,11 @@ pub struct StaticFileProviderInner {
blocks_per_file: u64, blocks_per_file: u64,
/// Write lock for when access is [`StaticFileAccess::RW`]. /// Write lock for when access is [`StaticFileAccess::RW`].
_lock_file: Option<StorageLock>, _lock_file: Option<StorageLock>,
/// Node primitives
_pd: PhantomData<N>,
} }
impl StaticFileProviderInner { impl<N: NodePrimitives> StaticFileProviderInner<N> {
/// Creates a new [`StaticFileProviderInner`]. /// Creates a new [`StaticFileProviderInner`].
fn new(path: impl AsRef<Path>, access: StaticFileAccess) -> ProviderResult<Self> { fn new(path: impl AsRef<Path>, access: StaticFileAccess) -> ProviderResult<Self> {
let _lock_file = if access.is_read_write() { let _lock_file = if access.is_read_write() {
@ -241,6 +253,7 @@ impl StaticFileProviderInner {
access, access,
blocks_per_file: DEFAULT_BLOCKS_PER_STATIC_FILE, blocks_per_file: DEFAULT_BLOCKS_PER_STATIC_FILE,
_lock_file, _lock_file,
_pd: Default::default(),
}; };
Ok(provider) Ok(provider)
@ -257,7 +270,7 @@ impl StaticFileProviderInner {
} }
} }
impl StaticFileProvider { impl<N: NodePrimitives> StaticFileProvider<N> {
/// Set a custom number of blocks per file. /// Set a custom number of blocks per file.
#[cfg(any(test, feature = "test-utils"))] #[cfg(any(test, feature = "test-utils"))]
pub fn with_custom_blocks_per_file(self, blocks_per_file: u64) -> Self { pub fn with_custom_blocks_per_file(self, blocks_per_file: u64) -> Self {
@ -323,7 +336,7 @@ impl StaticFileProvider {
segment: StaticFileSegment, segment: StaticFileSegment,
block: BlockNumber, block: BlockNumber,
path: Option<&Path>, path: Option<&Path>,
) -> ProviderResult<StaticFileJarProvider<'_>> { ) -> ProviderResult<StaticFileJarProvider<'_, N>> {
self.get_segment_provider( self.get_segment_provider(
segment, segment,
|| self.get_segment_ranges_from_block(segment, block), || self.get_segment_ranges_from_block(segment, block),
@ -338,7 +351,7 @@ impl StaticFileProvider {
segment: StaticFileSegment, segment: StaticFileSegment,
tx: TxNumber, tx: TxNumber,
path: Option<&Path>, path: Option<&Path>,
) -> ProviderResult<StaticFileJarProvider<'_>> { ) -> ProviderResult<StaticFileJarProvider<'_, N>> {
self.get_segment_provider( self.get_segment_provider(
segment, segment,
|| self.get_segment_ranges_from_transaction(segment, tx), || self.get_segment_ranges_from_transaction(segment, tx),
@ -355,7 +368,7 @@ impl StaticFileProvider {
segment: StaticFileSegment, segment: StaticFileSegment,
fn_range: impl Fn() -> Option<SegmentRangeInclusive>, fn_range: impl Fn() -> Option<SegmentRangeInclusive>,
path: Option<&Path>, path: Option<&Path>,
) -> ProviderResult<Option<StaticFileJarProvider<'_>>> { ) -> ProviderResult<Option<StaticFileJarProvider<'_, N>>> {
// If we have a path, then get the block range from its name. // If we have a path, then get the block range from its name.
// Otherwise, check `self.available_static_files` // Otherwise, check `self.available_static_files`
let block_range = match path { let block_range = match path {
@ -426,12 +439,12 @@ impl StaticFileProvider {
&self, &self,
segment: StaticFileSegment, segment: StaticFileSegment,
fixed_block_range: &SegmentRangeInclusive, fixed_block_range: &SegmentRangeInclusive,
) -> ProviderResult<StaticFileJarProvider<'_>> { ) -> ProviderResult<StaticFileJarProvider<'_, N>> {
let key = (fixed_block_range.end(), segment); let key = (fixed_block_range.end(), segment);
// Avoid using `entry` directly to avoid a write lock in the common case. // Avoid using `entry` directly to avoid a write lock in the common case.
trace!(target: "provider::static_file", ?segment, ?fixed_block_range, "Getting provider"); trace!(target: "provider::static_file", ?segment, ?fixed_block_range, "Getting provider");
let mut provider: StaticFileJarProvider<'_> = if let Some(jar) = self.map.get(&key) { let mut provider: StaticFileJarProvider<'_, N> = if let Some(jar) = self.map.get(&key) {
trace!(target: "provider::static_file", ?segment, ?fixed_block_range, "Jar found in cache"); trace!(target: "provider::static_file", ?segment, ?fixed_block_range, "Jar found in cache");
jar.into() jar.into()
} else { } else {
@ -924,7 +937,7 @@ impl StaticFileProvider {
pub fn find_static_file<T>( pub fn find_static_file<T>(
&self, &self,
segment: StaticFileSegment, segment: StaticFileSegment,
func: impl Fn(StaticFileJarProvider<'_>) -> ProviderResult<Option<T>>, func: impl Fn(StaticFileJarProvider<'_, N>) -> ProviderResult<Option<T>>,
) -> ProviderResult<Option<T>> { ) -> ProviderResult<Option<T>> {
if let Some(highest_block) = self.get_highest_static_file_block(segment) { if let Some(highest_block) = self.get_highest_static_file_block(segment) {
let mut range = self.find_fixed_range(highest_block); let mut range = self.find_fixed_range(highest_block);
@ -1167,30 +1180,35 @@ impl StaticFileProvider {
/// Helper trait to manage different [`StaticFileProviderRW`] of an `Arc<StaticFileProvider` /// Helper trait to manage different [`StaticFileProviderRW`] of an `Arc<StaticFileProvider`
pub trait StaticFileWriter { pub trait StaticFileWriter {
/// The primitives type used by the static file provider.
type Primitives: Send + Sync + 'static;
/// Returns a mutable reference to a [`StaticFileProviderRW`] of a [`StaticFileSegment`]. /// Returns a mutable reference to a [`StaticFileProviderRW`] of a [`StaticFileSegment`].
fn get_writer( fn get_writer(
&self, &self,
block: BlockNumber, block: BlockNumber,
segment: StaticFileSegment, segment: StaticFileSegment,
) -> ProviderResult<StaticFileProviderRWRefMut<'_>>; ) -> ProviderResult<StaticFileProviderRWRefMut<'_, Self::Primitives>>;
/// Returns a mutable reference to a [`StaticFileProviderRW`] of the latest /// Returns a mutable reference to a [`StaticFileProviderRW`] of the latest
/// [`StaticFileSegment`]. /// [`StaticFileSegment`].
fn latest_writer( fn latest_writer(
&self, &self,
segment: StaticFileSegment, segment: StaticFileSegment,
) -> ProviderResult<StaticFileProviderRWRefMut<'_>>; ) -> ProviderResult<StaticFileProviderRWRefMut<'_, Self::Primitives>>;
/// Commits all changes of all [`StaticFileProviderRW`] of all [`StaticFileSegment`]. /// Commits all changes of all [`StaticFileProviderRW`] of all [`StaticFileSegment`].
fn commit(&self) -> ProviderResult<()>; fn commit(&self) -> ProviderResult<()>;
} }
impl StaticFileWriter for StaticFileProvider { impl<N: NodePrimitives> StaticFileWriter for StaticFileProvider<N> {
type Primitives = N;
fn get_writer( fn get_writer(
&self, &self,
block: BlockNumber, block: BlockNumber,
segment: StaticFileSegment, segment: StaticFileSegment,
) -> ProviderResult<StaticFileProviderRWRefMut<'_>> { ) -> ProviderResult<StaticFileProviderRWRefMut<'_, Self::Primitives>> {
if self.access.is_read_only() { if self.access.is_read_only() {
return Err(ProviderError::ReadOnlyStaticFileAccess) return Err(ProviderError::ReadOnlyStaticFileAccess)
} }
@ -1204,7 +1222,7 @@ impl StaticFileWriter for StaticFileProvider {
fn latest_writer( fn latest_writer(
&self, &self,
segment: StaticFileSegment, segment: StaticFileSegment,
) -> ProviderResult<StaticFileProviderRWRefMut<'_>> { ) -> ProviderResult<StaticFileProviderRWRefMut<'_, Self::Primitives>> {
self.get_writer(self.get_highest_static_file_block(segment).unwrap_or_default(), segment) self.get_writer(self.get_highest_static_file_block(segment).unwrap_or_default(), segment)
} }
@ -1213,7 +1231,7 @@ impl StaticFileWriter for StaticFileProvider {
} }
} }
impl HeaderProvider for StaticFileProvider { impl<N: NodePrimitives> HeaderProvider for StaticFileProvider<N> {
fn header(&self, block_hash: &BlockHash) -> ProviderResult<Option<Header>> { fn header(&self, block_hash: &BlockHash) -> ProviderResult<Option<Header>> {
self.find_static_file(StaticFileSegment::Headers, |jar_provider| { self.find_static_file(StaticFileSegment::Headers, |jar_provider| {
Ok(jar_provider Ok(jar_provider
@ -1300,7 +1318,7 @@ impl HeaderProvider for StaticFileProvider {
} }
} }
impl BlockHashReader for StaticFileProvider { impl<N: NodePrimitives> BlockHashReader for StaticFileProvider<N> {
fn block_hash(&self, num: u64) -> ProviderResult<Option<B256>> { fn block_hash(&self, num: u64) -> ProviderResult<Option<B256>> {
self.get_segment_provider_from_block(StaticFileSegment::Headers, num, None)?.block_hash(num) self.get_segment_provider_from_block(StaticFileSegment::Headers, num, None)?.block_hash(num)
} }
@ -1319,7 +1337,7 @@ impl BlockHashReader for StaticFileProvider {
} }
} }
impl ReceiptProvider for StaticFileProvider { impl<N: NodePrimitives> ReceiptProvider for StaticFileProvider<N> {
fn receipt(&self, num: TxNumber) -> ProviderResult<Option<Receipt>> { fn receipt(&self, num: TxNumber) -> ProviderResult<Option<Receipt>> {
self.get_segment_provider_from_transaction(StaticFileSegment::Receipts, num, None) self.get_segment_provider_from_transaction(StaticFileSegment::Receipts, num, None)
.and_then(|provider| provider.receipt(num)) .and_then(|provider| provider.receipt(num))
@ -1356,7 +1374,7 @@ impl ReceiptProvider for StaticFileProvider {
} }
} }
impl TransactionsProviderExt for StaticFileProvider { impl<N: NodePrimitives> TransactionsProviderExt for StaticFileProvider<N> {
fn transaction_hashes_by_range( fn transaction_hashes_by_range(
&self, &self,
tx_range: Range<TxNumber>, tx_range: Range<TxNumber>,
@ -1417,7 +1435,7 @@ impl TransactionsProviderExt for StaticFileProvider {
} }
} }
impl TransactionsProvider for StaticFileProvider { impl<N: NodePrimitives> TransactionsProvider for StaticFileProvider<N> {
fn transaction_id(&self, tx_hash: TxHash) -> ProviderResult<Option<TxNumber>> { fn transaction_id(&self, tx_hash: TxHash) -> ProviderResult<Option<TxNumber>> {
self.find_static_file(StaticFileSegment::Transactions, |jar_provider| { self.find_static_file(StaticFileSegment::Transactions, |jar_provider| {
let mut cursor = jar_provider.cursor()?; let mut cursor = jar_provider.cursor()?;
@ -1529,7 +1547,7 @@ impl TransactionsProvider for StaticFileProvider {
/* Cannot be successfully implemented but must exist for trait requirements */ /* Cannot be successfully implemented but must exist for trait requirements */
impl BlockNumReader for StaticFileProvider { impl<N: NodePrimitives> BlockNumReader for StaticFileProvider<N> {
fn chain_info(&self) -> ProviderResult<ChainInfo> { fn chain_info(&self) -> ProviderResult<ChainInfo> {
// Required data not present in static_files // Required data not present in static_files
Err(ProviderError::UnsupportedProvider) Err(ProviderError::UnsupportedProvider)
@ -1551,7 +1569,7 @@ impl BlockNumReader for StaticFileProvider {
} }
} }
impl BlockReader for StaticFileProvider { impl<N: NodePrimitives> BlockReader for StaticFileProvider<N> {
fn find_block_by_hash( fn find_block_by_hash(
&self, &self,
_hash: B256, _hash: B256,
@ -1629,7 +1647,7 @@ impl BlockReader for StaticFileProvider {
} }
} }
impl WithdrawalsProvider for StaticFileProvider { impl<N: NodePrimitives> WithdrawalsProvider for StaticFileProvider<N> {
fn withdrawals_by_block( fn withdrawals_by_block(
&self, &self,
_id: BlockHashOrNumber, _id: BlockHashOrNumber,
@ -1645,7 +1663,7 @@ impl WithdrawalsProvider for StaticFileProvider {
} }
} }
impl StatsReader for StaticFileProvider { impl<N: NodePrimitives> StatsReader for StaticFileProvider<N> {
fn count_entries<T: Table>(&self) -> ProviderResult<usize> { fn count_entries<T: Table>(&self) -> ProviderResult<usize> {
match T::NAME { match T::NAME {
tables::CanonicalHeaders::NAME | tables::CanonicalHeaders::NAME |

View File

@ -55,7 +55,9 @@ impl Deref for LoadedJar {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::{test_utils::create_test_provider_factory, HeaderProvider}; use crate::{
test_utils::create_test_provider_factory, HeaderProvider, StaticFileProviderFactory,
};
use alloy_consensus::{Header, Transaction}; use alloy_consensus::{Header, Transaction};
use alloy_primitives::{BlockHash, TxNumber, B256, U256}; use alloy_primitives::{BlockHash, TxNumber, B256, U256};
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
@ -116,7 +118,7 @@ mod tests {
// Create StaticFile // Create StaticFile
{ {
let manager = StaticFileProvider::read_write(static_files_path.path()).unwrap(); let manager = factory.static_file_provider();
let mut writer = manager.latest_writer(StaticFileSegment::Headers).unwrap(); let mut writer = manager.latest_writer(StaticFileSegment::Headers).unwrap();
let mut td = U256::ZERO; let mut td = U256::ZERO;
@ -131,7 +133,7 @@ mod tests {
// Use providers to query Header data and compare if it matches // Use providers to query Header data and compare if it matches
{ {
let db_provider = factory.provider().unwrap(); let db_provider = factory.provider().unwrap();
let manager = StaticFileProvider::read_write(static_files_path.path()).unwrap(); let manager = db_provider.static_file_provider();
let jar_provider = manager let jar_provider = manager
.get_segment_provider_from_block(StaticFileSegment::Headers, 0, Some(&static_file)) .get_segment_provider_from_block(StaticFileSegment::Headers, 0, Some(&static_file))
.unwrap(); .unwrap();
@ -170,7 +172,7 @@ mod tests {
// [ Headers Creation and Commit ] // [ Headers Creation and Commit ]
{ {
let sf_rw = StaticFileProvider::read_write(&static_dir) let sf_rw = StaticFileProvider::<()>::read_write(&static_dir)
.expect("Failed to create static file provider") .expect("Failed to create static file provider")
.with_custom_blocks_per_file(blocks_per_file); .with_custom_blocks_per_file(blocks_per_file);
@ -189,8 +191,8 @@ mod tests {
// Helper function to prune headers and validate truncation results // Helper function to prune headers and validate truncation results
fn prune_and_validate( fn prune_and_validate(
writer: &mut StaticFileProviderRWRefMut<'_>, writer: &mut StaticFileProviderRWRefMut<'_, ()>,
sf_rw: &StaticFileProvider, sf_rw: &StaticFileProvider<()>,
static_dir: impl AsRef<Path>, static_dir: impl AsRef<Path>,
prune_count: u64, prune_count: u64,
expected_tip: Option<u64>, expected_tip: Option<u64>,
@ -302,13 +304,13 @@ mod tests {
/// * `10..=19`: no txs/receipts /// * `10..=19`: no txs/receipts
/// * `20..=29`: only one tx/receipt /// * `20..=29`: only one tx/receipt
fn setup_tx_based_scenario( fn setup_tx_based_scenario(
sf_rw: &StaticFileProvider, sf_rw: &StaticFileProvider<()>,
segment: StaticFileSegment, segment: StaticFileSegment,
blocks_per_file: u64, blocks_per_file: u64,
) { ) {
fn setup_block_ranges( fn setup_block_ranges(
writer: &mut StaticFileProviderRWRefMut<'_>, writer: &mut StaticFileProviderRWRefMut<'_, ()>,
sf_rw: &StaticFileProvider, sf_rw: &StaticFileProvider<()>,
segment: StaticFileSegment, segment: StaticFileSegment,
block_range: &Range<u64>, block_range: &Range<u64>,
mut tx_count: u64, mut tx_count: u64,
@ -413,7 +415,7 @@ mod tests {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn prune_and_validate( fn prune_and_validate(
sf_rw: &StaticFileProvider, sf_rw: &StaticFileProvider<()>,
static_dir: impl AsRef<Path>, static_dir: impl AsRef<Path>,
segment: StaticFileSegment, segment: StaticFileSegment,
prune_count: u64, prune_count: u64,

View File

@ -8,6 +8,7 @@ use parking_lot::{lock_api::RwLockWriteGuard, RawRwLock, RwLock};
use reth_codecs::Compact; use reth_codecs::Compact;
use reth_db_api::models::CompactU256; use reth_db_api::models::CompactU256;
use reth_nippy_jar::{NippyJar, NippyJarError, NippyJarWriter}; use reth_nippy_jar::{NippyJar, NippyJarError, NippyJarWriter};
use reth_node_types::NodePrimitives;
use reth_primitives::{ use reth_primitives::{
static_file::{SegmentHeader, SegmentRangeInclusive}, static_file::{SegmentHeader, SegmentRangeInclusive},
Receipt, StaticFileSegment, Receipt, StaticFileSegment,
@ -15,6 +16,7 @@ use reth_primitives::{
use reth_storage_errors::provider::{ProviderError, ProviderResult}; use reth_storage_errors::provider::{ProviderError, ProviderResult};
use std::{ use std::{
borrow::Borrow, borrow::Borrow,
fmt::Debug,
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::{Arc, Weak}, sync::{Arc, Weak},
time::Instant, time::Instant,
@ -25,19 +27,29 @@ use tracing::debug;
/// ///
/// WARNING: Trying to use more than one writer for the same segment type **will result in a /// WARNING: Trying to use more than one writer for the same segment type **will result in a
/// deadlock**. /// deadlock**.
#[derive(Debug, Default)] #[derive(Debug)]
pub(crate) struct StaticFileWriters { pub(crate) struct StaticFileWriters<N> {
headers: RwLock<Option<StaticFileProviderRW>>, headers: RwLock<Option<StaticFileProviderRW<N>>>,
transactions: RwLock<Option<StaticFileProviderRW>>, transactions: RwLock<Option<StaticFileProviderRW<N>>>,
receipts: RwLock<Option<StaticFileProviderRW>>, receipts: RwLock<Option<StaticFileProviderRW<N>>>,
} }
impl StaticFileWriters { impl<N> Default for StaticFileWriters<N> {
fn default() -> Self {
Self {
headers: Default::default(),
transactions: Default::default(),
receipts: Default::default(),
}
}
}
impl<N: NodePrimitives> StaticFileWriters<N> {
pub(crate) fn get_or_create( pub(crate) fn get_or_create(
&self, &self,
segment: StaticFileSegment, segment: StaticFileSegment,
create_fn: impl FnOnce() -> ProviderResult<StaticFileProviderRW>, create_fn: impl FnOnce() -> ProviderResult<StaticFileProviderRW<N>>,
) -> ProviderResult<StaticFileProviderRWRefMut<'_>> { ) -> ProviderResult<StaticFileProviderRWRefMut<'_, N>> {
let mut write_guard = match segment { let mut write_guard = match segment {
StaticFileSegment::Headers => self.headers.write(), StaticFileSegment::Headers => self.headers.write(),
StaticFileSegment::Transactions => self.transactions.write(), StaticFileSegment::Transactions => self.transactions.write(),
@ -64,19 +76,19 @@ impl StaticFileWriters {
/// Mutable reference to a [`StaticFileProviderRW`] behind a [`RwLockWriteGuard`]. /// Mutable reference to a [`StaticFileProviderRW`] behind a [`RwLockWriteGuard`].
#[derive(Debug)] #[derive(Debug)]
pub struct StaticFileProviderRWRefMut<'a>( pub struct StaticFileProviderRWRefMut<'a, N>(
pub(crate) RwLockWriteGuard<'a, RawRwLock, Option<StaticFileProviderRW>>, pub(crate) RwLockWriteGuard<'a, RawRwLock, Option<StaticFileProviderRW<N>>>,
); );
impl std::ops::DerefMut for StaticFileProviderRWRefMut<'_> { impl<N> std::ops::DerefMut for StaticFileProviderRWRefMut<'_, N> {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
// This is always created by [`StaticFileWriters::get_or_create`] // This is always created by [`StaticFileWriters::get_or_create`]
self.0.as_mut().expect("static file writer provider should be init") self.0.as_mut().expect("static file writer provider should be init")
} }
} }
impl std::ops::Deref for StaticFileProviderRWRefMut<'_> { impl<N> std::ops::Deref for StaticFileProviderRWRefMut<'_, N> {
type Target = StaticFileProviderRW; type Target = StaticFileProviderRW<N>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
// This is always created by [`StaticFileWriters::get_or_create`] // This is always created by [`StaticFileWriters::get_or_create`]
@ -86,11 +98,11 @@ impl std::ops::Deref for StaticFileProviderRWRefMut<'_> {
#[derive(Debug)] #[derive(Debug)]
/// Extends `StaticFileProvider` with writing capabilities /// Extends `StaticFileProvider` with writing capabilities
pub struct StaticFileProviderRW { pub struct StaticFileProviderRW<N> {
/// Reference back to the provider. We need [Weak] here because [`StaticFileProviderRW`] is /// Reference back to the provider. We need [Weak] here because [`StaticFileProviderRW`] is
/// stored in a [`dashmap::DashMap`] inside the parent [`StaticFileProvider`].which is an /// stored in a [`dashmap::DashMap`] inside the parent [`StaticFileProvider`].which is an
/// [Arc]. If we were to use an [Arc] here, we would create a reference cycle. /// [Arc]. If we were to use an [Arc] here, we would create a reference cycle.
reader: Weak<StaticFileProviderInner>, reader: Weak<StaticFileProviderInner<N>>,
/// A [`NippyJarWriter`] instance. /// A [`NippyJarWriter`] instance.
writer: NippyJarWriter<SegmentHeader>, writer: NippyJarWriter<SegmentHeader>,
/// Path to opened file. /// Path to opened file.
@ -104,7 +116,7 @@ pub struct StaticFileProviderRW {
prune_on_commit: Option<(u64, Option<BlockNumber>)>, prune_on_commit: Option<(u64, Option<BlockNumber>)>,
} }
impl StaticFileProviderRW { impl<N: NodePrimitives> StaticFileProviderRW<N> {
/// Creates a new [`StaticFileProviderRW`] for a [`StaticFileSegment`]. /// Creates a new [`StaticFileProviderRW`] for a [`StaticFileSegment`].
/// ///
/// Before use, transaction based segments should ensure the block end range is the expected /// Before use, transaction based segments should ensure the block end range is the expected
@ -112,7 +124,7 @@ impl StaticFileProviderRW {
pub fn new( pub fn new(
segment: StaticFileSegment, segment: StaticFileSegment,
block: BlockNumber, block: BlockNumber,
reader: Weak<StaticFileProviderInner>, reader: Weak<StaticFileProviderInner<N>>,
metrics: Option<Arc<StaticFileProviderMetrics>>, metrics: Option<Arc<StaticFileProviderMetrics>>,
) -> ProviderResult<Self> { ) -> ProviderResult<Self> {
let (writer, data_path) = Self::open(segment, block, reader.clone(), metrics.clone())?; let (writer, data_path) = Self::open(segment, block, reader.clone(), metrics.clone())?;
@ -133,7 +145,7 @@ impl StaticFileProviderRW {
fn open( fn open(
segment: StaticFileSegment, segment: StaticFileSegment,
block: u64, block: u64,
reader: Weak<StaticFileProviderInner>, reader: Weak<StaticFileProviderInner<N>>,
metrics: Option<Arc<StaticFileProviderMetrics>>, metrics: Option<Arc<StaticFileProviderMetrics>>,
) -> ProviderResult<(NippyJarWriter<SegmentHeader>, PathBuf)> { ) -> ProviderResult<(NippyJarWriter<SegmentHeader>, PathBuf)> {
let start = Instant::now(); let start = Instant::now();
@ -751,7 +763,7 @@ impl StaticFileProviderRW {
Ok(()) Ok(())
} }
fn reader(&self) -> StaticFileProvider { fn reader(&self) -> StaticFileProvider<N> {
Self::upgrade_provider_to_strong_reference(&self.reader) Self::upgrade_provider_to_strong_reference(&self.reader)
} }
@ -764,8 +776,8 @@ impl StaticFileProviderRW {
/// active. In reality, it's impossible to detach the [`StaticFileProviderRW`] from the /// active. In reality, it's impossible to detach the [`StaticFileProviderRW`] from the
/// [`StaticFileProvider`]. /// [`StaticFileProvider`].
fn upgrade_provider_to_strong_reference( fn upgrade_provider_to_strong_reference(
provider: &Weak<StaticFileProviderInner>, provider: &Weak<StaticFileProviderInner<N>>,
) -> StaticFileProvider { ) -> StaticFileProvider<N> {
provider.upgrade().map(StaticFileProvider).expect("StaticFileProvider is dropped") provider.upgrade().map(StaticFileProvider).expect("StaticFileProvider is dropped")
} }

View File

@ -556,7 +556,9 @@ impl PruneCheckpointReader for NoopProvider {
} }
impl StaticFileProviderFactory for NoopProvider { impl StaticFileProviderFactory for NoopProvider {
fn static_file_provider(&self) -> StaticFileProvider { type Primitives = ();
fn static_file_provider(&self) -> StaticFileProvider<Self::Primitives> {
StaticFileProvider::read_only(PathBuf::default(), false).unwrap() StaticFileProvider::read_only(PathBuf::default(), false).unwrap()
} }
} }

View File

@ -1,7 +1,12 @@
use reth_node_types::NodePrimitives;
use crate::providers::StaticFileProvider; use crate::providers::StaticFileProvider;
/// Static file provider factory. /// Static file provider factory.
pub trait StaticFileProviderFactory { pub trait StaticFileProviderFactory {
/// The network primitives type [`StaticFileProvider`] is using.
type Primitives: NodePrimitives;
/// Create new instance of static file provider. /// Create new instance of static file provider.
fn static_file_provider(&self) -> StaticFileProvider; fn static_file_provider(&self) -> StaticFileProvider<Self::Primitives>;
} }

View File

@ -1,7 +1,8 @@
use crate::{ use crate::{
providers::{StaticFileProvider, StaticFileProviderRWRefMut, StaticFileWriter as SfWriter}, providers::{StaticFileProvider, StaticFileProviderRWRefMut, StaticFileWriter as SfWriter},
writer::static_file::StaticFileWriter, writer::static_file::StaticFileWriter,
BlockExecutionWriter, BlockWriter, HistoryWriter, StateChangeWriter, StateWriter, TrieWriter, BlockExecutionWriter, BlockWriter, HistoryWriter, StateChangeWriter, StateWriter,
StaticFileProviderFactory, TrieWriter,
}; };
use alloy_consensus::Header; use alloy_consensus::Header;
use alloy_primitives::{BlockNumber, B256, U256}; use alloy_primitives::{BlockNumber, B256, U256};
@ -115,15 +116,13 @@ impl UnifiedStorageWriter<'_, (), ()> {
/// start-up. /// start-up.
/// ///
/// NOTE: If unwinding data from storage, use `commit_unwind` instead! /// NOTE: If unwinding data from storage, use `commit_unwind` instead!
pub fn commit<P>( pub fn commit<P>(provider: P) -> ProviderResult<()>
database: impl Into<P> + AsRef<P>,
static_file: StaticFileProvider,
) -> ProviderResult<()>
where where
P: DBProvider<Tx: DbTxMut>, P: DBProvider<Tx: DbTxMut> + StaticFileProviderFactory,
{ {
let static_file = provider.static_file_provider();
static_file.commit()?; static_file.commit()?;
database.into().into_tx().commit()?; provider.commit()?;
Ok(()) Ok(())
} }
@ -135,20 +134,18 @@ impl UnifiedStorageWriter<'_, (), ()> {
/// checkpoints on the next start-up. /// checkpoints on the next start-up.
/// ///
/// NOTE: Should only be used after unwinding data from storage! /// NOTE: Should only be used after unwinding data from storage!
pub fn commit_unwind<P>( pub fn commit_unwind<P>(provider: P) -> ProviderResult<()>
database: impl Into<P> + AsRef<P>,
static_file: StaticFileProvider,
) -> ProviderResult<()>
where where
P: DBProvider<Tx: DbTxMut>, P: DBProvider<Tx: DbTxMut> + StaticFileProviderFactory,
{ {
database.into().into_tx().commit()?; let static_file = provider.static_file_provider();
provider.commit()?;
static_file.commit()?; static_file.commit()?;
Ok(()) Ok(())
} }
} }
impl<ProviderDB> UnifiedStorageWriter<'_, ProviderDB, &StaticFileProvider> impl<ProviderDB> UnifiedStorageWriter<'_, ProviderDB, &StaticFileProvider<ProviderDB::Primitives>>
where where
ProviderDB: DBProvider<Tx: DbTx + DbTxMut> ProviderDB: DBProvider<Tx: DbTx + DbTxMut>
+ BlockWriter + BlockWriter
@ -158,7 +155,8 @@ where
+ HistoryWriter + HistoryWriter
+ StageCheckpointWriter + StageCheckpointWriter
+ BlockExecutionWriter + BlockExecutionWriter
+ AsRef<ProviderDB>, + AsRef<ProviderDB>
+ StaticFileProviderFactory,
{ {
/// Writes executed blocks and receipts to storage. /// Writes executed blocks and receipts to storage.
pub fn save_blocks(&self, blocks: &[ExecutedBlock]) -> ProviderResult<()> { pub fn save_blocks(&self, blocks: &[ExecutedBlock]) -> ProviderResult<()> {
@ -319,9 +317,10 @@ where
} }
} }
impl<ProviderDB> UnifiedStorageWriter<'_, ProviderDB, StaticFileProviderRWRefMut<'_>> impl<ProviderDB>
UnifiedStorageWriter<'_, ProviderDB, StaticFileProviderRWRefMut<'_, ProviderDB::Primitives>>
where where
ProviderDB: DBProvider<Tx: DbTx> + HeaderProvider, ProviderDB: DBProvider<Tx: DbTx> + HeaderProvider + StaticFileProviderFactory,
{ {
/// Ensures that the static file writer is set and of the right [`StaticFileSegment`] variant. /// Ensures that the static file writer is set and of the right [`StaticFileSegment`] variant.
/// ///
@ -430,9 +429,10 @@ where
} }
} }
impl<ProviderDB> UnifiedStorageWriter<'_, ProviderDB, StaticFileProviderRWRefMut<'_>> impl<ProviderDB>
UnifiedStorageWriter<'_, ProviderDB, StaticFileProviderRWRefMut<'_, ProviderDB::Primitives>>
where where
ProviderDB: DBProvider<Tx: DbTxMut + DbTx> + HeaderProvider, ProviderDB: DBProvider<Tx: DbTxMut + DbTx> + HeaderProvider + StaticFileProviderFactory,
{ {
/// Appends receipts block by block. /// Appends receipts block by block.
/// ///
@ -512,9 +512,12 @@ where
} }
impl<ProviderDB> StateWriter impl<ProviderDB> StateWriter
for UnifiedStorageWriter<'_, ProviderDB, StaticFileProviderRWRefMut<'_>> for UnifiedStorageWriter<'_, ProviderDB, StaticFileProviderRWRefMut<'_, ProviderDB::Primitives>>
where where
ProviderDB: DBProvider<Tx: DbTxMut + DbTx> + StateChangeWriter + HeaderProvider, ProviderDB: DBProvider<Tx: DbTxMut + DbTx>
+ StateChangeWriter
+ HeaderProvider
+ StaticFileProviderFactory,
{ {
/// Write the data and receipts to the database or static files if `static_file_producer` is /// Write the data and receipts to the database or static files if `static_file_producer` is
/// `Some`. It should be `None` if there is any kind of pruning/filtering over the receipts. /// `Some`. It should be `None` if there is any kind of pruning/filtering over the receipts.

View File

@ -1,12 +1,13 @@
use crate::providers::StaticFileProviderRWRefMut; use crate::providers::StaticFileProviderRWRefMut;
use alloy_primitives::{BlockNumber, TxNumber}; use alloy_primitives::{BlockNumber, TxNumber};
use reth_errors::ProviderResult; use reth_errors::ProviderResult;
use reth_node_types::NodePrimitives;
use reth_primitives::Receipt; use reth_primitives::Receipt;
use reth_storage_api::ReceiptWriter; use reth_storage_api::ReceiptWriter;
pub(crate) struct StaticFileWriter<'a, W>(pub(crate) &'a mut W); pub(crate) struct StaticFileWriter<'a, W>(pub(crate) &'a mut W);
impl ReceiptWriter for StaticFileWriter<'_, StaticFileProviderRWRefMut<'_>> { impl<N: NodePrimitives> ReceiptWriter for StaticFileWriter<'_, StaticFileProviderRWRefMut<'_, N>> {
fn append_block_receipts( fn append_block_receipts(
&mut self, &mut self,
first_tx_index: TxNumber, first_tx_index: TxNumber,