use semver::Version;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use strum::EnumDiscriminants;
use crate::{
entities::{CardanoDbBeacon, CompressionAlgorithm},
signable_builder::Artifact,
};
use super::MultiFilesUri;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct CardanoDatabaseSnapshot {
pub hash: String,
pub merkle_root: String,
pub beacon: CardanoDbBeacon,
pub total_db_size_uncompressed: u64,
pub locations: ArtifactsLocations,
pub compression_algorithm: CompressionAlgorithm,
pub cardano_node_version: String,
}
impl CardanoDatabaseSnapshot {
pub fn new(
merkle_root: String,
beacon: CardanoDbBeacon,
total_db_size_uncompressed: u64,
locations: ArtifactsLocations,
compression_algorithm: CompressionAlgorithm,
cardano_node_version: &Version,
) -> Self {
let cardano_node_version = format!("{cardano_node_version}");
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
}
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())
}
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "snake_case", tag = "type")]
pub enum DigestLocation {
Aggregator {
uri: String,
},
CloudStorage {
uri: String,
},
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "snake_case", tag = "type")]
pub enum ImmutablesLocation {
CloudStorage {
uri: MultiFilesUri,
},
}
#[derive(
Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, EnumDiscriminants,
)]
#[serde(rename_all = "snake_case", tag = "type")]
pub enum AncillaryLocation {
CloudStorage {
uri: String,
},
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct ArtifactsLocations {
pub digests: Vec<DigestLocation>,
pub immutables: Vec<ImmutablesLocation>,
pub ancillary: Vec<AncillaryLocation>,
}
#[typetag::serde]
impl Artifact for CardanoDatabaseSnapshot {
fn get_id(&self) -> String {
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),
)
}
mod cardano_database_snapshot_compute_hash {
use super::*;
#[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_same_epoch_in_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()
);
}
#[test]
fn compute_hash_returns_different_hash_with_different_beacon() {
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()
);
}
}
}