fix: throw error if genesis header found on static files, but empty db (#13157)

This commit is contained in:
joshieDo
2024-12-06 09:05:10 +00:00
committed by GitHub
parent 6453b62094
commit 242bbaa9c4
2 changed files with 30 additions and 18 deletions

View File

@ -14,7 +14,7 @@ use reth_beacon_consensus::EthBeaconConsensus;
use reth_chainspec::{Chain, EthChainSpec, EthereumHardforks}; use reth_chainspec::{Chain, EthChainSpec, EthereumHardforks};
use reth_config::{config::EtlConfig, PruneConfig}; use reth_config::{config::EtlConfig, PruneConfig};
use reth_db_api::{database::Database, database_metrics::DatabaseMetrics}; 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_downloaders::{bodies::noop::NoopBodiesDownloader, headers::noop::NoopHeaderDownloader};
use reth_engine_local::MiningMode; use reth_engine_local::MiningMode;
use reth_engine_tree::tree::{InvalidBlockHook, InvalidBlockHooks, NoopInvalidBlockHook}; use reth_engine_tree::tree::{InvalidBlockHook, InvalidBlockHooks, NoopInvalidBlockHook};
@ -542,13 +542,13 @@ where
} }
/// Convenience function to [`Self::init_genesis`] /// 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())?; init_genesis(self.provider_factory())?;
Ok(self) Ok(self)
} }
/// Write the genesis block and state if it has not already been written /// 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()) init_genesis(self.provider_factory())
} }

View File

@ -16,8 +16,8 @@ use reth_provider::{
errors::provider::ProviderResult, providers::StaticFileWriter, writer::UnifiedStorageWriter, errors::provider::ProviderResult, providers::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, StateWriter, OriginalValuesKnown, ProviderError, RevertsInit, StageCheckpointReader, StageCheckpointWriter,
StaticFileProviderFactory, StorageLocation, TrieWriter, StateWriter, StaticFileProviderFactory, StorageLocation, TrieWriter,
}; };
use reth_stages_types::{StageCheckpoint, StageId}; use reth_stages_types::{StageCheckpoint, StageId};
use reth_trie::{IntermediateStateRootState, StateRoot as StateRootComputer, StateRootProgress}; use reth_trie::{IntermediateStateRootState, StateRoot as StateRootComputer, StateRootProgress};
@ -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. /// Soft limit for the number of flushed updates after which to log progress summary.
const SOFT_LIMIT_COUNT_FLUSHED_UPDATES: usize = 1_000_000; 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)] #[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 /// An existing genesis block was found in the database, and its hash did not match the hash of
/// the chainspec. /// 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 { GenesisHashMismatch {
/// Expected genesis hash. /// Expected genesis hash.
chainspec_hash: B256, chainspec_hash: B256,
/// Actual genesis hash. /// Actual genesis hash.
database_hash: B256, storage_hash: B256,
}, },
/// Provider error. /// Provider error.
#[error(transparent)] #[error(transparent)]
@ -63,18 +66,19 @@ pub enum InitDatabaseError {
StateRootMismatch(GotExpected<B256>), StateRootMismatch(GotExpected<B256>),
} }
impl From<DatabaseError> for InitDatabaseError { impl From<DatabaseError> for InitStorageError {
fn from(error: DatabaseError) -> Self { fn from(error: DatabaseError) -> Self {
Self::Provider(ProviderError::Database(error)) Self::Provider(ProviderError::Database(error))
} }
} }
/// Write the genesis block if it has not already been written /// 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 where
PF: DatabaseProviderFactory PF: DatabaseProviderFactory
+ StaticFileProviderFactory<Primitives: NodePrimitives<BlockHeader: Compact>> + StaticFileProviderFactory<Primitives: NodePrimitives<BlockHeader: Compact>>
+ ChainSpecProvider + ChainSpecProvider
+ StageCheckpointReader
+ BlockHashReader, + BlockHashReader,
PF::ProviderRW: StaticFileProviderFactory<Primitives = PF::Primitives> PF::ProviderRW: StaticFileProviderFactory<Primitives = PF::Primitives>
+ StageCheckpointWriter + StageCheckpointWriter
@ -96,13 +100,21 @@ where
Ok(None) | Err(ProviderError::MissingStaticFileBlock(StaticFileSegment::Headers, 0)) => {} Ok(None) | Err(ProviderError::MissingStaticFileBlock(StaticFileSegment::Headers, 0)) => {}
Ok(Some(block_hash)) => { Ok(Some(block_hash)) => {
if block_hash == 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."); debug!("Genesis already written, skipping.");
return Ok(hash) return Ok(hash)
} }
return Err(InitDatabaseError::GenesisHashMismatch { return Err(InitStorageError::GenesisHashMismatch {
chainspec_hash: hash, chainspec_hash: hash,
database_hash: block_hash, storage_hash: block_hash,
}) })
} }
Err(e) => { Err(e) => {
@ -376,7 +388,7 @@ where
?expected_state_root, ?expected_state_root,
"State root from state dump does not match state root in current header." "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, got: dump_state_root,
expected: expected_state_root, expected: expected_state_root,
}) })
@ -409,7 +421,7 @@ where
"Computed state root does not match state root in state dump" "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, got: computed_state_root,
expected: expected_state_root, expected: expected_state_root,
}) })
@ -622,7 +634,7 @@ mod tests {
fn collect_table_entries<DB, T>( fn collect_table_entries<DB, T>(
tx: &<DB as Database>::TX, tx: &<DB as Database>::TX,
) -> Result<Vec<TableRow<T>>, InitDatabaseError> ) -> Result<Vec<TableRow<T>>, InitStorageError>
where where
DB: Database, DB: Database,
T: Table, T: Table,
@ -672,9 +684,9 @@ mod tests {
assert_eq!( assert_eq!(
genesis_hash.unwrap_err(), genesis_hash.unwrap_err(),
InitDatabaseError::GenesisHashMismatch { InitStorageError::GenesisHashMismatch {
chainspec_hash: MAINNET_GENESIS_HASH, chainspec_hash: MAINNET_GENESIS_HASH,
database_hash: SEPOLIA_GENESIS_HASH storage_hash: SEPOLIA_GENESIS_HASH
} }
) )
} }