Skip to content

Commit

Permalink
Check the database format before Zebra shuts down
Browse files Browse the repository at this point in the history
  • Loading branch information
teor2345 committed Sep 21, 2023
1 parent 48d1329 commit 1878581
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ impl DbFormatChange {

/// Run a format change in the database, or check the format of the database once.
#[allow(clippy::unwrap_in_result)]
fn run_format_change_or_check(
pub(crate) fn run_format_change_or_check(
&self,
config: &Config,
network: Network,
Expand Down
47 changes: 46 additions & 1 deletion zebra-state/src/service/finalized_state/zebra_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
//! The [`crate::constants::DATABASE_FORMAT_VERSION`] constant must
//! be incremented each time the database format (column, serialization, etc) changes.
use std::path::Path;
use std::{
path::Path,
sync::{mpsc, Arc},
};

use zebra_chain::parameters::Network;

Expand Down Expand Up @@ -46,6 +49,11 @@ pub struct ZebraDb {
// This configuration cannot be modified after the database is initialized,
// because some clones would have different values.
//
/// The configuration for the database.
//
// TODO: use the database and version paths instead, and refactor the upgrade code to use paths
config: Arc<Config>,

/// Should format upgrades and format checks be skipped for this instance?
/// Only used in test code.
debug_skip_format_upgrades: bool,
Expand Down Expand Up @@ -82,6 +90,7 @@ impl ZebraDb {

// Open the database and do initial checks.
let mut db = ZebraDb {
config: Arc::new(config.clone()),
debug_skip_format_upgrades,
format_change_handle: None,
// After the database directory is created, a newly created database temporarily
Expand Down Expand Up @@ -169,6 +178,42 @@ impl ZebraDb {
if let Some(format_change_handle) = self.format_change_handle.as_mut() {
format_change_handle.force_cancel();
}

// # Correctness
//
// Check that the database format is correct before shutting down.
// This lets users know to delete and re-sync their database immediately,
// rather than surprising them next time Zebra starts up.
//
// # Testinng
//
// In Zebra's CI, panicking here stops us writing invalid cached states,
// which would then get make unrelated PRs fail when Zebra starts up.

// If the upgrade has completed, or we've done a downgrade, check the state is valid.
let disk_version = database_format_version_on_disk(&self.config, self.network())
.expect("unexpected invalid or unreadable database version file");

if let Some(disk_version) = disk_version {
// We need to keep the cancel handle until the format check has finished,
// because dropping it cancels the format check.
let (_never_cancel_handle, never_cancel_receiver) = mpsc::sync_channel(1);

// We block here because the checks are quick and database validity is
// consensus-critical.
if disk_version >= database_format_version_in_code() {
DbFormatChange::check_new_blocks()
.run_format_change_or_check(
&self.config,
self.network(),
// This argument is not used by the format check.
None,
self,
&never_cancel_receiver,
)
.expect("cancel handle is never used");
}
}
}

self.check_for_panics();
Expand Down

0 comments on commit 1878581

Please sign in to comment.