Skip to content

Commit

Permalink
fix: throw error if genesis header found on static files, but empty db (
Browse files Browse the repository at this point in the history
  • Loading branch information
joshieDo authored Dec 6, 2024
1 parent 6453b62 commit 242bbaa
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 18 deletions.
6 changes: 3 additions & 3 deletions crates/node/builder/src/launch/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use reth_beacon_consensus::EthBeaconConsensus;
use reth_chainspec::{Chain, EthChainSpec, EthereumHardforks};
use reth_config::{config::EtlConfig, PruneConfig};
use reth_db_api::{database::Database, database_metrics::DatabaseMetrics};
use reth_db_common::init::{init_genesis, InitDatabaseError};
use reth_db_common::init::{init_genesis, InitStorageError};
use reth_downloaders::{bodies::noop::NoopBodiesDownloader, headers::noop::NoopHeaderDownloader};
use reth_engine_local::MiningMode;
use reth_engine_tree::tree::{InvalidBlockHook, InvalidBlockHooks, NoopInvalidBlockHook};
Expand Down Expand Up @@ -542,13 +542,13 @@ where
}

/// Convenience function to [`Self::init_genesis`]
pub fn with_genesis(self) -> Result<Self, InitDatabaseError> {
pub fn with_genesis(self) -> Result<Self, InitStorageError> {
init_genesis(self.provider_factory())?;
Ok(self)
}

/// Write the genesis block and state if it has not already been written
pub fn init_genesis(&self) -> Result<B256, InitDatabaseError> {
pub fn init_genesis(&self) -> Result<B256, InitStorageError> {
init_genesis(self.provider_factory())
}

Expand Down
42 changes: 27 additions & 15 deletions crates/storage/db-common/src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use reth_provider::{
errors::provider::ProviderResult, providers::StaticFileWriter, writer::UnifiedStorageWriter,
BlockHashReader, BlockNumReader, BundleStateInit, ChainSpecProvider, DBProvider,
DatabaseProviderFactory, ExecutionOutcome, HashingWriter, HeaderProvider, HistoryWriter,
OriginalValuesKnown, ProviderError, RevertsInit, StageCheckpointWriter, StateWriter,
StaticFileProviderFactory, StorageLocation, TrieWriter,
OriginalValuesKnown, ProviderError, RevertsInit, StageCheckpointReader, StageCheckpointWriter,
StateWriter, StaticFileProviderFactory, StorageLocation, TrieWriter,
};
use reth_stages_types::{StageCheckpoint, StageId};
use reth_trie::{IntermediateStateRootState, StateRoot as StateRootComputer, StateRootProgress};
Expand All @@ -43,17 +43,20 @@ pub const AVERAGE_COUNT_ACCOUNTS_PER_GB_STATE_DUMP: usize = 285_228;
/// Soft limit for the number of flushed updates after which to log progress summary.
const SOFT_LIMIT_COUNT_FLUSHED_UPDATES: usize = 1_000_000;

/// Database initialization error type.
/// Storage initialization error type.
#[derive(Debug, thiserror::Error, PartialEq, Eq, Clone)]
pub enum InitDatabaseError {
pub enum InitStorageError {
/// Genesis header found on static files but the database is empty.
#[error("static files found, but the database is uninitialized. If attempting to re-syncing, delete both.")]
UninitializedDatabase,
/// An existing genesis block was found in the database, and its hash did not match the hash of
/// the chainspec.
#[error("genesis hash in the database does not match the specified chainspec: chainspec is {chainspec_hash}, database is {database_hash}")]
#[error("genesis hash in the storage does not match the specified chainspec: chainspec is {chainspec_hash}, database is {storage_hash}")]
GenesisHashMismatch {
/// Expected genesis hash.
chainspec_hash: B256,
/// Actual genesis hash.
database_hash: B256,
storage_hash: B256,
},
/// Provider error.
#[error(transparent)]
Expand All @@ -63,18 +66,19 @@ pub enum InitDatabaseError {
StateRootMismatch(GotExpected<B256>),
}

impl From<DatabaseError> for InitDatabaseError {
impl From<DatabaseError> for InitStorageError {
fn from(error: DatabaseError) -> Self {
Self::Provider(ProviderError::Database(error))
}
}

/// Write the genesis block if it has not already been written
pub fn init_genesis<PF>(factory: &PF) -> Result<B256, InitDatabaseError>
pub fn init_genesis<PF>(factory: &PF) -> Result<B256, InitStorageError>
where
PF: DatabaseProviderFactory
+ StaticFileProviderFactory<Primitives: NodePrimitives<BlockHeader: Compact>>
+ ChainSpecProvider
+ StageCheckpointReader
+ BlockHashReader,
PF::ProviderRW: StaticFileProviderFactory<Primitives = PF::Primitives>
+ StageCheckpointWriter
Expand All @@ -96,13 +100,21 @@ where
Ok(None) | Err(ProviderError::MissingStaticFileBlock(StaticFileSegment::Headers, 0)) => {}
Ok(Some(block_hash)) => {
if block_hash == hash {
// Some users will at times attempt to re-sync from scratch by just deleting the
// database. Since `factory.block_hash` will only query the static files, we need to
// make sure that our database has been written to, and throw error if it's empty.
if factory.get_stage_checkpoint(StageId::Headers)?.is_none() {
error!(target: "reth::storage", "Genesis header found on static files, but database is uninitialized.");
return Err(InitStorageError::UninitializedDatabase)
}

debug!("Genesis already written, skipping.");
return Ok(hash)
}

return Err(InitDatabaseError::GenesisHashMismatch {
return Err(InitStorageError::GenesisHashMismatch {
chainspec_hash: hash,
database_hash: block_hash,
storage_hash: block_hash,
})
}
Err(e) => {
Expand Down Expand Up @@ -376,7 +388,7 @@ where
?expected_state_root,
"State root from state dump does not match state root in current header."
);
return Err(InitDatabaseError::StateRootMismatch(GotExpected {
return Err(InitStorageError::StateRootMismatch(GotExpected {
got: dump_state_root,
expected: expected_state_root,
})
Expand Down Expand Up @@ -409,7 +421,7 @@ where
"Computed state root does not match state root in state dump"
);

return Err(InitDatabaseError::StateRootMismatch(GotExpected {
return Err(InitStorageError::StateRootMismatch(GotExpected {
got: computed_state_root,
expected: expected_state_root,
})
Expand Down Expand Up @@ -622,7 +634,7 @@ mod tests {

fn collect_table_entries<DB, T>(
tx: &<DB as Database>::TX,
) -> Result<Vec<TableRow<T>>, InitDatabaseError>
) -> Result<Vec<TableRow<T>>, InitStorageError>
where
DB: Database,
T: Table,
Expand Down Expand Up @@ -672,9 +684,9 @@ mod tests {

assert_eq!(
genesis_hash.unwrap_err(),
InitDatabaseError::GenesisHashMismatch {
InitStorageError::GenesisHashMismatch {
chainspec_hash: MAINNET_GENESIS_HASH,
database_hash: SEPOLIA_GENESIS_HASH
storage_hash: SEPOLIA_GENESIS_HASH
}
)
}
Expand Down

0 comments on commit 242bbaa

Please sign in to comment.