Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions crates/node/builder/src/launch/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -541,10 +541,16 @@ where
(None, Some(_)) => "static file",
(None, None) => unreachable!(),
};
assert_ne!(
unwind_block, 0,
"A {} inconsistency was found that would trigger an unwind to block 0",
inconsistency_source

let genesis_block = self.chain_spec().genesis().number.unwrap_or(0);

assert!(
unwind_block >= genesis_block,
"A {} inconsistency was found that would trigger an unwind to block {} (genesis is {}). \
This would cause data loss. Check RocksDB consistency logic for custom genesis support.",
inconsistency_source,
unwind_block,
genesis_block
);

let unwind_target = PipelineTarget::Unwind(unwind_block);
Expand Down
18 changes: 18 additions & 0 deletions crates/node/builder/src/launch/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,24 @@ impl EngineNodeLauncher {
.with_genesis()?
.inspect(|this: &LaunchContextWith<Attached<WithConfigs<<T::Types as NodeTypes>::ChainSpec>, _>>| {
info!(target: "reth::cli", "\n{}", this.chain_spec().display_hardforks());

// Log storage settings after genesis initialization
match this.provider_factory().storage_settings() {
Ok(settings) => {
info!(
target: "reth::cli",
?settings,
"Storage settings (after genesis)"
);
},
Err(err) => {
warn!(
target: "reth::cli",
?err,
"Failed to get storage settings after genesis"
);
},
}
})
.with_metrics_task()
// passing FullNodeTypes as type parameter here so that we can build
Expand Down
18 changes: 14 additions & 4 deletions crates/node/core/src/args/static_files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,19 @@ impl StaticFilesArgs {

/// Converts the static files arguments into [`StorageSettings`].
pub const fn to_settings(&self) -> StorageSettings {
StorageSettings::legacy()
.with_receipts_in_static_files(self.receipts)
.with_transaction_senders_in_static_files(self.transaction_senders)
.with_account_changesets_in_static_files(self.account_changesets)
#[cfg(feature = "edge")]
{
StorageSettings::edge()
.with_receipts_in_static_files(self.receipts)
.with_transaction_senders_in_static_files(self.transaction_senders)
.with_account_changesets_in_static_files(self.account_changesets)
}
#[cfg(not(feature = "edge"))]
{
StorageSettings::legacy()
.with_receipts_in_static_files(self.receipts)
.with_transaction_senders_in_static_files(self.transaction_senders)
.with_account_changesets_in_static_files(self.account_changesets)
}
}
}
6 changes: 3 additions & 3 deletions crates/storage/db-api/src/models/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ impl StorageSettings {
receipts_in_static_files: true,
transaction_senders_in_static_files: true,
account_changesets_in_static_files: true,
storages_history_in_rocksdb: false,
transaction_hash_numbers_in_rocksdb: false,
account_history_in_rocksdb: false,
storages_history_in_rocksdb: true,
transaction_hash_numbers_in_rocksdb: true,
account_history_in_rocksdb: true,
}
}

Expand Down
120 changes: 100 additions & 20 deletions crates/storage/provider/src/providers/rocksdb/invariants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use reth_storage_api::{
DBProvider, StageCheckpointReader, StorageSettingsCache, TransactionsProvider,
};
use reth_storage_errors::provider::ProviderResult;
use reth_chainspec::{ChainSpecProvider, EthChainSpec};

impl RocksDBProvider {
/// Checks consistency of `RocksDB` tables against MDBX stage checkpoints.
Expand Down Expand Up @@ -51,27 +52,28 @@ impl RocksDBProvider {
+ StageCheckpointReader
+ StorageSettingsCache
+ StaticFileProviderFactory
+ TransactionsProvider<Transaction: Encodable2718>,
+ TransactionsProvider<Transaction: Encodable2718>
+ ChainSpecProvider,
{
let mut unwind_target: Option<BlockNumber> = None;

// Check TransactionHashNumbers if stored in RocksDB
if provider.cached_storage_settings().transaction_hash_numbers_in_rocksdb &&
let Some(target) = self.check_transaction_hash_numbers(provider)?
if provider.cached_storage_settings().transaction_hash_numbers_in_rocksdb
&& let Some(target) = self.check_transaction_hash_numbers(provider)?
{
unwind_target = Some(unwind_target.map_or(target, |t| t.min(target)));
}

// Check StoragesHistory if stored in RocksDB
if provider.cached_storage_settings().storages_history_in_rocksdb &&
let Some(target) = self.check_storages_history(provider)?
if provider.cached_storage_settings().storages_history_in_rocksdb
&& let Some(target) = self.check_storages_history(provider)?
{
unwind_target = Some(unwind_target.map_or(target, |t| t.min(target)));
}

// Check AccountsHistory if stored in RocksDB
if provider.cached_storage_settings().account_history_in_rocksdb &&
let Some(target) = self.check_accounts_history(provider)?
if provider.cached_storage_settings().account_history_in_rocksdb
&& let Some(target) = self.check_accounts_history(provider)?
{
unwind_target = Some(unwind_target.map_or(target, |t| t.min(target)));
}
Expand Down Expand Up @@ -99,7 +101,8 @@ impl RocksDBProvider {
Provider: DBProvider
+ StageCheckpointReader
+ StaticFileProviderFactory
+ TransactionsProvider<Transaction: Encodable2718>,
+ TransactionsProvider<Transaction: Encodable2718>
+ ChainSpecProvider,
{
// Get the TransactionLookup stage checkpoint
let checkpoint = provider
Expand Down Expand Up @@ -167,12 +170,37 @@ impl RocksDBProvider {
// Both MDBX and static files are empty.
// If checkpoint says we should have data, that's an inconsistency.
if checkpoint > 0 {
tracing::warn!(
target: "reth::providers::rocksdb",
checkpoint,
"Checkpoint set but no transaction data exists, unwind needed"
);
return Ok(Some(0));
// For nodes with custom genesis blocks, having empty data at genesis
// checkpoint is normal. Only trigger unwind if checkpoint is beyond genesis.
let genesis_block = provider.chain_spec().genesis().number.unwrap_or(0);

if checkpoint > genesis_block {
tracing::warn!(
target: "reth::providers::rocksdb",
checkpoint,
genesis_block,
"Checkpoint beyond genesis but no transaction data exists, unwind needed"
);
return Ok(Some(genesis_block));
} else if checkpoint == genesis_block {
// Checkpoint is at genesis with empty data - this is normal for custom genesis.
// No unwind needed, RocksDB will start populating from genesis forward.
tracing::info!(
target: "reth::providers::rocksdb",
genesis_block,
"RocksDB checkpoint at custom genesis with empty data - normal state"
);
return Ok(None);
} else {
// Checkpoint < genesis_block - shouldn't happen but handle gracefully
tracing::warn!(
target: "reth::providers::rocksdb",
checkpoint,
genesis_block,
"Checkpoint below genesis, unwind to genesis needed"
);
return Ok(Some(genesis_block));
}
}
}
}
Expand Down Expand Up @@ -239,7 +267,7 @@ impl RocksDBProvider {
provider: &Provider,
) -> ProviderResult<Option<BlockNumber>>
where
Provider: DBProvider + StageCheckpointReader,
Provider: DBProvider + StageCheckpointReader + ChainSpecProvider,
{
// Get the IndexStorageHistory stage checkpoint
let checkpoint = provider
Expand Down Expand Up @@ -298,8 +326,34 @@ impl RocksDBProvider {
None => {
// Empty RocksDB table
if checkpoint > 0 {
// Stage says we should have data but we don't
return Ok(Some(0));
// For nodes with custom genesis blocks, having empty data at genesis
// checkpoint is normal. Only trigger unwind if checkpoint is beyond genesis.
let genesis_block = provider.chain_spec().genesis().number.unwrap_or(0);

if checkpoint > genesis_block {
tracing::warn!(
target: "reth::providers::rocksdb",
checkpoint,
genesis_block,
"StoragesHistory checkpoint beyond genesis but no data exists, unwind needed"
);
return Ok(Some(genesis_block));
} else if checkpoint == genesis_block {
tracing::info!(
target: "reth::providers::rocksdb",
genesis_block,
"StoragesHistory at custom genesis with empty data - normal state"
);
return Ok(None);
} else {
tracing::warn!(
target: "reth::providers::rocksdb",
checkpoint,
genesis_block,
"StoragesHistory checkpoint below genesis, unwind to genesis needed"
);
return Ok(Some(genesis_block));
}
}
Ok(None)
}
Expand Down Expand Up @@ -353,7 +407,7 @@ impl RocksDBProvider {
provider: &Provider,
) -> ProviderResult<Option<BlockNumber>>
where
Provider: DBProvider + StageCheckpointReader,
Provider: DBProvider + StageCheckpointReader + ChainSpecProvider,
{
// Get the IndexAccountHistory stage checkpoint
let checkpoint = provider
Expand Down Expand Up @@ -415,8 +469,34 @@ impl RocksDBProvider {
None => {
// Empty RocksDB table
if checkpoint > 0 {
// Stage says we should have data but we don't
return Ok(Some(0));
// For nodes with custom genesis blocks, having empty data at genesis
// checkpoint is normal. Only trigger unwind if checkpoint is beyond genesis.
let genesis_block = provider.chain_spec().genesis().number.unwrap_or(0);

if checkpoint > genesis_block {
tracing::warn!(
target: "reth::providers::rocksdb",
checkpoint,
genesis_block,
"AccountsHistory checkpoint beyond genesis but no data exists, unwind needed"
);
return Ok(Some(genesis_block));
} else if checkpoint == genesis_block {
tracing::info!(
target: "reth::providers::rocksdb",
genesis_block,
"AccountsHistory at custom genesis with empty data - normal state"
);
return Ok(None);
} else {
tracing::warn!(
target: "reth::providers::rocksdb",
checkpoint,
genesis_block,
"AccountsHistory checkpoint below genesis, unwind to genesis needed"
);
return Ok(Some(genesis_block));
}
}
Ok(None)
}
Expand Down
6 changes: 5 additions & 1 deletion crates/storage/provider/src/providers/rocksdb/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ use reth_db::Tables;
use reth_metrics::Metrics;
use strum::{EnumIter, IntoEnumIterator};

const ROCKSDB_TABLES: &[&str] = &[Tables::TransactionHashNumbers.name()];
const ROCKSDB_TABLES: &[&str] = &[
Tables::TransactionHashNumbers.name(),
Tables::AccountsHistory.name(),
Tables::StoragesHistory.name(),
];

/// Metrics for the `RocksDB` provider.
#[derive(Debug)]
Expand Down