chore: check genesis mismatch in init_genesis (#1560)

This commit is contained in:
Tom French
2023-02-27 13:08:20 +00:00
committed by GitHub
parent 2d0699e98a
commit 7275f8d922
3 changed files with 47 additions and 20 deletions

View File

@ -49,16 +49,7 @@ impl InitCommand {
info!(target: "reth::cli", "Database opened");
info!(target: "reth::cli", "Writing genesis block");
let genesis_hash = init_genesis(db, self.chain.clone())?;
if genesis_hash != self.chain.genesis_hash() {
// TODO: better error text
return Err(eyre::eyre!(
"Genesis hash mismatch: expected {}, got {}",
self.chain.genesis_hash(),
genesis_hash
))
}
init_genesis(db, self.chain.clone())?;
Ok(())
}

View File

@ -41,7 +41,7 @@ tracing = "0.1.37"
rand = { version = "0.8", optional = true }
# errors
thiserror = { version = "1", optional = true }
thiserror = "1"
# enr
enr = { version = "0.7.0", features = ["serde", "rust-secp256k1"], optional = true }
@ -89,7 +89,6 @@ test-utils = [
"dep:enr",
"dep:ethers-core",
"dep:tempfile",
"dep:thiserror",
"dep:hex",
"dep:rand",
"dep:tokio",

View File

@ -21,16 +21,39 @@ pub fn init_db<P: AsRef<Path>>(path: P) -> eyre::Result<Env<WriteMap>> {
Ok(db)
}
/// Database initialization error type.
#[derive(Debug, thiserror::Error, PartialEq, Eq, Clone)]
pub enum InitDatabaseError {
/// Attempted to reinitialize database with inconsistent genesis block
#[error("Genesis hash mismatch: expected {expected}, got {actual}")]
GenesisHashMismatch { expected: H256, actual: H256 },
/// Low-level database error.
#[error(transparent)]
DBError(#[from] reth_db::Error),
}
/// Write the genesis block if it has not already been written
#[allow(clippy::field_reassign_with_default)]
pub fn init_genesis<DB: Database>(db: Arc<DB>, chain: ChainSpec) -> Result<H256, reth_db::Error> {
pub fn init_genesis<DB: Database>(
db: Arc<DB>,
chain: ChainSpec,
) -> Result<H256, InitDatabaseError> {
let genesis = chain.genesis();
let header = chain.genesis_header();
let hash = header.hash_slow();
let tx = db.tx()?;
if let Some((_, hash)) = tx.cursor_read::<tables::CanonicalHeaders>()?.first()? {
if let Some((_, db_hash)) = tx.cursor_read::<tables::CanonicalHeaders>()?.first()? {
if db_hash == hash {
debug!("Genesis already written, skipping.");
return Ok(hash)
}
return Err(InitDatabaseError::GenesisHashMismatch { expected: hash, actual: db_hash })
}
drop(tx);
debug!("Writing genesis block.");
let tx = db.tx_mut()?;
@ -48,9 +71,6 @@ pub fn init_genesis<DB: Database>(db: Arc<DB>, chain: ChainSpec) -> Result<H256,
}
// Insert header
let header = chain.genesis_header();
let hash = header.hash_slow();
tx.put::<tables::CanonicalHeaders>(0, hash)?;
tx.put::<tables::HeaderNumbers>(hash, 0)?;
tx.put::<tables::BlockBodies>(0, Default::default())?;
@ -65,7 +85,7 @@ pub fn init_genesis<DB: Database>(db: Arc<DB>, chain: ChainSpec) -> Result<H256,
#[cfg(test)]
mod tests {
use super::init_genesis;
use super::{init_genesis, InitDatabaseError};
use reth_db::mdbx::test_utils::create_test_rw_db;
use reth_primitives::{
GOERLI, GOERLI_GENESIS, MAINNET, MAINNET_GENESIS, SEPOLIA, SEPOLIA_GENESIS,
@ -97,4 +117,21 @@ mod tests {
// actual, expected
assert_eq!(genesis_hash, SEPOLIA_GENESIS);
}
#[test]
fn fail_init_inconsistent_db() {
let db = create_test_rw_db();
init_genesis(db.clone(), SEPOLIA.clone()).unwrap();
// Try to init db with a different genesis block
let genesis_hash = init_genesis(db, MAINNET.clone());
assert_eq!(
genesis_hash.unwrap_err(),
InitDatabaseError::GenesisHashMismatch {
expected: MAINNET_GENESIS,
actual: SEPOLIA_GENESIS
}
)
}
}