diff --git a/base_layer/common_types/src/chain_metadata.rs b/base_layer/common_types/src/chain_metadata.rs index 0ab3d7285b..c9aa217d02 100644 --- a/base_layer/common_types/src/chain_metadata.rs +++ b/base_layer/common_types/src/chain_metadata.rs @@ -47,6 +47,13 @@ pub struct ChainMetadata { /// Timestamp of the tip block in the longest valid chain timestamp: u64, } +#[derive(Debug, thiserror::Error)] +pub enum ChainMetaDataError { + #[error("Pruning Height is higher than the Best Block height")] + PruningHeightAboveBestBlock, + #[error("The total accumulated difficulty is zero")] + AccumulatedDifficultyZero, +} impl ChainMetadata { pub fn new( @@ -56,15 +63,22 @@ impl ChainMetadata { pruned_height: u64, accumulated_difficulty: U256, timestamp: u64, - ) -> ChainMetadata { - ChainMetadata { + ) -> Result { + let chain_meta_data = ChainMetadata { best_block_height, best_block_hash, pruning_horizon, pruned_height, accumulated_difficulty, timestamp, - } + }; + if chain_meta_data.accumulated_difficulty == 0.into() { + return Err(ChainMetaDataError::AccumulatedDifficultyZero); + }; + if chain_meta_data.pruned_height > chain_meta_data.best_block_height { + return Err(ChainMetaDataError::PruningHeightAboveBestBlock); + }; + Ok(chain_meta_data) } /// The block height at the pruning horizon, given the chain height of the network. Typically database backends diff --git a/base_layer/core/src/base_node/proto/chain_metadata.rs b/base_layer/core/src/base_node/proto/chain_metadata.rs index 333f80aceb..2a876fbe63 100644 --- a/base_layer/core/src/base_node/proto/chain_metadata.rs +++ b/base_layer/core/src/base_node/proto/chain_metadata.rs @@ -56,14 +56,15 @@ impl TryFrom for ChainMetadata { .best_block_hash .try_into() .map_err(|e| format!("Malformed best block: {}", e))?; - Ok(ChainMetadata::new( + ChainMetadata::new( best_block_height, hash, pruning_horizon, metadata.pruned_height, accumulated_difficulty, metadata.timestamp, - )) + ) + .map_err(|e| e.to_string()) } } diff --git a/base_layer/core/src/base_node/state_machine_service/states/listening.rs b/base_layer/core/src/base_node/state_machine_service/states/listening.rs index 20d307fc08..9e097d8d9b 100644 --- a/base_layer/core/src/base_node/state_machine_service/states/listening.rs +++ b/base_layer/core/src/base_node/state_machine_service/states/listening.rs @@ -456,7 +456,7 @@ mod test { let archival_node = PeerChainMetadata::new( random_node_id(), - ChainMetadata::new(NETWORK_TIP_HEIGHT, block_hash, 0, 0, accumulated_difficulty, 0), + ChainMetadata::new(NETWORK_TIP_HEIGHT, block_hash, 0, 0, accumulated_difficulty, 0).unwrap(), None, ); @@ -469,7 +469,8 @@ mod test { 0, accumulated_difficulty - U256::from(1000), 0, - ), + ) + .unwrap(), None, ); diff --git a/base_layer/core/src/base_node/sync/sync_peer.rs b/base_layer/core/src/base_node/sync/sync_peer.rs index 52877c627c..4594f78aa5 100644 --- a/base_layer/core/src/base_node/sync/sync_peer.rs +++ b/base_layer/core/src/base_node/sync/sync_peer.rs @@ -135,7 +135,6 @@ mod test { use super::*; mod sort_by_latency { - use primitive_types::U256; use tari_common_types::types::FixedHash; use tari_comms::types::{CommsPublicKey, CommsSecretKey}; use tari_crypto::keys::{PublicKey, SecretKey}; @@ -151,7 +150,7 @@ mod test { let latency_option = latency.map(|latency| Duration::from_millis(latency as u64)); PeerChainMetadata::new( node_id, - ChainMetadata::new(0, FixedHash::zero(), 0, 0, U256::zero(), 0), + ChainMetadata::new(0, FixedHash::zero(), 0, 0, 1.into(), 0).unwrap(), latency_option, ) .into() diff --git a/base_layer/core/src/chain_storage/error.rs b/base_layer/core/src/chain_storage/error.rs index 47f5217697..f9551e336c 100644 --- a/base_layer/core/src/chain_storage/error.rs +++ b/base_layer/core/src/chain_storage/error.rs @@ -21,7 +21,7 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use lmdb_zero::error; -use tari_common_types::types::FixedHashSizeError; +use tari_common_types::{chain_metadata::ChainMetaDataError, types::FixedHashSizeError}; use tari_mmr::{error::MerkleMountainRangeError, sparse_merkle_tree::SMTError, MerkleProofError}; use tari_storage::lmdb_store::LMDBError; use thiserror::Error; @@ -139,6 +139,8 @@ pub enum ChainStorageError { FromKeyBytesFailed(String), #[error("Sparse Merkle Tree error: {0}")] SMTError(#[from] SMTError), + #[error("Invalid ChainMetaData: {0}")] + InvalidChainMetaData(#[from] ChainMetaDataError), } impl ChainStorageError { @@ -190,6 +192,7 @@ impl ChainStorageError { _err @ ChainStorageError::FixedHashSizeError(_) | _err @ ChainStorageError::CompositeKeyLengthExceeded | _err @ ChainStorageError::FromKeyBytesFailed(_) | + _err @ ChainStorageError::InvalidChainMetaData(_) | _err @ ChainStorageError::OutOfRange => None, } } diff --git a/base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs b/base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs index 35c8a3a532..2b4faffe2a 100644 --- a/base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs +++ b/base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs @@ -2449,7 +2449,7 @@ fn fetch_metadata(txn: &ConstTransaction<'_>, db: &Database) -> Result::digest(node_identity.node_id().as_bytes()).into(); - let metadata = ChainMetadata::new(10, block_hash, 2800, 0, 5000.into(), 0); + let metadata = ChainMetadata::new(10, block_hash, 2800, 0, 5000.into(), 0).unwrap(); node.comms .peer_manager() diff --git a/base_layer/wallet/tests/support/base_node_service_mock.rs b/base_layer/wallet/tests/support/base_node_service_mock.rs index 46f755d12d..ebfb37f9ef 100644 --- a/base_layer/wallet/tests/support/base_node_service_mock.rs +++ b/base_layer/wallet/tests/support/base_node_service_mock.rs @@ -79,7 +79,7 @@ impl MockBaseNodeService { pub fn set_base_node_state(&mut self, height: Option) { let (chain_metadata, is_synced) = match height { Some(height) => { - let metadata = ChainMetadata::new(height, FixedHash::zero(), 0, 0, 0.into(), 0); + let metadata = ChainMetadata::new(height, FixedHash::zero(), 0, 0, 1.into(), 0).unwrap(); (Some(metadata), Some(true)) }, None => (None, None), @@ -95,7 +95,7 @@ impl MockBaseNodeService { } pub fn set_default_base_node_state(&mut self) { - let metadata = ChainMetadata::new(i64::MAX as u64, FixedHash::zero(), 0, 0, 0.into(), 0); + let metadata = ChainMetadata::new(i64::MAX as u64, FixedHash::zero(), 0, 0, 1.into(), 0).unwrap(); self.state = BaseNodeState { node_id: None, chain_metadata: Some(metadata), diff --git a/base_layer/wallet/tests/transaction_service_tests/service.rs b/base_layer/wallet/tests/transaction_service_tests/service.rs index f12b8d67be..efba77a934 100644 --- a/base_layer/wallet/tests/transaction_service_tests/service.rs +++ b/base_layer/wallet/tests/transaction_service_tests/service.rs @@ -195,7 +195,7 @@ async fn setup_transaction_service>( let passphrase = SafePassword::from("My lovely secret passphrase"); let db = WalletDatabase::new(WalletSqliteDatabase::new(db_connection.clone(), passphrase).unwrap()); - let metadata = ChainMetadata::new(std::i64::MAX as u64, FixedHash::zero(), 0, 0, 0.into(), 0); + let metadata = ChainMetadata::new(std::i64::MAX as u64, FixedHash::zero(), 0, 0, 1.into(), 0).unwrap(); db.set_chain_metadata(metadata).unwrap(); diff --git a/base_layer/wallet_ffi/src/callback_handler_tests.rs b/base_layer/wallet_ffi/src/callback_handler_tests.rs index 184fe38b08..377f1ecf75 100644 --- a/base_layer/wallet_ffi/src/callback_handler_tests.rs +++ b/base_layer/wallet_ffi/src/callback_handler_tests.rs @@ -507,7 +507,8 @@ mod test { 0, 123.into(), ts_now.timestamp_millis() as u64, - ); + ) + .unwrap(); base_node_event_sender .send(Arc::new(BaseNodeEvent::BaseNodeStateChanged(BaseNodeState {