From 60ac5ed154940e4ab24360c75c62cbb6664723a2 Mon Sep 17 00:00:00 2001 From: Damien Lachaume <135982616+dlachaume@users.noreply.github.com> Date: Tue, 24 Dec 2024 16:28:32 +0100 Subject: [PATCH] feat: ensure `CardanoDatabaseSnapshot` identifiers are unique by computing a unique hash --- .../src/entities/cardano_database.rs | 127 +++++++++++++++++- 1 file changed, 124 insertions(+), 3 deletions(-) diff --git a/mithril-common/src/entities/cardano_database.rs b/mithril-common/src/entities/cardano_database.rs index f6ee441f5c..2b75298923 100644 --- a/mithril-common/src/entities/cardano_database.rs +++ b/mithril-common/src/entities/cardano_database.rs @@ -1,5 +1,6 @@ use semver::Version; use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; use strum::EnumDiscriminants; use crate::{ @@ -10,6 +11,9 @@ use crate::{ /// Cardano database snapshot. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct CardanoDatabaseSnapshot { + /// Unique hash of the Cardano database snapshot. + pub hash: String, + /// Merkle root of the Cardano database snapshot. pub merkle_root: String, @@ -41,14 +45,28 @@ impl CardanoDatabaseSnapshot { ) -> Self { let cardano_node_version = format!("{cardano_node_version}"); - Self { + let mut cardano_database_snapshot = Self { + hash: "".to_string(), merkle_root, beacon, locations, total_db_size_uncompressed, compression_algorithm, cardano_node_version, - } + }; + + cardano_database_snapshot.hash = cardano_database_snapshot.compute_hash(); + + cardano_database_snapshot + } + + /// Cardano database snapshot hash computation + fn compute_hash(&self) -> String { + let mut hasher = Sha256::new(); + hasher.update(self.beacon.epoch.to_be_bytes()); + hasher.update(self.merkle_root.as_bytes()); + + hex::encode(hasher.finalize()) } } @@ -106,6 +124,109 @@ pub struct ArtifactsLocations { #[typetag::serde] impl Artifact for CardanoDatabaseSnapshot { fn get_id(&self) -> String { - self.merkle_root.clone() + self.hash.clone() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + fn dummy() -> CardanoDatabaseSnapshot { + CardanoDatabaseSnapshot::new( + "mk-root-1111111111".to_string(), + CardanoDbBeacon::new(2222, 55555), + 0, + ArtifactsLocations { + digests: vec![], + immutables: vec![], + ancillary: vec![], + }, + CompressionAlgorithm::Gzip, + &Version::new(1, 0, 0), + ) + } + + #[test] + fn test_cardano_database_snapshot_compute_hash() { + let cardano_database_snapshot = CardanoDatabaseSnapshot { + merkle_root: "mk-root-123".to_string(), + beacon: CardanoDbBeacon::new(123, 98), + ..dummy() + }; + + assert_eq!( + "b1cc5e0deaa7856e8e811e349d6e639fa667aa70288602955f438c5893ce29c8", + cardano_database_snapshot.compute_hash() + ); + } + + #[test] + fn compute_hash_returns_same_hash_with_same_cardano_database_snapshot() { + assert_eq!( + CardanoDatabaseSnapshot { + merkle_root: "mk-root-123".to_string(), + beacon: CardanoDbBeacon::new(123, 98), + ..dummy() + } + .compute_hash(), + CardanoDatabaseSnapshot { + merkle_root: "mk-root-123".to_string(), + beacon: CardanoDbBeacon::new(123, 98), + ..dummy() + } + .compute_hash() + ); + } + + #[test] + fn compute_hash_returns_different_hash_with_different_merkle_root() { + assert_ne!( + CardanoDatabaseSnapshot { + merkle_root: "mk-root-123".to_string(), + beacon: CardanoDbBeacon::new(123, 98), + ..dummy() + } + .compute_hash(), + CardanoDatabaseSnapshot { + merkle_root: "mk-root-456".to_string(), + beacon: CardanoDbBeacon::new(123, 98), + ..dummy() + } + .compute_hash() + ); + } + + #[test] + fn compute_hash_returns_different_hash_with_different_beacon() { + assert_eq!( + CardanoDatabaseSnapshot { + merkle_root: "mk-root-123".to_string(), + beacon: CardanoDbBeacon::new(123, 98), + ..dummy() + } + .compute_hash(), + CardanoDatabaseSnapshot { + merkle_root: "mk-root-123".to_string(), + beacon: CardanoDbBeacon::new(123, 12), + ..dummy() + } + .compute_hash() + ); + + assert_ne!( + CardanoDatabaseSnapshot { + merkle_root: "mk-root-123".to_string(), + beacon: CardanoDbBeacon::new(123, 98), + ..dummy() + } + .compute_hash(), + CardanoDatabaseSnapshot { + merkle_root: "mk-root-123".to_string(), + beacon: CardanoDbBeacon::new(456, 98), + ..dummy() + } + .compute_hash() + ); } }