mithril_common/entities/
mithril_stake_distribution.rs1use serde::{Deserialize, Serialize};
2use sha2::{Digest, Sha256};
3
4use crate::entities::{Epoch, SignerWithStake};
5
6use super::ProtocolParameters;
7
8#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
10pub struct MithrilStakeDistribution {
11 pub epoch: Epoch,
13
14 pub signers_with_stake: Vec<SignerWithStake>,
16
17 pub hash: String,
19
20 pub protocol_parameters: ProtocolParameters,
22}
23
24impl MithrilStakeDistribution {
25 pub fn new(
27 epoch: Epoch,
28 signers_with_stake: Vec<SignerWithStake>,
29 protocol_parameters: &ProtocolParameters,
30 ) -> Self {
31 let mut signers_with_stake_sorted = signers_with_stake;
32 signers_with_stake_sorted.sort();
33 let mut mithril_stake_distribution: MithrilStakeDistribution = Self {
34 epoch,
35 signers_with_stake: signers_with_stake_sorted,
36 hash: "".to_string(),
37 protocol_parameters: protocol_parameters.to_owned(),
38 };
39 mithril_stake_distribution.hash = mithril_stake_distribution.compute_hash();
40 mithril_stake_distribution
41 }
42
43 fn compute_hash(&self) -> String {
46 let mut hasher = Sha256::new();
47 hasher.update(self.epoch.to_be_bytes());
48
49 for signer_with_stake in &self.signers_with_stake {
50 hasher.update(signer_with_stake.compute_hash().as_bytes());
51 }
52
53 hex::encode(hasher.finalize())
54 }
55}
56
57#[cfg(test)]
58mod tests {
59 use crate::test_utils::{fake_data, MithrilFixtureBuilder};
60
61 use super::*;
62
63 const EXPECTED_HASH: &str = "c5c1ff02e37c751329e3db7625c77fa2a24e86b2a75422c54f1b9f9232374d6f";
64
65 #[test]
66 fn test_compute_hash() {
67 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
68 let stake_distribution = MithrilStakeDistribution::new(
69 Epoch(1),
70 fixtures.signers_with_stake(),
71 &fake_data::protocol_parameters(),
72 );
73
74 assert_eq!(EXPECTED_HASH.to_owned(), stake_distribution.compute_hash());
75 }
76
77 #[test]
78 fn test_hash_fail_for_different_stake() {
79 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
80 let mut signers = fixtures.signers_with_stake();
81 signers[0].stake += 1;
82 let stake_distribution =
83 MithrilStakeDistribution::new(Epoch(1), signers, &fake_data::protocol_parameters());
84
85 assert_ne!(EXPECTED_HASH.to_owned(), stake_distribution.compute_hash());
86 }
87
88 #[test]
89 fn test_hash_fail_for_different_epoch() {
90 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
91 let stake_distribution = MithrilStakeDistribution::new(
92 Epoch(2),
93 fixtures.signers_with_stake(),
94 &fake_data::protocol_parameters(),
95 );
96
97 assert_ne!(EXPECTED_HASH.to_owned(), stake_distribution.compute_hash());
98 }
99
100 #[test]
101 fn test_independence_protocol_parameters() {
102 let signers = MithrilFixtureBuilder::default()
103 .with_signers(10)
104 .build()
105 .signers_with_stake();
106 let protocol_parameters = ProtocolParameters {
107 k: 100,
108 m: 0,
109 phi_f: 0.0,
110 };
111 let stake_distribution =
112 MithrilStakeDistribution::new(Epoch(1), signers, &protocol_parameters);
113
114 assert_eq!(EXPECTED_HASH.to_owned(), stake_distribution.compute_hash());
115 }
116}