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_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())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user