From e5c26233551fca77950d2f74005cb8b64ad353d4 Mon Sep 17 00:00:00 2001 From: Vui-Chee Date: Tue, 27 Jan 2026 13:36:53 +0800 Subject: [PATCH 1/7] run rocksdb --- crates/storage/db-api/src/models/metadata.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/storage/db-api/src/models/metadata.rs b/crates/storage/db-api/src/models/metadata.rs index 6fa9ea6443e..12bc04d1973 100644 --- a/crates/storage/db-api/src/models/metadata.rs +++ b/crates/storage/db-api/src/models/metadata.rs @@ -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, } } From a8501e2121be9494850d9834ff4a6c4acd4413ad Mon Sep 17 00:00:00 2001 From: Vui-Chee Date: Tue, 27 Jan 2026 14:35:42 +0800 Subject: [PATCH 2/7] pass in edge() settings for rocksdb --- crates/node/core/src/args/static_files.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/crates/node/core/src/args/static_files.rs b/crates/node/core/src/args/static_files.rs index 44116dd84b5..d2b7f52e408 100644 --- a/crates/node/core/src/args/static_files.rs +++ b/crates/node/core/src/args/static_files.rs @@ -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) + } } } From dc469855d8aa4fde10ece02b4160424b308e0c29 Mon Sep 17 00:00:00 2001 From: Vui-Chee Date: Tue, 27 Jan 2026 14:53:32 +0800 Subject: [PATCH 3/7] add table metics --- crates/storage/provider/src/providers/rocksdb/metrics.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/storage/provider/src/providers/rocksdb/metrics.rs b/crates/storage/provider/src/providers/rocksdb/metrics.rs index 890d9faac2f..18474a3bd29 100644 --- a/crates/storage/provider/src/providers/rocksdb/metrics.rs +++ b/crates/storage/provider/src/providers/rocksdb/metrics.rs @@ -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)] From 40d36ef2827b8d1b3956fd0016aff8e8783c0bd5 Mon Sep 17 00:00:00 2001 From: Vui-Chee Date: Tue, 27 Jan 2026 15:01:28 +0800 Subject: [PATCH 4/7] reveal storage settings after genesis --- crates/node/builder/src/launch/engine.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/crates/node/builder/src/launch/engine.rs b/crates/node/builder/src/launch/engine.rs index e9dd5344c4a..f4246175f3a 100644 --- a/crates/node/builder/src/launch/engine.rs +++ b/crates/node/builder/src/launch/engine.rs @@ -126,6 +126,24 @@ impl EngineNodeLauncher { .with_genesis()? .inspect(|this: &LaunchContextWith::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 From ac080d9a3cd163ccb3bf29aea8a1885cb1e0eb95 Mon Sep 17 00:00:00 2001 From: Vui-Chee Date: Tue, 27 Jan 2026 16:43:41 +0800 Subject: [PATCH 5/7] add custom genesis support for rocksdb --- crates/node/builder/src/launch/common.rs | 14 ++- .../src/providers/rocksdb/invariants.rs | 116 +++++++++++++++--- 2 files changed, 107 insertions(+), 23 deletions(-) diff --git a/crates/node/builder/src/launch/common.rs b/crates/node/builder/src/launch/common.rs index 2a3bef156f6..86dec1cfa48 100644 --- a/crates/node/builder/src/launch/common.rs +++ b/crates/node/builder/src/launch/common.rs @@ -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); diff --git a/crates/storage/provider/src/providers/rocksdb/invariants.rs b/crates/storage/provider/src/providers/rocksdb/invariants.rs index 7a5c5f9db30..119a6dd1296 100644 --- a/crates/storage/provider/src/providers/rocksdb/invariants.rs +++ b/crates/storage/provider/src/providers/rocksdb/invariants.rs @@ -56,22 +56,22 @@ impl RocksDBProvider { let mut unwind_target: Option = 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))); } @@ -99,7 +99,8 @@ impl RocksDBProvider { Provider: DBProvider + StageCheckpointReader + StaticFileProviderFactory - + TransactionsProvider, + + TransactionsProvider + + ChainSpecProvider, { // Get the TransactionLookup stage checkpoint let checkpoint = provider @@ -167,12 +168,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)); + } } } } @@ -239,7 +265,7 @@ impl RocksDBProvider { provider: &Provider, ) -> ProviderResult> where - Provider: DBProvider + StageCheckpointReader, + Provider: DBProvider + StageCheckpointReader + ChainSpecProvider, { // Get the IndexStorageHistory stage checkpoint let checkpoint = provider @@ -298,8 +324,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) } @@ -353,7 +405,7 @@ impl RocksDBProvider { provider: &Provider, ) -> ProviderResult> where - Provider: DBProvider + StageCheckpointReader, + Provider: DBProvider + StageCheckpointReader + ChainSpecProvider, { // Get the IndexAccountHistory stage checkpoint let checkpoint = provider @@ -415,8 +467,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) } From 075e3b7f7abaa7d2d30b1376f5b99dbe021db706 Mon Sep 17 00:00:00 2001 From: Vui-Chee Date: Tue, 27 Jan 2026 16:53:12 +0800 Subject: [PATCH 6/7] missing ChainSpecProvider --- crates/storage/provider/src/providers/rocksdb/invariants.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/storage/provider/src/providers/rocksdb/invariants.rs b/crates/storage/provider/src/providers/rocksdb/invariants.rs index 119a6dd1296..b28764971f3 100644 --- a/crates/storage/provider/src/providers/rocksdb/invariants.rs +++ b/crates/storage/provider/src/providers/rocksdb/invariants.rs @@ -17,6 +17,7 @@ use reth_storage_api::{ DBProvider, StageCheckpointReader, StorageSettingsCache, TransactionsProvider, }; use reth_storage_errors::provider::ProviderResult; +use reth_chainspec::ChainSpecProvider; impl RocksDBProvider { /// Checks consistency of `RocksDB` tables against MDBX stage checkpoints. From 56478f7097c853d1e09a432d84c15626260371dc Mon Sep 17 00:00:00 2001 From: Vui-Chee Date: Wed, 28 Jan 2026 10:09:34 +0800 Subject: [PATCH 7/7] fix compile issue with rocksdb invariants --- crates/storage/provider/src/providers/rocksdb/invariants.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/storage/provider/src/providers/rocksdb/invariants.rs b/crates/storage/provider/src/providers/rocksdb/invariants.rs index b28764971f3..d00d5fb2c38 100644 --- a/crates/storage/provider/src/providers/rocksdb/invariants.rs +++ b/crates/storage/provider/src/providers/rocksdb/invariants.rs @@ -17,7 +17,7 @@ use reth_storage_api::{ DBProvider, StageCheckpointReader, StorageSettingsCache, TransactionsProvider, }; use reth_storage_errors::provider::ProviderResult; -use reth_chainspec::ChainSpecProvider; +use reth_chainspec::{ChainSpecProvider, EthChainSpec}; impl RocksDBProvider { /// Checks consistency of `RocksDB` tables against MDBX stage checkpoints. @@ -52,7 +52,8 @@ impl RocksDBProvider { + StageCheckpointReader + StorageSettingsCache + StaticFileProviderFactory - + TransactionsProvider, + + TransactionsProvider + + ChainSpecProvider, { let mut unwind_target: Option = None;