mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
fix: throw error if genesis header found on static files, but empty db (#13157)
This commit is contained in:
@ -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};
|
||||
@ -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())
|
||||
}
|
||||
|
||||
|
||||
@ -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};
|
||||
@ -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)]
|
||||
@ -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
|
||||
@ -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) => {
|
||||
@ -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,
|
||||
})
|
||||
@ -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,
|
||||
})
|
||||
@ -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,
|
||||
@ -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
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user