diff --git a/consensus/CHANGELOG.md b/consensus/CHANGELOG.md index 5be6ef067b..473462e379 100644 --- a/consensus/CHANGELOG.md +++ b/consensus/CHANGELOG.md @@ -7,7 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -[1.0.1] - 2025-01-23 +### Fixed + +- Fix `MismatchHeight` error message + +## [1.0.1] - 2025-01-23 ## [1.0.0] - 2025-01-16 diff --git a/consensus/src/errors.rs b/consensus/src/errors.rs index fa9c7af511..2a039c294c 100644 --- a/consensus/src/errors.rs +++ b/consensus/src/errors.rs @@ -89,7 +89,7 @@ pub enum HeaderError { UnsupportedVersion, #[error("empty block hash")] EmptyHash, - #[error("invalid block height block_height: {0}, curr_height: {0}")] + #[error("invalid block height block_height: {0}, curr_height: {1}")] MismatchHeight(u64, u64), #[error("block time is less than minimum block time")] BlockTimeLess, diff --git a/node/CHANGELOG.md b/node/CHANGELOG.md index 7bf341c751..342e88ac0d 100644 --- a/node/CHANGELOG.md +++ b/node/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Add `create_if_missing` field to `DatabaseOptions` +- Add support for `RUSK_EXT_CHAIN` env + ## [1.1.0] - 2025-02-14 ### Added diff --git a/node/src/chain.rs b/node/src/chain.rs index 4b97b4e7b9..ea5d1a2d2c 100644 --- a/node/src/chain.rs +++ b/node/src/chain.rs @@ -83,14 +83,10 @@ impl ) .await?; - let state_hash = tip.inner().header().state_hash; - let provisioners_list = vm.read().await.get_provisioners(state_hash)?; - // Initialize Acceptor let acc = Acceptor::init_consensus( &self.keys_path, tip, - provisioners_list, db, network, vm, diff --git a/node/src/chain/acceptor.rs b/node/src/chain/acceptor.rs index a0db0f86ef..6166f5b0a4 100644 --- a/node/src/chain/acceptor.rs +++ b/node/src/chain/acceptor.rs @@ -44,10 +44,12 @@ use crate::archive::Archive; use crate::chain::header_validation::{verify_att, verify_faults, Validator}; use crate::chain::metrics::AverageElapsedTime; use crate::database::rocksdb::{ - MD_AVG_PROPOSAL, MD_AVG_RATIFICATION, MD_AVG_VALIDATION, MD_HASH_KEY, - MD_STATE_ROOT_KEY, + Backend, MD_AVG_PROPOSAL, MD_AVG_RATIFICATION, MD_AVG_VALIDATION, + MD_HASH_KEY, MD_STATE_ROOT_KEY, +}; +use crate::database::{ + self, ConsensusStorage, DatabaseOptions, Ledger, Mempool, Metadata, DB, }; -use crate::database::{self, ConsensusStorage, Ledger, Mempool, Metadata}; use crate::{vm, Message, Network}; const CANDIDATES_DELETION_OFFSET: u64 = 10; @@ -196,7 +198,6 @@ impl Acceptor { pub async fn init_consensus( keys_path: &str, tip: BlockWithLabel, - provisioners_list: Provisioners, db: Arc>, network: Arc>, vm: Arc>, @@ -208,6 +209,8 @@ impl Acceptor { ) -> anyhow::Result { let tip_height = tip.inner().header().height; let tip_state_hash = tip.inner().header().state_hash; + let provisioners_list = + vm.read().await.get_provisioners(tip_state_hash)?; let mut provisioners_list = ContextProvisioners::new(provisioners_list); @@ -217,7 +220,7 @@ impl Acceptor { provisioners_list.apply_changes(changed_provisioners); } - let acc = Self { + let mut acc = Self { tip: RwLock::new(tip), provisioners_list: RwLock::new(provisioners_list), db: db.clone(), @@ -261,6 +264,36 @@ impl Acceptor { ); } } + let ext_db_parent_path = env::var("RUSK_EXT_CHAIN").unwrap_or_default(); + + if !ext_db_parent_path.is_empty() { + let opts = DatabaseOptions { + create_if_missing: false, + ..Default::default() + }; + let db_ext = Backend::create_or_open(ext_db_parent_path, opts); + let tip_ext = db_ext + .view(|t| { + anyhow::Ok(t.op_read(MD_HASH_KEY)?.and_then(|tip_hash| { + t.block(&tip_hash[..]) + .expect("block to be found if metadata is set") + })) + })? + .expect("Cannot find tip for ext block") + .header() + .height; + + if tip_ext > tip_height { + info!("detected ext db at height {tip_ext}. Syncing local db starting from {tip_height}" ); + + for height in tip_height + 1..=tip_ext { + let blk = db_ext + .view(|db| db.block_by_height(height))? + .expect("block to be found"); + acc.try_accept_block(&blk, false).await?; + } + } + } let tip_ts = acc.tip.read().await.inner().header().timestamp; Self::init_delay(tip_ts).await; diff --git a/node/src/database.rs b/node/src/database.rs index 668c240364..c319bea6dc 100644 --- a/node/src/database.rs +++ b/node/src/database.rs @@ -241,6 +241,9 @@ pub struct DatabaseOptions { /// Enables a set of flags for collecting DB stats as log data. pub enable_debug: bool, + + /// Create the database if missing + pub create_if_missing: bool, } impl Default for DatabaseOptions { @@ -250,6 +253,7 @@ impl Default for DatabaseOptions { mempool_cf_max_write_buffer_size: 10 * 1024 * 1024, // 10 MiB blocks_cf_disable_block_cache: true, enable_debug: false, + create_if_missing: true, } } } diff --git a/node/src/database/rocksdb.rs b/node/src/database/rocksdb.rs index 8ea6cc6773..cd1905bd53 100644 --- a/node/src/database/rocksdb.rs +++ b/node/src/database/rocksdb.rs @@ -153,7 +153,7 @@ impl DB for Backend { // A set of options for initializing any blocks-related CF (including // METADATA CF) let mut blocks_cf_opts = Options::default(); - blocks_cf_opts.create_if_missing(true); + blocks_cf_opts.create_if_missing(db_opts.create_if_missing); blocks_cf_opts.create_missing_column_families(true); blocks_cf_opts.set_level_compaction_dynamic_level_bytes(true); blocks_cf_opts