change(state): Expose ZebraDb methods that can create different kinds of databases (#8002)
* Provide access to DiskDb and DiskWriteBatch outside the state using a feature * Actually let's export ZebraDb for the format upgrade code * Pass column families to ZebraDb as an argument * Allow the database kind to be changed in config.rs * Use the state kind in finalized_state.rs * Allow different database kinds in ZebraDb, but don't move the upgrade code yet * Allow different database kinds in DiskDb * Allow different database kinds in upgrade.rs, but don't split the upgrade code out yet * Add new arguments to raw database tests * Fix doc links * Fix internal imports * Fix unused code * Update zebrad version metadata * Create a specific state database delete function * Fix state exports * Fix zebrad tests * Fix zebrad state write tests * Make CI run again * Fix dead code warnings for test methods * Remove unnecessary async on some tests * Fix logging required by tests * Fix logging required in test itself * Fix variable names * Try to copy the message and add regexes
This commit is contained in:
parent
35a7764b01
commit
1d241afbaa
|
|
@ -35,6 +35,9 @@ proptest-impl = [
|
|||
"zebra-chain/proptest-impl"
|
||||
]
|
||||
|
||||
# Experimental shielded blockchain scanning
|
||||
shielded-scan = []
|
||||
|
||||
# Experimental elasticsearch support
|
||||
elasticsearch = [
|
||||
"dep:elasticsearch",
|
||||
|
|
|
|||
|
|
@ -15,11 +15,8 @@ use tracing::Span;
|
|||
use zebra_chain::parameters::Network;
|
||||
|
||||
use crate::{
|
||||
constants::{
|
||||
DATABASE_FORMAT_MINOR_VERSION, DATABASE_FORMAT_PATCH_VERSION, DATABASE_FORMAT_VERSION,
|
||||
DATABASE_FORMAT_VERSION_FILE_NAME,
|
||||
},
|
||||
BoxError,
|
||||
constants::{DATABASE_FORMAT_VERSION_FILE_NAME, STATE_DATABASE_KIND},
|
||||
state_database_format_version_in_code, BoxError,
|
||||
};
|
||||
|
||||
/// Configuration for the state service.
|
||||
|
|
@ -128,27 +125,37 @@ fn gen_temp_path(prefix: &str) -> PathBuf {
|
|||
}
|
||||
|
||||
impl Config {
|
||||
/// Returns the path for the finalized state database
|
||||
pub fn db_path(&self, network: Network) -> PathBuf {
|
||||
/// Returns the path for the database, based on the kind, major version and network.
|
||||
/// Each incompatible database format or network gets its own unique path.
|
||||
pub fn db_path(
|
||||
&self,
|
||||
db_kind: impl AsRef<str>,
|
||||
major_version: u64,
|
||||
network: Network,
|
||||
) -> PathBuf {
|
||||
let db_kind = db_kind.as_ref();
|
||||
let major_version = format!("v{}", major_version);
|
||||
let net_dir = network.lowercase_name();
|
||||
|
||||
if self.ephemeral {
|
||||
gen_temp_path(&format!(
|
||||
"zebra-state-v{}-{}-",
|
||||
crate::constants::DATABASE_FORMAT_VERSION,
|
||||
net_dir
|
||||
))
|
||||
gen_temp_path(&format!("zebra-{db_kind}-{major_version}-{net_dir}-"))
|
||||
} else {
|
||||
self.cache_dir
|
||||
.join("state")
|
||||
.join(format!("v{}", crate::constants::DATABASE_FORMAT_VERSION))
|
||||
.join(db_kind)
|
||||
.join(major_version)
|
||||
.join(net_dir)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the path of the database format version file.
|
||||
pub fn version_file_path(&self, network: Network) -> PathBuf {
|
||||
let mut version_path = self.db_path(network);
|
||||
/// Returns the path for the database format minor/patch version file,
|
||||
/// based on the kind, major version and network.
|
||||
pub fn version_file_path(
|
||||
&self,
|
||||
db_kind: impl AsRef<str>,
|
||||
major_version: u64,
|
||||
network: Network,
|
||||
) -> PathBuf {
|
||||
let mut version_path = self.db_path(db_kind, major_version, network);
|
||||
|
||||
version_path.push(DATABASE_FORMAT_VERSION_FILE_NAME);
|
||||
|
||||
|
|
@ -189,21 +196,48 @@ impl Default for Config {
|
|||
// Cleaning up old database versions
|
||||
// TODO: put this in a different module?
|
||||
|
||||
/// Spawns a task that checks if there are old state database folders,
|
||||
/// and deletes them from the filesystem.
|
||||
///
|
||||
/// See `check_and_delete_old_databases()` for details.
|
||||
pub fn check_and_delete_old_state_databases(config: &Config, network: Network) -> JoinHandle<()> {
|
||||
check_and_delete_old_databases(
|
||||
config,
|
||||
STATE_DATABASE_KIND,
|
||||
state_database_format_version_in_code().major,
|
||||
network,
|
||||
)
|
||||
}
|
||||
|
||||
/// Spawns a task that checks if there are old database folders,
|
||||
/// and deletes them from the filesystem.
|
||||
///
|
||||
/// Iterate over the files and directories in the databases folder and delete if:
|
||||
/// - The state directory exists.
|
||||
/// - The entry is a directory.
|
||||
/// - The `db_kind` directory exists.
|
||||
/// - The entry in `db_kind` is a directory.
|
||||
/// - The directory name has a prefix `v`.
|
||||
/// - The directory name without the prefix can be parsed as an unsigned number.
|
||||
/// - The parsed number is lower than the hardcoded `DATABASE_FORMAT_VERSION`.
|
||||
pub fn check_and_delete_old_databases(config: Config) -> JoinHandle<()> {
|
||||
/// - The parsed number is lower than the `major_version`.
|
||||
///
|
||||
/// The network is used to generate the path, then ignored.
|
||||
/// If `config` is an ephemeral database, no databases are deleted.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If the path doesn't match the expected `db_kind/major_version/network` format.
|
||||
pub fn check_and_delete_old_databases(
|
||||
config: &Config,
|
||||
db_kind: impl AsRef<str>,
|
||||
major_version: u64,
|
||||
network: Network,
|
||||
) -> JoinHandle<()> {
|
||||
let current_span = Span::current();
|
||||
let config = config.clone();
|
||||
let db_kind = db_kind.as_ref().to_string();
|
||||
|
||||
spawn_blocking(move || {
|
||||
current_span.in_scope(|| {
|
||||
delete_old_databases(config);
|
||||
delete_old_databases(config, db_kind, major_version, network);
|
||||
info!("finished old database version cleanup task");
|
||||
})
|
||||
})
|
||||
|
|
@ -212,20 +246,43 @@ pub fn check_and_delete_old_databases(config: Config) -> JoinHandle<()> {
|
|||
/// Check if there are old database folders and delete them from the filesystem.
|
||||
///
|
||||
/// See [`check_and_delete_old_databases`] for details.
|
||||
fn delete_old_databases(config: Config) {
|
||||
fn delete_old_databases(config: Config, db_kind: String, major_version: u64, network: Network) {
|
||||
if config.ephemeral || !config.delete_old_database {
|
||||
return;
|
||||
}
|
||||
|
||||
info!("checking for old database versions");
|
||||
info!(db_kind, "checking for old database versions");
|
||||
|
||||
let state_dir = config.cache_dir.join("state");
|
||||
if let Some(state_dir) = read_dir(&state_dir) {
|
||||
for entry in state_dir.flatten() {
|
||||
let deleted_state = check_and_delete_database(&config, &entry);
|
||||
let mut db_path = config.db_path(&db_kind, major_version, network);
|
||||
// Check and remove the network path.
|
||||
assert_eq!(
|
||||
db_path.file_name(),
|
||||
Some(network.lowercase_name().as_ref()),
|
||||
"unexpected database network path structure"
|
||||
);
|
||||
assert!(db_path.pop());
|
||||
|
||||
if let Some(deleted_state) = deleted_state {
|
||||
info!(?deleted_state, "deleted outdated state directory");
|
||||
// Check and remove the major version path, we'll iterate over them all below.
|
||||
assert_eq!(
|
||||
db_path.file_name(),
|
||||
Some(format!("v{major_version}").as_ref()),
|
||||
"unexpected database version path structure"
|
||||
);
|
||||
assert!(db_path.pop());
|
||||
|
||||
// Check for the correct database kind to iterate within.
|
||||
assert_eq!(
|
||||
db_path.file_name(),
|
||||
Some(db_kind.as_ref()),
|
||||
"unexpected database kind path structure"
|
||||
);
|
||||
|
||||
if let Some(db_kind_dir) = read_dir(&db_path) {
|
||||
for entry in db_kind_dir.flatten() {
|
||||
let deleted_db = check_and_delete_database(&config, major_version, &entry);
|
||||
|
||||
if let Some(deleted_db) = deleted_db {
|
||||
info!(?deleted_db, "deleted outdated {db_kind} database directory");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -247,11 +304,15 @@ fn read_dir(dir: &Path) -> Option<ReadDir> {
|
|||
/// See [`check_and_delete_old_databases`] for details.
|
||||
///
|
||||
/// If the directory was deleted, returns its path.
|
||||
fn check_and_delete_database(config: &Config, entry: &DirEntry) -> Option<PathBuf> {
|
||||
fn check_and_delete_database(
|
||||
config: &Config,
|
||||
major_version: u64,
|
||||
entry: &DirEntry,
|
||||
) -> Option<PathBuf> {
|
||||
let dir_name = parse_dir_name(entry)?;
|
||||
let version_number = parse_version_number(&dir_name)?;
|
||||
let dir_major_version = parse_major_version(&dir_name)?;
|
||||
|
||||
if version_number >= crate::constants::DATABASE_FORMAT_VERSION {
|
||||
if dir_major_version >= major_version {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
|
@ -296,10 +357,10 @@ fn parse_dir_name(entry: &DirEntry) -> Option<String> {
|
|||
None
|
||||
}
|
||||
|
||||
/// Parse the state version number from `dir_name`.
|
||||
/// Parse the database major version number from `dir_name`.
|
||||
///
|
||||
/// Returns `None` if parsing fails, or the directory name is not in the expected format.
|
||||
fn parse_version_number(dir_name: &str) -> Option<u64> {
|
||||
fn parse_major_version(dir_name: &str) -> Option<u64> {
|
||||
dir_name
|
||||
.strip_prefix('v')
|
||||
.and_then(|version| version.parse().ok())
|
||||
|
|
@ -307,23 +368,26 @@ fn parse_version_number(dir_name: &str) -> Option<u64> {
|
|||
|
||||
// TODO: move these to the format upgrade module
|
||||
|
||||
/// Returns the full semantic version of the currently running database format code.
|
||||
///
|
||||
/// This is the version implemented by the Zebra code that's currently running,
|
||||
/// the minor and patch versions on disk can be different.
|
||||
pub fn database_format_version_in_code() -> Version {
|
||||
Version::new(
|
||||
DATABASE_FORMAT_VERSION,
|
||||
DATABASE_FORMAT_MINOR_VERSION,
|
||||
DATABASE_FORMAT_PATCH_VERSION,
|
||||
/// Returns the full semantic version of the on-disk state database, based on its config and network.
|
||||
pub fn state_database_format_version_on_disk(
|
||||
config: &Config,
|
||||
network: Network,
|
||||
) -> Result<Option<Version>, BoxError> {
|
||||
database_format_version_on_disk(
|
||||
config,
|
||||
STATE_DATABASE_KIND,
|
||||
state_database_format_version_in_code().major,
|
||||
network,
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the full semantic version of the on-disk database.
|
||||
/// Returns the full semantic version of the on-disk database, based on its config, kind, major version,
|
||||
/// and network.
|
||||
///
|
||||
/// Typically, the version is read from a version text file.
|
||||
///
|
||||
/// If there is an existing on-disk database, but no version file, returns `Ok(Some(major.0.0))`.
|
||||
/// If there is an existing on-disk database, but no version file,
|
||||
/// returns `Ok(Some(major_version.0.0))`.
|
||||
/// (This happens even if the database directory was just newly created.)
|
||||
///
|
||||
/// If there is no existing on-disk database, returns `Ok(None)`.
|
||||
|
|
@ -332,12 +396,14 @@ pub fn database_format_version_in_code() -> Version {
|
|||
/// implemented by the running Zebra code can be different.
|
||||
pub fn database_format_version_on_disk(
|
||||
config: &Config,
|
||||
db_kind: impl AsRef<str>,
|
||||
major_version: u64,
|
||||
network: Network,
|
||||
) -> Result<Option<Version>, BoxError> {
|
||||
let version_path = config.version_file_path(network);
|
||||
let db_path = config.db_path(network);
|
||||
let version_path = config.version_file_path(&db_kind, major_version, network);
|
||||
let db_path = config.db_path(db_kind, major_version, network);
|
||||
|
||||
database_format_version_at_path(&version_path, &db_path)
|
||||
database_format_version_at_path(&version_path, &db_path, major_version)
|
||||
}
|
||||
|
||||
/// Returns the full semantic version of the on-disk database at `version_path`.
|
||||
|
|
@ -346,6 +412,7 @@ pub fn database_format_version_on_disk(
|
|||
pub(crate) fn database_format_version_at_path(
|
||||
version_path: &Path,
|
||||
db_path: &Path,
|
||||
major_version: u64,
|
||||
) -> Result<Option<Version>, BoxError> {
|
||||
let disk_version_file = match fs::read_to_string(version_path) {
|
||||
Ok(version) => Some(version),
|
||||
|
|
@ -363,7 +430,7 @@ pub(crate) fn database_format_version_at_path(
|
|||
.ok_or("invalid database format version file")?;
|
||||
|
||||
return Ok(Some(Version::new(
|
||||
DATABASE_FORMAT_VERSION,
|
||||
major_version,
|
||||
minor.parse()?,
|
||||
patch.parse()?,
|
||||
)));
|
||||
|
|
@ -374,7 +441,7 @@ pub(crate) fn database_format_version_at_path(
|
|||
match fs::metadata(db_path) {
|
||||
// But there is a database on disk, so it has the current major version with no upgrades.
|
||||
// If the database directory was just newly created, we also return this version.
|
||||
Ok(_metadata) => Ok(Some(Version::new(DATABASE_FORMAT_VERSION, 0, 0))),
|
||||
Ok(_metadata) => Ok(Some(Version::new(major_version, 0, 0))),
|
||||
|
||||
// There's no version file and no database on disk, so it's a new database.
|
||||
// It will be created with the current version,
|
||||
|
|
@ -386,15 +453,33 @@ pub(crate) fn database_format_version_at_path(
|
|||
}
|
||||
|
||||
// Hide this destructive method from the public API, except in tests.
|
||||
pub(crate) use hidden::write_database_format_version_to_disk;
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use hidden::{
|
||||
write_database_format_version_to_disk, write_state_database_format_version_to_disk,
|
||||
};
|
||||
|
||||
pub(crate) mod hidden {
|
||||
#![allow(dead_code)]
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Writes `changed_version` to the on-disk state database after the format is changed.
|
||||
/// (Or a new database is created.)
|
||||
///
|
||||
/// See `write_database_format_version_to_disk()` for details.
|
||||
pub fn write_state_database_format_version_to_disk(
|
||||
config: &Config,
|
||||
changed_version: &Version,
|
||||
network: Network,
|
||||
) -> Result<(), BoxError> {
|
||||
write_database_format_version_to_disk(config, STATE_DATABASE_KIND, changed_version, network)
|
||||
}
|
||||
|
||||
/// Writes `changed_version` to the on-disk database after the format is changed.
|
||||
/// (Or a new database is created.)
|
||||
///
|
||||
/// The database path is based on its kind, `changed_version.major`, and network.
|
||||
///
|
||||
/// # Correctness
|
||||
///
|
||||
/// This should only be called:
|
||||
|
|
@ -407,22 +492,13 @@ pub(crate) mod hidden {
|
|||
/// This must only be called while RocksDB has an open database for `config`.
|
||||
/// Otherwise, multiple Zebra processes could write the version at the same time,
|
||||
/// corrupting the file.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If the major versions do not match. (The format is incompatible.)
|
||||
pub fn write_database_format_version_to_disk(
|
||||
changed_version: &Version,
|
||||
config: &Config,
|
||||
db_kind: impl AsRef<str>,
|
||||
changed_version: &Version,
|
||||
network: Network,
|
||||
) -> Result<(), BoxError> {
|
||||
let version_path = config.version_file_path(network);
|
||||
|
||||
// The major version is already in the directory path.
|
||||
assert_eq!(
|
||||
changed_version.major, DATABASE_FORMAT_VERSION,
|
||||
"tried to do in-place database format change to an incompatible version"
|
||||
);
|
||||
let version_path = config.version_file_path(db_kind, changed_version.major, network);
|
||||
|
||||
let version = format!("{}.{}", changed_version.minor, changed_version.patch);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ use semver::Version;
|
|||
|
||||
// For doc comment links
|
||||
#[allow(unused_imports)]
|
||||
use crate::config::{self, Config};
|
||||
use crate::{
|
||||
config::{self, Config},
|
||||
constants,
|
||||
};
|
||||
|
||||
pub use zebra_chain::transparent::MIN_TRANSPARENT_COINBASE_MATURITY;
|
||||
|
||||
|
|
@ -27,6 +30,9 @@ pub use zebra_chain::transparent::MIN_TRANSPARENT_COINBASE_MATURITY;
|
|||
// TODO: change to HeightDiff
|
||||
pub const MAX_BLOCK_REORG_HEIGHT: u32 = MIN_TRANSPARENT_COINBASE_MATURITY - 1;
|
||||
|
||||
/// The directory name used to distinguish the state database from Zebra's other databases or flat files.
|
||||
pub const STATE_DATABASE_KIND: &str = "state";
|
||||
|
||||
/// The database format major version, incremented each time the on-disk database format has a
|
||||
/// breaking data format change.
|
||||
///
|
||||
|
|
@ -38,9 +44,9 @@ pub const MAX_BLOCK_REORG_HEIGHT: u32 = MIN_TRANSPARENT_COINBASE_MATURITY - 1;
|
|||
/// - we previously added compatibility code, and
|
||||
/// - it's available in all supported Zebra versions.
|
||||
///
|
||||
/// Use [`config::database_format_version_in_code()`] or
|
||||
/// [`config::database_format_version_on_disk()`] to get the full semantic format version.
|
||||
pub(crate) const DATABASE_FORMAT_VERSION: u64 = 25;
|
||||
/// Instead of using this constant directly, use [`constants::state_database_format_version_in_code()`]
|
||||
/// or [`config::database_format_version_on_disk()`] to get the full semantic format version.
|
||||
const DATABASE_FORMAT_VERSION: u64 = 25;
|
||||
|
||||
/// The database format minor version, incremented each time the on-disk database format has a
|
||||
/// significant data format change.
|
||||
|
|
@ -49,11 +55,23 @@ pub(crate) const DATABASE_FORMAT_VERSION: u64 = 25;
|
|||
/// - adding new column families,
|
||||
/// - changing the format of a column family in a compatible way, or
|
||||
/// - breaking changes with compatibility code in all supported Zebra versions.
|
||||
pub(crate) const DATABASE_FORMAT_MINOR_VERSION: u64 = 3;
|
||||
const DATABASE_FORMAT_MINOR_VERSION: u64 = 3;
|
||||
|
||||
/// The database format patch version, incremented each time the on-disk database format has a
|
||||
/// significant format compatibility fix.
|
||||
pub(crate) const DATABASE_FORMAT_PATCH_VERSION: u64 = 0;
|
||||
const DATABASE_FORMAT_PATCH_VERSION: u64 = 0;
|
||||
|
||||
/// Returns the full semantic version of the currently running state database format code.
|
||||
///
|
||||
/// This is the version implemented by the Zebra code that's currently running,
|
||||
/// the minor and patch versions on disk can be different.
|
||||
pub fn state_database_format_version_in_code() -> Version {
|
||||
Version::new(
|
||||
DATABASE_FORMAT_VERSION,
|
||||
DATABASE_FORMAT_MINOR_VERSION,
|
||||
DATABASE_FORMAT_PATCH_VERSION,
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the highest database version that modifies the subtree index format.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -40,10 +40,10 @@ mod service;
|
|||
mod tests;
|
||||
|
||||
pub use config::{
|
||||
check_and_delete_old_databases, database_format_version_in_code,
|
||||
database_format_version_on_disk, Config,
|
||||
check_and_delete_old_databases, check_and_delete_old_state_databases,
|
||||
database_format_version_on_disk, state_database_format_version_on_disk, Config,
|
||||
};
|
||||
pub use constants::MAX_BLOCK_REORG_HEIGHT;
|
||||
pub use constants::{state_database_format_version_in_code, MAX_BLOCK_REORG_HEIGHT};
|
||||
pub use error::{
|
||||
BoxError, CloneError, CommitSemanticallyVerifiedError, DuplicateNullifierError,
|
||||
ValidateContextError,
|
||||
|
|
@ -59,6 +59,12 @@ pub use service::{
|
|||
OutputIndex, OutputLocation, TransactionLocation,
|
||||
};
|
||||
|
||||
#[cfg(feature = "shielded-scan")]
|
||||
pub use service::finalized_state::{ReadDisk, ZebraDb};
|
||||
|
||||
#[cfg(any(test, feature = "proptest-impl", feature = "shielded-scan"))]
|
||||
pub use service::finalized_state::{DiskWriteBatch, WriteDisk};
|
||||
|
||||
#[cfg(feature = "getblocktemplate-rpcs")]
|
||||
pub use response::GetBlockTemplateChainInfo;
|
||||
|
||||
|
|
@ -66,12 +72,20 @@ pub use response::GetBlockTemplateChainInfo;
|
|||
pub use service::{
|
||||
arbitrary::{populated_state, CHAIN_TIP_UPDATE_WAIT_LIMIT},
|
||||
chain_tip::{ChainTipBlock, ChainTipSender},
|
||||
finalized_state::{DiskWriteBatch, MAX_ON_DISK_HEIGHT},
|
||||
finalized_state::MAX_ON_DISK_HEIGHT,
|
||||
init_test, init_test_services, ReadStateService,
|
||||
};
|
||||
|
||||
#[cfg(not(any(test, feature = "proptest-impl")))]
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use config::hidden::{
|
||||
write_database_format_version_to_disk, write_state_database_format_version_to_disk,
|
||||
};
|
||||
|
||||
#[cfg(any(test, feature = "proptest-impl"))]
|
||||
pub use config::hidden::write_database_format_version_to_disk;
|
||||
pub use config::hidden::{
|
||||
write_database_format_version_to_disk, write_state_database_format_version_to_disk,
|
||||
};
|
||||
|
||||
#[cfg(any(test, feature = "proptest-impl"))]
|
||||
pub use constants::latest_version_for_adding_subtrees;
|
||||
|
|
|
|||
|
|
@ -2,9 +2,8 @@
|
|||
//!
|
||||
//! Zebra's database is implemented in 4 layers:
|
||||
//! - [`FinalizedState`]: queues, validates, and commits blocks, using...
|
||||
//! - [`ZebraDb`]: reads and writes [`zebra_chain`] types to the database, using...
|
||||
//! - [`DiskDb`](disk_db::DiskDb): reads and writes format-specific types
|
||||
//! to the database, using...
|
||||
//! - [`ZebraDb`]: reads and writes [`zebra_chain`] types to the state database, using...
|
||||
//! - [`DiskDb`]: reads and writes generic types to any column family in the database, using...
|
||||
//! - [`disk_format`]: converts types to raw database bytes.
|
||||
//!
|
||||
//! These layers allow us to split [`zebra_chain`] types for efficient database storage.
|
||||
|
|
@ -12,8 +11,8 @@
|
|||
//!
|
||||
//! # Correctness
|
||||
//!
|
||||
//! The [`crate::constants::DATABASE_FORMAT_VERSION`] constant must
|
||||
//! be incremented each time the database format (column, serialization, etc) changes.
|
||||
//! [`crate::constants::state_database_format_version_in_code()`] must be incremented
|
||||
//! each time the database format (column, serialization, etc) changes.
|
||||
|
||||
use std::{
|
||||
io::{stderr, stdout, Write},
|
||||
|
|
@ -23,6 +22,7 @@ use std::{
|
|||
use zebra_chain::{block, parallel::tree::NoteCommitmentTrees, parameters::Network};
|
||||
|
||||
use crate::{
|
||||
constants::{state_database_format_version_in_code, STATE_DATABASE_KIND},
|
||||
request::{FinalizableBlock, FinalizedBlock, Treestate},
|
||||
service::{check, QueuedCheckpointVerified},
|
||||
BoxError, CheckpointVerifiedBlock, CloneError, Config,
|
||||
|
|
@ -38,17 +38,52 @@ mod arbitrary;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
pub use disk_db::{DiskDb, DiskWriteBatch, WriteDisk};
|
||||
pub use disk_format::{OutputIndex, OutputLocation, TransactionLocation};
|
||||
pub use zebra_db::ZebraDb;
|
||||
|
||||
#[cfg(feature = "shielded-scan")]
|
||||
pub use disk_db::ReadDisk;
|
||||
|
||||
#[cfg(any(test, feature = "proptest-impl"))]
|
||||
pub use disk_format::MAX_ON_DISK_HEIGHT;
|
||||
|
||||
pub(super) use zebra_db::ZebraDb;
|
||||
|
||||
#[cfg(any(test, feature = "proptest-impl"))]
|
||||
pub use disk_db::DiskWriteBatch;
|
||||
#[cfg(not(any(test, feature = "proptest-impl")))]
|
||||
use disk_db::DiskWriteBatch;
|
||||
/// The column families supported by the running `zebra-state` database code.
|
||||
///
|
||||
/// Existing column families that aren't listed here are preserved when the database is opened.
|
||||
pub const STATE_COLUMN_FAMILIES_IN_CODE: &[&str] = &[
|
||||
// Blocks
|
||||
"hash_by_height",
|
||||
"height_by_hash",
|
||||
"block_header_by_height",
|
||||
// Transactions
|
||||
"tx_by_loc",
|
||||
"hash_by_tx_loc",
|
||||
"tx_loc_by_hash",
|
||||
// Transparent
|
||||
"balance_by_transparent_addr",
|
||||
"tx_loc_by_transparent_addr_loc",
|
||||
"utxo_by_out_loc",
|
||||
"utxo_loc_by_transparent_addr_loc",
|
||||
// Sprout
|
||||
"sprout_nullifiers",
|
||||
"sprout_anchors",
|
||||
"sprout_note_commitment_tree",
|
||||
// Sapling
|
||||
"sapling_nullifiers",
|
||||
"sapling_anchors",
|
||||
"sapling_note_commitment_tree",
|
||||
"sapling_note_commitment_subtree",
|
||||
// Orchard
|
||||
"orchard_nullifiers",
|
||||
"orchard_anchors",
|
||||
"orchard_note_commitment_tree",
|
||||
"orchard_note_commitment_subtree",
|
||||
// Chain
|
||||
"history_tree",
|
||||
"tip_chain_value_pool",
|
||||
];
|
||||
|
||||
/// The finalized part of the chain state, stored in the db.
|
||||
///
|
||||
|
|
@ -65,9 +100,6 @@ pub struct FinalizedState {
|
|||
// This configuration cannot be modified after the database is initialized,
|
||||
// because some clones would have different values.
|
||||
//
|
||||
/// The configured network.
|
||||
network: Network,
|
||||
|
||||
/// The configured stop height.
|
||||
///
|
||||
/// Commit blocks to the finalized state up to this height, then exit Zebra.
|
||||
|
|
@ -120,11 +152,19 @@ impl FinalizedState {
|
|||
debug_skip_format_upgrades: bool,
|
||||
#[cfg(feature = "elasticsearch")] elastic_db: Option<elasticsearch::Elasticsearch>,
|
||||
) -> Self {
|
||||
let db = ZebraDb::new(config, network, debug_skip_format_upgrades);
|
||||
let db = ZebraDb::new(
|
||||
config,
|
||||
STATE_DATABASE_KIND,
|
||||
&state_database_format_version_in_code(),
|
||||
network,
|
||||
debug_skip_format_upgrades,
|
||||
STATE_COLUMN_FAMILIES_IN_CODE
|
||||
.iter()
|
||||
.map(ToString::to_string),
|
||||
);
|
||||
|
||||
#[cfg(feature = "elasticsearch")]
|
||||
let new_state = Self {
|
||||
network,
|
||||
debug_stop_at_height: config.debug_stop_at_height.map(block::Height),
|
||||
db,
|
||||
elastic_db,
|
||||
|
|
@ -133,7 +173,6 @@ impl FinalizedState {
|
|||
|
||||
#[cfg(not(feature = "elasticsearch"))]
|
||||
let new_state = Self {
|
||||
network,
|
||||
debug_stop_at_height: config.debug_stop_at_height.map(block::Height),
|
||||
db,
|
||||
};
|
||||
|
|
@ -182,7 +221,7 @@ impl FinalizedState {
|
|||
|
||||
/// Returns the configured network for this database.
|
||||
pub fn network(&self) -> Network {
|
||||
self.network
|
||||
self.db.network()
|
||||
}
|
||||
|
||||
/// Commit a checkpoint-verified block to the state.
|
||||
|
|
@ -293,7 +332,7 @@ impl FinalizedState {
|
|||
// thread, if it shows up in profiles
|
||||
check::block_commitment_is_valid_for_chain_history(
|
||||
block.clone(),
|
||||
self.network,
|
||||
self.network(),
|
||||
&history_tree,
|
||||
)?;
|
||||
|
||||
|
|
@ -359,9 +398,12 @@ impl FinalizedState {
|
|||
let finalized_inner_block = finalized.block.clone();
|
||||
let note_commitment_trees = finalized.treestate.note_commitment_trees.clone();
|
||||
|
||||
let result =
|
||||
self.db
|
||||
.write_block(finalized, prev_note_commitment_trees, self.network, source);
|
||||
let result = self.db.write_block(
|
||||
finalized,
|
||||
prev_note_commitment_trees,
|
||||
self.network(),
|
||||
source,
|
||||
);
|
||||
|
||||
if result.is_ok() {
|
||||
// Save blocks to elasticsearch if the feature is enabled.
|
||||
|
|
@ -421,7 +463,7 @@ impl FinalizedState {
|
|||
// less than this number of seconds.
|
||||
const CLOSE_TO_TIP_SECONDS: i64 = 14400; // 4 hours
|
||||
|
||||
let mut blocks_size_to_dump = match self.network {
|
||||
let mut blocks_size_to_dump = match self.network() {
|
||||
Network::Mainnet => MAINNET_AWAY_FROM_TIP_BULK_SIZE,
|
||||
Network::Testnet => TESTNET_AWAY_FROM_TIP_BULK_SIZE,
|
||||
};
|
||||
|
|
@ -451,7 +493,7 @@ impl FinalizedState {
|
|||
let rt = tokio::runtime::Runtime::new()
|
||||
.expect("runtime creation for elasticsearch should not fail.");
|
||||
let blocks = self.elastic_blocks.clone();
|
||||
let network = self.network;
|
||||
let network = self.network();
|
||||
|
||||
rt.block_on(async move {
|
||||
let response = client
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@
|
|||
//!
|
||||
//! # Correctness
|
||||
//!
|
||||
//! The [`crate::constants::DATABASE_FORMAT_VERSION`] constants must
|
||||
//! be incremented each time the database format (column, serialization, etc) changes.
|
||||
//! [`crate::constants::state_database_format_version_in_code()`] must be incremented
|
||||
//! each time the database format (column, serialization, etc) changes.
|
||||
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
|
|
@ -22,6 +22,7 @@ use itertools::Itertools;
|
|||
use rlimit::increase_nofile_limit;
|
||||
|
||||
use rocksdb::ReadOptions;
|
||||
use semver::Version;
|
||||
use zebra_chain::parameters::Network;
|
||||
|
||||
use crate::{
|
||||
|
|
@ -65,6 +66,12 @@ pub struct DiskDb {
|
|||
// This configuration cannot be modified after the database is initialized,
|
||||
// because some clones would have different values.
|
||||
//
|
||||
/// The configured database kind for this database.
|
||||
db_kind: String,
|
||||
|
||||
/// The format version of the running Zebra code.
|
||||
format_version_in_code: Version,
|
||||
|
||||
/// The configured network for this database.
|
||||
network: Network,
|
||||
|
||||
|
|
@ -93,10 +100,6 @@ pub struct DiskDb {
|
|||
///
|
||||
/// [`rocksdb::WriteBatch`] is a batched set of database updates,
|
||||
/// which must be written to the database using `DiskDb::write(batch)`.
|
||||
//
|
||||
// TODO: move DiskDb, FinalizedBlock, and the source String into this struct,
|
||||
// (DiskDb can be cloned),
|
||||
// and make them accessible via read-only methods
|
||||
#[must_use = "batches must be written to the database"]
|
||||
#[derive(Default)]
|
||||
pub struct DiskWriteBatch {
|
||||
|
|
@ -617,44 +620,18 @@ impl DiskDb {
|
|||
/// <https://github.com/facebook/rocksdb/wiki/RocksDB-FAQ#configuration-and-tuning>
|
||||
const MEMTABLE_RAM_CACHE_MEGABYTES: usize = 128;
|
||||
|
||||
/// The column families supported by the running database code.
|
||||
const COLUMN_FAMILIES_IN_CODE: &'static [&'static str] = &[
|
||||
// Blocks
|
||||
"hash_by_height",
|
||||
"height_by_hash",
|
||||
"block_header_by_height",
|
||||
// Transactions
|
||||
"tx_by_loc",
|
||||
"hash_by_tx_loc",
|
||||
"tx_loc_by_hash",
|
||||
// Transparent
|
||||
"balance_by_transparent_addr",
|
||||
"tx_loc_by_transparent_addr_loc",
|
||||
"utxo_by_out_loc",
|
||||
"utxo_loc_by_transparent_addr_loc",
|
||||
// Sprout
|
||||
"sprout_nullifiers",
|
||||
"sprout_anchors",
|
||||
"sprout_note_commitment_tree",
|
||||
// Sapling
|
||||
"sapling_nullifiers",
|
||||
"sapling_anchors",
|
||||
"sapling_note_commitment_tree",
|
||||
"sapling_note_commitment_subtree",
|
||||
// Orchard
|
||||
"orchard_nullifiers",
|
||||
"orchard_anchors",
|
||||
"orchard_note_commitment_tree",
|
||||
"orchard_note_commitment_subtree",
|
||||
// Chain
|
||||
"history_tree",
|
||||
"tip_chain_value_pool",
|
||||
];
|
||||
|
||||
/// Opens or creates the database at `config.path` for `network`,
|
||||
/// Opens or creates the database at a path based on the kind, major version and network,
|
||||
/// with the supplied column families, preserving any existing column families,
|
||||
/// and returns a shared low-level database wrapper.
|
||||
pub fn new(config: &Config, network: Network) -> DiskDb {
|
||||
let path = config.db_path(network);
|
||||
pub fn new(
|
||||
config: &Config,
|
||||
db_kind: impl AsRef<str>,
|
||||
format_version_in_code: &Version,
|
||||
network: Network,
|
||||
column_families_in_code: impl IntoIterator<Item = String>,
|
||||
) -> DiskDb {
|
||||
let db_kind = db_kind.as_ref();
|
||||
let path = config.db_path(db_kind, format_version_in_code.major, network);
|
||||
|
||||
let db_options = DiskDb::options();
|
||||
|
||||
|
|
@ -666,9 +643,7 @@ impl DiskDb {
|
|||
//
|
||||
// <https://github.com/facebook/rocksdb/wiki/Column-Families#reference>
|
||||
let column_families_on_disk = DB::list_cf(&db_options, &path).unwrap_or_default();
|
||||
let column_families_in_code = Self::COLUMN_FAMILIES_IN_CODE
|
||||
.iter()
|
||||
.map(ToString::to_string);
|
||||
let column_families_in_code = column_families_in_code.into_iter();
|
||||
|
||||
let column_families = column_families_on_disk
|
||||
.into_iter()
|
||||
|
|
@ -683,6 +658,8 @@ impl DiskDb {
|
|||
info!("Opened Zebra state cache at {}", path.display());
|
||||
|
||||
let db = DiskDb {
|
||||
db_kind: db_kind.to_string(),
|
||||
format_version_in_code: format_version_in_code.clone(),
|
||||
network,
|
||||
ephemeral: config.ephemeral,
|
||||
db: Arc::new(db),
|
||||
|
|
@ -704,6 +681,21 @@ impl DiskDb {
|
|||
|
||||
// Accessor methods
|
||||
|
||||
/// Returns the configured database kind for this database.
|
||||
pub fn db_kind(&self) -> String {
|
||||
self.db_kind.clone()
|
||||
}
|
||||
|
||||
/// Returns the format version of the running code that created this `DiskDb` instance in memory.
|
||||
pub fn format_version_in_code(&self) -> Version {
|
||||
self.format_version_in_code.clone()
|
||||
}
|
||||
|
||||
/// Returns the fixed major version for this database.
|
||||
pub fn major_version(&self) -> u64 {
|
||||
self.format_version_in_code().major
|
||||
}
|
||||
|
||||
/// Returns the configured network for this database.
|
||||
pub fn network(&self) -> Network {
|
||||
self.network
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
//!
|
||||
//! # Correctness
|
||||
//!
|
||||
//! The [`crate::constants::DATABASE_FORMAT_VERSION`] constant must
|
||||
//! be incremented each time the database format (column, serialization, etc) changes.
|
||||
//! [`crate::constants::state_database_format_version_in_code()`] must be incremented
|
||||
//! each time the database format (column, serialization, etc) changes.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
//!
|
||||
//! # Correctness
|
||||
//!
|
||||
//! The [`crate::constants::DATABASE_FORMAT_VERSION`] constant must
|
||||
//! be incremented each time the database format (column, serialization, etc) changes.
|
||||
//! [`crate::constants::state_database_format_version_in_code()`] must be incremented
|
||||
//! each time the database format (column, serialization, etc) changes.
|
||||
|
||||
use zebra_chain::{
|
||||
block::{self, Height},
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
//!
|
||||
//! # Correctness
|
||||
//!
|
||||
//! The [`crate::constants::DATABASE_FORMAT_VERSION`] constant must
|
||||
//! be incremented each time the database format (column, serialization, etc) changes.
|
||||
//! [`crate::constants::state_database_format_version_in_code()`] must be incremented
|
||||
//! each time the database format (column, serialization, etc) changes.
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
//!
|
||||
//! # Correctness
|
||||
//!
|
||||
//! The [`crate::constants::DATABASE_FORMAT_VERSION`] constant must
|
||||
//! be incremented each time the database format (column, serialization, etc) changes.
|
||||
//! [`crate::constants::state_database_format_version_in_code()`] must be incremented
|
||||
//! each time the database format (column, serialization, etc) changes.
|
||||
|
||||
use bincode::Options;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
//!
|
||||
//! # Correctness
|
||||
//!
|
||||
//! The [`crate::constants::DATABASE_FORMAT_VERSION`] constant must
|
||||
//! be incremented each time the database format (column, serialization, etc) changes.
|
||||
//! [`crate::constants::state_database_format_version_in_code()`] must be incremented
|
||||
//! each time the database format (column, serialization, etc) changes.
|
||||
|
||||
use std::{cmp::max, fmt::Debug};
|
||||
|
||||
|
|
|
|||
|
|
@ -15,17 +15,13 @@ use zebra_chain::{
|
|||
task::{CheckForPanics, WaitForPanics},
|
||||
CodeTimer,
|
||||
},
|
||||
parameters::Network,
|
||||
};
|
||||
|
||||
use DbFormatChange::*;
|
||||
|
||||
use crate::{
|
||||
config::write_database_format_version_to_disk,
|
||||
constants::{latest_version_for_adding_subtrees, DATABASE_FORMAT_VERSION},
|
||||
database_format_version_in_code, database_format_version_on_disk,
|
||||
constants::latest_version_for_adding_subtrees,
|
||||
service::finalized_state::{DiskWriteBatch, ZebraDb},
|
||||
Config,
|
||||
};
|
||||
|
||||
pub(crate) mod add_subtrees;
|
||||
|
|
@ -113,7 +109,9 @@ impl DbFormatChange {
|
|||
/// Also logs that change at info level.
|
||||
///
|
||||
/// If `disk_version` is `None`, Zebra is creating a new database.
|
||||
pub fn open_database(running_version: Version, disk_version: Option<Version>) -> Self {
|
||||
pub fn open_database(running_version: &Version, disk_version: Option<Version>) -> Self {
|
||||
let running_version = running_version.clone();
|
||||
|
||||
let Some(disk_version) = disk_version else {
|
||||
info!(
|
||||
%running_version,
|
||||
|
|
@ -160,8 +158,8 @@ impl DbFormatChange {
|
|||
/// This check makes sure the upgrade and new block code produce the same data.
|
||||
///
|
||||
/// Also logs the check at info level.
|
||||
pub fn check_new_blocks() -> Self {
|
||||
let running_version = database_format_version_in_code();
|
||||
pub fn check_new_blocks(db: &ZebraDb) -> Self {
|
||||
let running_version = db.format_version_in_code();
|
||||
|
||||
info!(%running_version, "checking new blocks were written in current database format");
|
||||
CheckNewBlocksCurrent { running_version }
|
||||
|
|
@ -219,14 +217,12 @@ impl DbFormatChange {
|
|||
/// Launch a `std::thread` that applies this format change to the database,
|
||||
/// then continues running to perform periodic format checks.
|
||||
///
|
||||
/// `initial_tip_height` is the database height when it was opened, and `upgrade_db` is the
|
||||
/// `initial_tip_height` is the database height when it was opened, and `db` is the
|
||||
/// database instance to upgrade or check.
|
||||
pub fn spawn_format_change(
|
||||
self,
|
||||
config: Config,
|
||||
network: Network,
|
||||
db: ZebraDb,
|
||||
initial_tip_height: Option<Height>,
|
||||
upgrade_db: ZebraDb,
|
||||
) -> DbFormatChangeThreadHandle {
|
||||
// # Correctness
|
||||
//
|
||||
|
|
@ -237,13 +233,7 @@ impl DbFormatChange {
|
|||
let span = Span::current();
|
||||
let update_task = thread::spawn(move || {
|
||||
span.in_scope(move || {
|
||||
self.format_change_run_loop(
|
||||
config,
|
||||
network,
|
||||
initial_tip_height,
|
||||
upgrade_db,
|
||||
cancel_receiver,
|
||||
)
|
||||
self.format_change_run_loop(db, initial_tip_height, cancel_receiver)
|
||||
})
|
||||
});
|
||||
|
||||
|
|
@ -264,21 +254,13 @@ impl DbFormatChange {
|
|||
/// newly added blocks matches the current format. It will run until it is cancelled or panics.
|
||||
fn format_change_run_loop(
|
||||
self,
|
||||
config: Config,
|
||||
network: Network,
|
||||
db: ZebraDb,
|
||||
initial_tip_height: Option<Height>,
|
||||
upgrade_db: ZebraDb,
|
||||
cancel_receiver: mpsc::Receiver<CancelFormatChange>,
|
||||
) -> Result<(), CancelFormatChange> {
|
||||
self.run_format_change_or_check(
|
||||
&config,
|
||||
network,
|
||||
initial_tip_height,
|
||||
&upgrade_db,
|
||||
&cancel_receiver,
|
||||
)?;
|
||||
self.run_format_change_or_check(&db, initial_tip_height, &cancel_receiver)?;
|
||||
|
||||
let Some(debug_validity_check_interval) = config.debug_validity_check_interval else {
|
||||
let Some(debug_validity_check_interval) = db.config().debug_validity_check_interval else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
|
|
@ -292,11 +274,9 @@ impl DbFormatChange {
|
|||
return Err(CancelFormatChange);
|
||||
}
|
||||
|
||||
Self::check_new_blocks().run_format_change_or_check(
|
||||
&config,
|
||||
network,
|
||||
Self::check_new_blocks(&db).run_format_change_or_check(
|
||||
&db,
|
||||
initial_tip_height,
|
||||
&upgrade_db,
|
||||
&cancel_receiver,
|
||||
)?;
|
||||
}
|
||||
|
|
@ -306,24 +286,16 @@ impl DbFormatChange {
|
|||
#[allow(clippy::unwrap_in_result)]
|
||||
pub(crate) fn run_format_change_or_check(
|
||||
&self,
|
||||
config: &Config,
|
||||
network: Network,
|
||||
db: &ZebraDb,
|
||||
initial_tip_height: Option<Height>,
|
||||
upgrade_db: &ZebraDb,
|
||||
cancel_receiver: &mpsc::Receiver<CancelFormatChange>,
|
||||
) -> Result<(), CancelFormatChange> {
|
||||
match self {
|
||||
// Perform any required upgrades, then mark the state as upgraded.
|
||||
Upgrade { .. } => self.apply_format_upgrade(
|
||||
config,
|
||||
network,
|
||||
initial_tip_height,
|
||||
upgrade_db,
|
||||
cancel_receiver,
|
||||
)?,
|
||||
Upgrade { .. } => self.apply_format_upgrade(db, initial_tip_height, cancel_receiver)?,
|
||||
|
||||
NewlyCreated { .. } => {
|
||||
Self::mark_as_newly_created(config, network);
|
||||
Self::mark_as_newly_created(db);
|
||||
}
|
||||
|
||||
Downgrade { .. } => {
|
||||
|
|
@ -332,7 +304,7 @@ impl DbFormatChange {
|
|||
// At the start of a format downgrade, the database must be marked as partially or
|
||||
// fully downgraded. This lets newer Zebra versions know that some blocks with older
|
||||
// formats have been added to the database.
|
||||
Self::mark_as_downgraded(config, network);
|
||||
Self::mark_as_downgraded(db);
|
||||
|
||||
// Older supported versions just assume they can read newer formats,
|
||||
// because they can't predict all changes a newer Zebra version could make.
|
||||
|
|
@ -373,10 +345,10 @@ impl DbFormatChange {
|
|||
// (unless a future upgrade breaks these format checks)
|
||||
// - re-opening the current version should be valid, regardless of whether the upgrade
|
||||
// or new block code created the format (or any combination).
|
||||
Self::format_validity_checks_detailed(upgrade_db, cancel_receiver)?.unwrap_or_else(|_| {
|
||||
Self::format_validity_checks_detailed(db, cancel_receiver)?.unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"unexpected invalid database format: delete and re-sync the database at '{:?}'",
|
||||
upgrade_db.path()
|
||||
db.path()
|
||||
)
|
||||
});
|
||||
|
||||
|
|
@ -392,6 +364,8 @@ impl DbFormatChange {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
// TODO: Move state-specific upgrade code to a finalized_state/* module.
|
||||
|
||||
/// Apply any required format updates to the database.
|
||||
/// Format changes should be launched in an independent `std::thread`.
|
||||
///
|
||||
|
|
@ -405,10 +379,8 @@ impl DbFormatChange {
|
|||
#[allow(clippy::unwrap_in_result)]
|
||||
fn apply_format_upgrade(
|
||||
&self,
|
||||
config: &Config,
|
||||
network: Network,
|
||||
initial_tip_height: Option<Height>,
|
||||
db: &ZebraDb,
|
||||
initial_tip_height: Option<Height>,
|
||||
cancel_receiver: &mpsc::Receiver<CancelFormatChange>,
|
||||
) -> Result<(), CancelFormatChange> {
|
||||
let Upgrade {
|
||||
|
|
@ -430,7 +402,7 @@ impl DbFormatChange {
|
|||
"marking empty database as upgraded"
|
||||
);
|
||||
|
||||
Self::mark_as_upgraded_to(&database_format_version_in_code(), config, network);
|
||||
Self::mark_as_upgraded_to(db, newer_running_version);
|
||||
|
||||
info!(
|
||||
%newer_running_version,
|
||||
|
|
@ -510,7 +482,7 @@ impl DbFormatChange {
|
|||
|
||||
// Mark the database as upgraded. Zebra won't repeat the upgrade anymore once the
|
||||
// database is marked, so the upgrade MUST be complete at this point.
|
||||
Self::mark_as_upgraded_to(&version_for_pruning_trees, config, network);
|
||||
Self::mark_as_upgraded_to(db, &version_for_pruning_trees);
|
||||
|
||||
timer.finish(module_path!(), line!(), "deduplicate trees upgrade");
|
||||
}
|
||||
|
|
@ -538,7 +510,7 @@ impl DbFormatChange {
|
|||
|
||||
// Mark the database as upgraded. Zebra won't repeat the upgrade anymore once the
|
||||
// database is marked, so the upgrade MUST be complete at this point.
|
||||
Self::mark_as_upgraded_to(&latest_version_for_adding_subtrees, config, network);
|
||||
Self::mark_as_upgraded_to(db, &latest_version_for_adding_subtrees);
|
||||
|
||||
timer.finish(module_path!(), line!(), "add subtrees upgrade");
|
||||
}
|
||||
|
|
@ -564,7 +536,7 @@ impl DbFormatChange {
|
|||
|
||||
// Mark the database as upgraded. Zebra won't repeat the upgrade anymore once the
|
||||
// database is marked, so the upgrade MUST be complete at this point.
|
||||
Self::mark_as_upgraded_to(&version_for_tree_keys_and_caches, config, network);
|
||||
Self::mark_as_upgraded_to(db, &version_for_tree_keys_and_caches);
|
||||
|
||||
timer.finish(module_path!(), line!(), "tree keys and caches upgrade");
|
||||
}
|
||||
|
|
@ -721,12 +693,13 @@ impl DbFormatChange {
|
|||
/// # Panics
|
||||
///
|
||||
/// If the format should not have been upgraded, because the database is not newly created.
|
||||
fn mark_as_newly_created(config: &Config, network: Network) {
|
||||
let disk_version = database_format_version_on_disk(config, network)
|
||||
fn mark_as_newly_created(db: &ZebraDb) {
|
||||
let running_version = db.format_version_in_code();
|
||||
let disk_version = db
|
||||
.format_version_on_disk()
|
||||
.expect("unable to read database format version file path");
|
||||
let running_version = database_format_version_in_code();
|
||||
|
||||
let default_new_version = Some(Version::new(DATABASE_FORMAT_VERSION, 0, 0));
|
||||
let default_new_version = Some(Version::new(running_version.major, 0, 0));
|
||||
|
||||
// The database version isn't empty any more, because we've created the RocksDB database
|
||||
// and acquired its lock. (If it is empty, we have a database locking bug.)
|
||||
|
|
@ -737,7 +710,7 @@ impl DbFormatChange {
|
|||
running: {running_version}"
|
||||
);
|
||||
|
||||
write_database_format_version_to_disk(&running_version, config, network)
|
||||
db.update_format_version_on_disk(&running_version)
|
||||
.expect("unable to write database format version file to disk");
|
||||
|
||||
info!(
|
||||
|
|
@ -768,11 +741,12 @@ impl DbFormatChange {
|
|||
/// - older or the same as the disk version
|
||||
/// (multiple upgrades to the same version are not allowed)
|
||||
/// - greater than the running version (that's a logic bug)
|
||||
fn mark_as_upgraded_to(format_upgrade_version: &Version, config: &Config, network: Network) {
|
||||
let disk_version = database_format_version_on_disk(config, network)
|
||||
fn mark_as_upgraded_to(db: &ZebraDb, format_upgrade_version: &Version) {
|
||||
let running_version = db.format_version_in_code();
|
||||
let disk_version = db
|
||||
.format_version_on_disk()
|
||||
.expect("unable to read database format version file")
|
||||
.expect("tried to upgrade a newly created database");
|
||||
let running_version = database_format_version_in_code();
|
||||
|
||||
assert!(
|
||||
running_version > disk_version,
|
||||
|
|
@ -798,7 +772,7 @@ impl DbFormatChange {
|
|||
running: {running_version}"
|
||||
);
|
||||
|
||||
write_database_format_version_to_disk(format_upgrade_version, config, network)
|
||||
db.update_format_version_on_disk(format_upgrade_version)
|
||||
.expect("unable to write database format version file to disk");
|
||||
|
||||
info!(
|
||||
|
|
@ -826,11 +800,12 @@ impl DbFormatChange {
|
|||
/// If the state is newly created, because the running version should be the same.
|
||||
///
|
||||
/// Multiple downgrades are allowed, because they all downgrade to the same running version.
|
||||
fn mark_as_downgraded(config: &Config, network: Network) {
|
||||
let disk_version = database_format_version_on_disk(config, network)
|
||||
fn mark_as_downgraded(db: &ZebraDb) {
|
||||
let running_version = db.format_version_in_code();
|
||||
let disk_version = db
|
||||
.format_version_on_disk()
|
||||
.expect("unable to read database format version file")
|
||||
.expect("can't downgrade a newly created database");
|
||||
let running_version = database_format_version_in_code();
|
||||
|
||||
assert!(
|
||||
disk_version >= running_version,
|
||||
|
|
@ -839,7 +814,7 @@ impl DbFormatChange {
|
|||
running: {running_version}"
|
||||
);
|
||||
|
||||
write_database_format_version_to_disk(&running_version, config, network)
|
||||
db.update_format_version_on_disk(&running_version)
|
||||
.expect("unable to write database format version file to disk");
|
||||
|
||||
info!(
|
||||
|
|
|
|||
|
|
@ -6,18 +6,19 @@
|
|||
//!
|
||||
//! # Correctness
|
||||
//!
|
||||
//! The [`crate::constants::DATABASE_FORMAT_VERSION`] constant must
|
||||
//! be incremented each time the database format (column, serialization, etc) changes.
|
||||
//! [`crate::constants::state_database_format_version_in_code()`] must be incremented
|
||||
//! each time the database format (column, serialization, etc) changes.
|
||||
|
||||
use std::{
|
||||
path::Path,
|
||||
sync::{mpsc, Arc},
|
||||
};
|
||||
|
||||
use semver::Version;
|
||||
use zebra_chain::parameters::Network;
|
||||
|
||||
use crate::{
|
||||
config::{database_format_version_in_code, database_format_version_on_disk},
|
||||
config::database_format_version_on_disk,
|
||||
service::finalized_state::{
|
||||
disk_db::DiskDb,
|
||||
disk_format::{
|
||||
|
|
@ -25,7 +26,7 @@ use crate::{
|
|||
upgrade::{DbFormatChange, DbFormatChangeThreadHandle},
|
||||
},
|
||||
},
|
||||
Config,
|
||||
write_database_format_version_to_disk, BoxError, Config,
|
||||
};
|
||||
|
||||
pub mod block;
|
||||
|
|
@ -37,7 +38,7 @@ pub mod transparent;
|
|||
#[cfg(any(test, feature = "proptest-impl"))]
|
||||
pub mod arbitrary;
|
||||
|
||||
/// Wrapper struct to ensure high-level typed database access goes through the correct API.
|
||||
/// Wrapper struct to ensure high-level `zebra-state` database access goes through the correct API.
|
||||
///
|
||||
/// `rocksdb` allows concurrent writes through a shared reference,
|
||||
/// so database instances are cloneable. When the final clone is dropped,
|
||||
|
|
@ -51,11 +52,13 @@ pub struct ZebraDb {
|
|||
//
|
||||
/// The configuration for the database.
|
||||
//
|
||||
// TODO: use the database and version paths instead, and refactor the upgrade code to use paths
|
||||
// TODO: move the config to DiskDb
|
||||
config: Arc<Config>,
|
||||
|
||||
/// Should format upgrades and format checks be skipped for this instance?
|
||||
/// Only used in test code.
|
||||
//
|
||||
// TODO: move this to DiskDb
|
||||
debug_skip_format_upgrades: bool,
|
||||
|
||||
// Owned State
|
||||
|
|
@ -68,6 +71,8 @@ pub struct ZebraDb {
|
|||
///
|
||||
/// This field should be dropped before the database field, so the format upgrade task is
|
||||
/// cancelled before the database is dropped. This helps avoid some kinds of deadlocks.
|
||||
//
|
||||
// TODO: move the generic upgrade code and fields to DiskDb
|
||||
format_change_handle: Option<DbFormatChangeThreadHandle>,
|
||||
|
||||
/// The inner low-level database wrapper for the RocksDB database.
|
||||
|
|
@ -75,18 +80,32 @@ pub struct ZebraDb {
|
|||
}
|
||||
|
||||
impl ZebraDb {
|
||||
/// Opens or creates the database at `config.path` for `network`,
|
||||
/// Opens or creates the database at a path based on the kind, major version and network,
|
||||
/// with the supplied column families, preserving any existing column families,
|
||||
/// and returns a shared high-level typed database wrapper.
|
||||
///
|
||||
/// If `debug_skip_format_upgrades` is true, don't do any format upgrades or format checks.
|
||||
/// This argument is only used when running tests, it is ignored in production code.
|
||||
pub fn new(config: &Config, network: Network, debug_skip_format_upgrades: bool) -> ZebraDb {
|
||||
let running_version = database_format_version_in_code();
|
||||
let disk_version = database_format_version_on_disk(config, network)
|
||||
.expect("unable to read database format version file");
|
||||
//
|
||||
// TODO: rename to StateDb and remove the db_kind and column_families_in_code arguments
|
||||
pub fn new(
|
||||
config: &Config,
|
||||
db_kind: impl AsRef<str>,
|
||||
format_version_in_code: &Version,
|
||||
network: Network,
|
||||
debug_skip_format_upgrades: bool,
|
||||
column_families_in_code: impl IntoIterator<Item = String>,
|
||||
) -> ZebraDb {
|
||||
let disk_version = database_format_version_on_disk(
|
||||
config,
|
||||
&db_kind,
|
||||
format_version_in_code.major,
|
||||
network,
|
||||
)
|
||||
.expect("unable to read database format version file");
|
||||
|
||||
// Log any format changes before opening the database, in case opening fails.
|
||||
let format_change = DbFormatChange::open_database(running_version, disk_version);
|
||||
let format_change = DbFormatChange::open_database(format_version_in_code, disk_version);
|
||||
|
||||
// Open the database and do initial checks.
|
||||
let mut db = ZebraDb {
|
||||
|
|
@ -97,21 +116,22 @@ impl ZebraDb {
|
|||
// changes to the default database version. Then we set the correct version in the
|
||||
// upgrade thread. We need to do the version change in this order, because the version
|
||||
// file can only be changed while we hold the RocksDB database lock.
|
||||
db: DiskDb::new(config, network),
|
||||
db: DiskDb::new(
|
||||
config,
|
||||
db_kind,
|
||||
format_version_in_code,
|
||||
network,
|
||||
column_families_in_code,
|
||||
),
|
||||
};
|
||||
|
||||
db.spawn_format_change(config, network, format_change);
|
||||
db.spawn_format_change(format_change);
|
||||
|
||||
db
|
||||
}
|
||||
|
||||
/// Launch any required format changes or format checks, and store their thread handle.
|
||||
pub fn spawn_format_change(
|
||||
&mut self,
|
||||
config: &Config,
|
||||
network: Network,
|
||||
format_change: DbFormatChange,
|
||||
) {
|
||||
pub fn spawn_format_change(&mut self, format_change: DbFormatChange) {
|
||||
// Always do format upgrades & checks in production code.
|
||||
if cfg!(test) && self.debug_skip_format_upgrades {
|
||||
return;
|
||||
|
|
@ -128,18 +148,59 @@ impl ZebraDb {
|
|||
|
||||
// TODO:
|
||||
// - should debug_stop_at_height wait for the upgrade task to finish?
|
||||
// - if needed, make upgrade_db into a FinalizedState,
|
||||
// or move the FinalizedState methods needed for upgrades to ZebraDb.
|
||||
let format_change_handle = format_change.spawn_format_change(
|
||||
config.clone(),
|
||||
network,
|
||||
initial_tip_height,
|
||||
upgrade_db,
|
||||
);
|
||||
let format_change_handle =
|
||||
format_change.spawn_format_change(upgrade_db, initial_tip_height);
|
||||
|
||||
self.format_change_handle = Some(format_change_handle);
|
||||
}
|
||||
|
||||
/// Returns config for this database.
|
||||
pub fn config(&self) -> &Config {
|
||||
&self.config
|
||||
}
|
||||
|
||||
/// Returns the configured database kind for this database.
|
||||
pub fn db_kind(&self) -> String {
|
||||
self.db.db_kind()
|
||||
}
|
||||
|
||||
/// Returns the format version of the running code that created this `ZebraDb` instance in memory.
|
||||
pub fn format_version_in_code(&self) -> Version {
|
||||
self.db.format_version_in_code()
|
||||
}
|
||||
|
||||
/// Returns the fixed major version for this database.
|
||||
pub fn major_version(&self) -> u64 {
|
||||
self.db.major_version()
|
||||
}
|
||||
|
||||
/// Returns the format version of this database on disk.
|
||||
///
|
||||
/// See `database_format_version_on_disk()` for details.
|
||||
pub fn format_version_on_disk(&self) -> Result<Option<Version>, BoxError> {
|
||||
database_format_version_on_disk(
|
||||
self.config(),
|
||||
self.db_kind(),
|
||||
self.major_version(),
|
||||
self.network(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Updates the format of this database on disk to the suppled version.
|
||||
///
|
||||
/// See `write_database_format_version_to_disk()` for details.
|
||||
pub(crate) fn update_format_version_on_disk(
|
||||
&self,
|
||||
new_version: &Version,
|
||||
) -> Result<(), BoxError> {
|
||||
write_database_format_version_to_disk(
|
||||
self.config(),
|
||||
self.db_kind(),
|
||||
new_version,
|
||||
self.network(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the configured network for this database.
|
||||
pub fn network(&self) -> Network {
|
||||
self.db.network()
|
||||
|
|
@ -191,8 +252,13 @@ impl ZebraDb {
|
|||
// which would then 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");
|
||||
let disk_version = database_format_version_on_disk(
|
||||
&self.config,
|
||||
self.db_kind(),
|
||||
self.major_version(),
|
||||
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,
|
||||
|
|
@ -201,14 +267,12 @@ impl ZebraDb {
|
|||
|
||||
// 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()
|
||||
if disk_version >= self.db.format_version_in_code() {
|
||||
DbFormatChange::check_new_blocks(self)
|
||||
.run_format_change_or_check(
|
||||
&self.config,
|
||||
self.network(),
|
||||
// This argument is not used by the format check.
|
||||
None,
|
||||
self,
|
||||
// The initial tip height is not used by the new blocks format check.
|
||||
None,
|
||||
&never_cancel_receiver,
|
||||
)
|
||||
.expect("cancel handle is never used");
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
//!
|
||||
//! # Correctness
|
||||
//!
|
||||
//! The [`crate::constants::DATABASE_FORMAT_VERSION`] constant must
|
||||
//! be incremented each time the database format (column, serialization, etc) changes.
|
||||
//! [`crate::constants::state_database_format_version_in_code()`] must be incremented
|
||||
//! each time the database format (column, serialization, etc) changes.
|
||||
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap, HashSet},
|
||||
|
|
|
|||
|
|
@ -26,8 +26,9 @@ use zebra_chain::{
|
|||
use zebra_test::vectors::{MAINNET_BLOCKS, TESTNET_BLOCKS};
|
||||
|
||||
use crate::{
|
||||
constants::{state_database_format_version_in_code, STATE_DATABASE_KIND},
|
||||
request::{FinalizedBlock, Treestate},
|
||||
service::finalized_state::{disk_db::DiskWriteBatch, ZebraDb},
|
||||
service::finalized_state::{disk_db::DiskWriteBatch, ZebraDb, STATE_COLUMN_FAMILIES_IN_CODE},
|
||||
CheckpointVerifiedBlock, Config,
|
||||
};
|
||||
|
||||
|
|
@ -80,9 +81,14 @@ fn test_block_db_round_trip_with(
|
|||
|
||||
let state = ZebraDb::new(
|
||||
&Config::ephemeral(),
|
||||
STATE_DATABASE_KIND,
|
||||
&state_database_format_version_in_code(),
|
||||
network,
|
||||
// The raw database accesses in this test create invalid database formats.
|
||||
true,
|
||||
STATE_COLUMN_FAMILIES_IN_CODE
|
||||
.iter()
|
||||
.map(ToString::to_string),
|
||||
);
|
||||
|
||||
// Check that each block round-trips to the database
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
//!
|
||||
//! # Correctness
|
||||
//!
|
||||
//! The [`crate::constants::DATABASE_FORMAT_VERSION`] constant must
|
||||
//! be incremented each time the database format (column, serialization, etc) changes.
|
||||
//! [`crate::constants::state_database_format_version_in_code()`] must be incremented
|
||||
//! each time the database format (column, serialization, etc) changes.
|
||||
|
||||
use std::{borrow::Borrow, collections::HashMap, sync::Arc};
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
//!
|
||||
//! # Correctness
|
||||
//!
|
||||
//! The [`crate::constants::DATABASE_FORMAT_VERSION`] constant must
|
||||
//! be incremented each time the database format (column, serialization, etc) changes.
|
||||
//! [`crate::constants::state_database_format_version_in_code()`] must be incremented
|
||||
//! each time the database format (column, serialization, etc) changes.
|
||||
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@
|
|||
//!
|
||||
//! # Correctness
|
||||
//!
|
||||
//! The [`crate::constants::DATABASE_FORMAT_VERSION`] constant must
|
||||
//! be incremented each time the database format (column, serialization, etc) changes.
|
||||
//! [`crate::constants::state_database_format_version_in_code()`] must be incremented
|
||||
//! each time the database format (column, serialization, etc) changes.
|
||||
|
||||
use std::{
|
||||
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
|
||||
|
|
|
|||
|
|
@ -18,10 +18,11 @@ use zebra_test::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
constants::{state_database_format_version_in_code, STATE_DATABASE_KIND},
|
||||
init_test_services, populated_state,
|
||||
response::MinedTx,
|
||||
service::{
|
||||
finalized_state::{DiskWriteBatch, ZebraDb},
|
||||
finalized_state::{DiskWriteBatch, ZebraDb, STATE_COLUMN_FAMILIES_IN_CODE},
|
||||
non_finalized_state::Chain,
|
||||
read::{orchard_subtrees, sapling_subtrees},
|
||||
},
|
||||
|
|
@ -122,7 +123,8 @@ async fn test_read_subtrees() -> Result<()> {
|
|||
|
||||
// Prepare the finalized state.
|
||||
let db = {
|
||||
let db = ZebraDb::new(&Config::ephemeral(), Mainnet, true);
|
||||
let db = new_ephemeral_db();
|
||||
|
||||
let db_subtrees = db_height_range.enumerate().map(dummy_subtree);
|
||||
for db_subtree in db_subtrees {
|
||||
let mut db_batch = DiskWriteBatch::new();
|
||||
|
|
@ -206,7 +208,8 @@ async fn test_sapling_subtrees() -> Result<()> {
|
|||
|
||||
// Prepare the finalized state.
|
||||
let db_subtree = NoteCommitmentSubtree::new(0, Height(1), dummy_subtree_root);
|
||||
let db = ZebraDb::new(&Config::ephemeral(), Mainnet, true);
|
||||
|
||||
let db = new_ephemeral_db();
|
||||
let mut db_batch = DiskWriteBatch::new();
|
||||
db_batch.insert_sapling_subtree(&db, &db_subtree);
|
||||
db.write(db_batch)
|
||||
|
|
@ -271,7 +274,8 @@ async fn test_orchard_subtrees() -> Result<()> {
|
|||
|
||||
// Prepare the finalized state.
|
||||
let db_subtree = NoteCommitmentSubtree::new(0, Height(1), dummy_subtree_root);
|
||||
let db = ZebraDb::new(&Config::ephemeral(), Mainnet, true);
|
||||
|
||||
let db = new_ephemeral_db();
|
||||
let mut db_batch = DiskWriteBatch::new();
|
||||
db_batch.insert_orchard_subtree(&db, &db_subtree);
|
||||
db.write(db_batch)
|
||||
|
|
@ -361,3 +365,17 @@ where
|
|||
{
|
||||
index == &subtree.index && subtree_data == &subtree.into_data()
|
||||
}
|
||||
|
||||
/// Returns a new ephemeral database with no consistency checks.
|
||||
fn new_ephemeral_db() -> ZebraDb {
|
||||
ZebraDb::new(
|
||||
&Config::ephemeral(),
|
||||
STATE_DATABASE_KIND,
|
||||
&state_database_format_version_in_code(),
|
||||
Mainnet,
|
||||
true,
|
||||
STATE_COLUMN_FAMILIES_IN_CODE
|
||||
.iter()
|
||||
.map(ToString::to_string),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@ use semver::{BuildMetadata, Version};
|
|||
|
||||
use zebra_network::constants::PORT_IN_USE_ERROR;
|
||||
use zebra_state::{
|
||||
constants::LOCK_FILE_ERROR, database_format_version_in_code, database_format_version_on_disk,
|
||||
constants::LOCK_FILE_ERROR, state_database_format_version_in_code,
|
||||
state_database_format_version_on_disk,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
|
@ -267,7 +268,7 @@ impl Application for ZebradApp {
|
|||
|
||||
// reads state disk version file, doesn't open RocksDB database
|
||||
let disk_db_version =
|
||||
match database_format_version_on_disk(&config.state, config.network.network) {
|
||||
match state_database_format_version_on_disk(&config.state, config.network.network) {
|
||||
Ok(Some(version)) => version.to_string(),
|
||||
// This "version" is specially formatted to match a relaxed version regex in CI
|
||||
Ok(None) => "creating.new.database".to_string(),
|
||||
|
|
@ -286,7 +287,7 @@ impl Application for ZebradApp {
|
|||
// code constant
|
||||
(
|
||||
"running state version",
|
||||
database_format_version_in_code().to_string(),
|
||||
state_database_format_version_in_code().to_string(),
|
||||
),
|
||||
// state disk file, doesn't open database
|
||||
("initial disk state version", disk_db_version),
|
||||
|
|
|
|||
|
|
@ -249,8 +249,10 @@ impl StartCmd {
|
|||
);
|
||||
|
||||
info!("spawning delete old databases task");
|
||||
let mut old_databases_task_handle =
|
||||
zebra_state::check_and_delete_old_databases(config.state.clone());
|
||||
let mut old_databases_task_handle = zebra_state::check_and_delete_old_state_databases(
|
||||
&config.state,
|
||||
config.network.network,
|
||||
);
|
||||
|
||||
info!("spawning progress logging task");
|
||||
let progress_task_handle = tokio::spawn(
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ use zebra_chain::{
|
|||
};
|
||||
use zebra_network::constants::PORT_IN_USE_ERROR;
|
||||
use zebra_node_services::rpc_client::RpcRequestClient;
|
||||
use zebra_state::{constants::LOCK_FILE_ERROR, database_format_version_in_code};
|
||||
use zebra_state::{constants::LOCK_FILE_ERROR, state_database_format_version_in_code};
|
||||
|
||||
use zebra_test::{
|
||||
args,
|
||||
|
|
@ -1856,7 +1856,7 @@ fn lightwalletd_integration_test(test_type: TestType) -> Result<()> {
|
|||
wait_for_state_version_upgrade(
|
||||
&mut zebrad,
|
||||
&state_version_message,
|
||||
database_format_version_in_code(),
|
||||
state_database_format_version_in_code(),
|
||||
[format!(
|
||||
"Opened RPC endpoint at {}",
|
||||
zebra_rpc_address.expect("lightwalletd test must have RPC port")
|
||||
|
|
@ -1866,7 +1866,7 @@ fn lightwalletd_integration_test(test_type: TestType) -> Result<()> {
|
|||
wait_for_state_version_upgrade(
|
||||
&mut zebrad,
|
||||
&state_version_message,
|
||||
database_format_version_in_code(),
|
||||
state_database_format_version_in_code(),
|
||||
None,
|
||||
)?;
|
||||
}
|
||||
|
|
@ -1978,7 +1978,7 @@ fn lightwalletd_integration_test(test_type: TestType) -> Result<()> {
|
|||
wait_for_state_version_upgrade(
|
||||
&mut zebrad,
|
||||
&state_version_message,
|
||||
database_format_version_in_code(),
|
||||
state_database_format_version_in_code(),
|
||||
None,
|
||||
)?;
|
||||
}
|
||||
|
|
@ -2004,7 +2004,7 @@ fn lightwalletd_integration_test(test_type: TestType) -> Result<()> {
|
|||
wait_for_state_version_upgrade(
|
||||
&mut zebrad,
|
||||
&state_version_message,
|
||||
database_format_version_in_code(),
|
||||
state_database_format_version_in_code(),
|
||||
None,
|
||||
)?;
|
||||
}
|
||||
|
|
@ -2192,7 +2192,7 @@ fn zebra_state_conflict() -> Result<()> {
|
|||
dir_conflict_full.push("state");
|
||||
dir_conflict_full.push(format!(
|
||||
"v{}",
|
||||
zebra_state::database_format_version_in_code().major,
|
||||
zebra_state::state_database_format_version_in_code().major,
|
||||
));
|
||||
dir_conflict_full.push(config.network.network.to_string().to_lowercase());
|
||||
format!(
|
||||
|
|
@ -2331,8 +2331,8 @@ async fn fully_synced_rpc_test() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn delete_old_databases() -> Result<()> {
|
||||
#[test]
|
||||
fn delete_old_databases() -> Result<()> {
|
||||
use std::fs::{canonicalize, create_dir};
|
||||
|
||||
let _init_guard = zebra_test::init();
|
||||
|
|
@ -2379,7 +2379,7 @@ async fn delete_old_databases() -> Result<()> {
|
|||
|
||||
// inside dir was deleted
|
||||
child.expect_stdout_line_matches(format!(
|
||||
"deleted outdated state directory deleted_state={canonicalized_inside_dir:?}"
|
||||
"deleted outdated state database directory.*deleted_db.*=.*{canonicalized_inside_dir:?}"
|
||||
))?;
|
||||
assert!(!inside_dir.as_path().exists());
|
||||
|
||||
|
|
@ -2526,7 +2526,7 @@ async fn new_state_format() -> Result<()> {
|
|||
/// (or just add a delay during tests)
|
||||
#[tokio::test]
|
||||
async fn update_state_format() -> Result<()> {
|
||||
let mut fake_version = database_format_version_in_code();
|
||||
let mut fake_version = state_database_format_version_in_code();
|
||||
fake_version.minor = 0;
|
||||
fake_version.patch = 0;
|
||||
|
||||
|
|
@ -2543,7 +2543,7 @@ async fn update_state_format() -> Result<()> {
|
|||
/// Future version compatibility is a best-effort attempt, this test can be disabled if it fails.
|
||||
#[tokio::test]
|
||||
async fn downgrade_state_format() -> Result<()> {
|
||||
let mut fake_version = database_format_version_in_code();
|
||||
let mut fake_version = state_database_format_version_in_code();
|
||||
fake_version.minor = u16::MAX.into();
|
||||
fake_version.patch = 0;
|
||||
|
||||
|
|
@ -2625,13 +2625,17 @@ async fn state_format_test(
|
|||
.zebrad_config(test_name, false, Some(dir.path()), network)
|
||||
.expect("already checked config")?;
|
||||
|
||||
zebra_state::write_database_format_version_to_disk(fake_version, &config.state, network)
|
||||
.expect("can't write fake database version to disk");
|
||||
zebra_state::write_state_database_format_version_to_disk(
|
||||
&config.state,
|
||||
fake_version,
|
||||
network,
|
||||
)
|
||||
.expect("can't write fake database version to disk");
|
||||
|
||||
// Give zebra_state enough time to actually write the database version to disk.
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
|
||||
let running_version = database_format_version_in_code();
|
||||
let running_version = state_database_format_version_in_code();
|
||||
|
||||
match fake_version.cmp(&running_version) {
|
||||
Ordering::Less => expect_older_version = true,
|
||||
|
|
@ -2737,7 +2741,7 @@ async fn fully_synced_rpc_z_getsubtreesbyindex_snapshot_test() -> Result<()> {
|
|||
wait_for_state_version_upgrade(
|
||||
&mut zebrad,
|
||||
&state_version_message,
|
||||
database_format_version_in_code(),
|
||||
state_database_format_version_in_code(),
|
||||
None,
|
||||
)?;
|
||||
|
||||
|
|
@ -2800,10 +2804,10 @@ async fn fully_synced_rpc_z_getsubtreesbyindex_snapshot_test() -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "zebra-scan")]
|
||||
/// Test that the scanner gets started when the node starts.
|
||||
#[tokio::test]
|
||||
async fn scan_task_starts() -> Result<()> {
|
||||
#[cfg(feature = "zebra-scan")]
|
||||
#[test]
|
||||
fn scan_task_starts() -> Result<()> {
|
||||
use indexmap::IndexMap;
|
||||
|
||||
const ZECPAGES_VIEWING_KEY: &str = "zxviews1q0duytgcqqqqpqre26wkl45gvwwwd706xw608hucmvfalr759ejwf7qshjf5r9aa7323zulvz6plhttp5mltqcgs9t039cx2d09mgq05ts63n8u35hyv6h9nc9ctqqtue2u7cer2mqegunuulq2luhq3ywjcz35yyljewa4mgkgjzyfwh6fr6jd0dzd44ghk0nxdv2hnv4j5nxfwv24rwdmgllhe0p8568sgqt9ckt02v2kxf5ahtql6s0ltjpkckw8gtymxtxuu9gcr0swvz";
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use zebra_chain::{
|
|||
};
|
||||
use zebra_consensus::MAX_CHECKPOINT_HEIGHT_GAP;
|
||||
use zebra_node_services::rpc_client::RpcRequestClient;
|
||||
use zebra_state::database_format_version_in_code;
|
||||
use zebra_state::state_database_format_version_in_code;
|
||||
use zebra_test::{
|
||||
args,
|
||||
command::{Arguments, TestDirExt, NO_MATCHES_REGEX_ITER},
|
||||
|
|
@ -98,7 +98,7 @@ pub async fn run(network: Network) -> Result<()> {
|
|||
wait_for_state_version_upgrade(
|
||||
&mut zebrad,
|
||||
&state_version_message,
|
||||
database_format_version_in_code(),
|
||||
state_database_format_version_in_code(),
|
||||
None,
|
||||
)?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ use zebra_chain::{
|
|||
parameters::NetworkUpgrade::{Nu5, Sapling},
|
||||
serialization::ZcashDeserializeInto,
|
||||
};
|
||||
use zebra_state::database_format_version_in_code;
|
||||
use zebra_state::state_database_format_version_in_code;
|
||||
|
||||
use crate::common::{
|
||||
cached_state::{
|
||||
|
|
@ -122,7 +122,7 @@ pub async fn run() -> Result<()> {
|
|||
wait_for_state_version_upgrade(
|
||||
&mut zebrad,
|
||||
&state_version_message,
|
||||
database_format_version_in_code(),
|
||||
state_database_format_version_in_code(),
|
||||
[format!("Opened RPC endpoint at {zebra_rpc_address}")],
|
||||
)?;
|
||||
}
|
||||
|
|
@ -159,7 +159,7 @@ pub async fn run() -> Result<()> {
|
|||
wait_for_state_version_upgrade(
|
||||
&mut zebrad,
|
||||
&state_version_message,
|
||||
database_format_version_in_code(),
|
||||
state_database_format_version_in_code(),
|
||||
None,
|
||||
)?;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue