Skip to content

Commit

Permalink
feat: check chain metadata (#6146)
Browse files Browse the repository at this point in the history
Description
---
Checks chain metadata for correctness

Motivation and Context
---
The base node makes certain logic desisions based on what the chain meta
data is, but no where do we make checks to ensure that the data is valid
inside of this.

How Has This Been Tested?
---
unit tests
  • Loading branch information
SWvheerden committed Feb 16, 2024
1 parent 506e59c commit 8a16f7b
Show file tree
Hide file tree
Showing 10 changed files with 35 additions and 16 deletions.
20 changes: 17 additions & 3 deletions base_layer/common_types/src/chain_metadata.rs
Expand Up @@ -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(
Expand All @@ -56,15 +63,22 @@ impl ChainMetadata {
pruned_height: u64,
accumulated_difficulty: U256,
timestamp: u64,
) -> ChainMetadata {
ChainMetadata {
) -> Result<ChainMetadata, ChainMetaDataError> {
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
Expand Down
5 changes: 3 additions & 2 deletions base_layer/core/src/base_node/proto/chain_metadata.rs
Expand Up @@ -56,14 +56,15 @@ impl TryFrom<proto::ChainMetadata> 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())
}
}

Expand Down
Expand Up @@ -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,
);

Expand All @@ -469,7 +469,8 @@ mod test {
0,
accumulated_difficulty - U256::from(1000),
0,
),
)
.unwrap(),
None,
);

Expand Down
3 changes: 1 addition & 2 deletions base_layer/core/src/base_node/sync/sync_peer.rs
Expand Up @@ -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};
Expand All @@ -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()
Expand Down
5 changes: 4 additions & 1 deletion base_layer/core/src/chain_storage/error.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -190,6 +192,7 @@ impl ChainStorageError {
_err @ ChainStorageError::FixedHashSizeError(_) |
_err @ ChainStorageError::CompositeKeyLengthExceeded |
_err @ ChainStorageError::FromKeyBytesFailed(_) |
_err @ ChainStorageError::InvalidChainMetaData(_) |
_err @ ChainStorageError::OutOfRange => None,
}
}
Expand Down
2 changes: 1 addition & 1 deletion base_layer/core/src/chain_storage/lmdb_db/lmdb_db.rs
Expand Up @@ -2449,7 +2449,7 @@ fn fetch_metadata(txn: &ConstTransaction<'_>, db: &Database) -> Result<ChainMeta
fetch_pruned_height(txn, db)?,
fetch_accumulated_work(txn, db)?,
fetch_best_block_timestamp(txn, db)?,
))
)?)
}

// Fetches the chain height from the provided metadata db.
Expand Down
2 changes: 1 addition & 1 deletion base_layer/core/tests/tests/node_state_machine.rs
Expand Up @@ -304,7 +304,7 @@ async fn test_event_channel() {

let node_identity = random_node_identity();
let block_hash = Blake2b::<U32>::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()
Expand Down
4 changes: 2 additions & 2 deletions base_layer/wallet/tests/support/base_node_service_mock.rs
Expand Up @@ -79,7 +79,7 @@ impl MockBaseNodeService {
pub fn set_base_node_state(&mut self, height: Option<u64>) {
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),
Expand All @@ -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),
Expand Down
Expand Up @@ -195,7 +195,7 @@ async fn setup_transaction_service<P: AsRef<Path>>(

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();

Expand Down
3 changes: 2 additions & 1 deletion base_layer/wallet_ffi/src/callback_handler_tests.rs
Expand Up @@ -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 {
Expand Down

0 comments on commit 8a16f7b

Please sign in to comment.