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::{builder::MithrilFixtureBuilder, double::fake_data};
60
61 use super::*;
62
63 #[cfg(not(feature = "future_snark"))]
64 const EXPECTED_HASH: &str = "c5c1ff02e37c751329e3db7625c77fa2a24e86b2a75422c54f1b9f9232374d6f";
65 #[cfg(feature = "future_snark")]
66 const EXPECTED_HASH: &str = "aafc009f81c97622f4a4695acf218447585648c8ff56ec16837b842e9557b1aa";
67
68 #[test]
69 fn test_compute_hash() {
70 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
71 let stake_distribution = MithrilStakeDistribution::new(
72 Epoch(1),
73 fixtures.signers_with_stake(),
74 &fake_data::protocol_parameters(),
75 );
76
77 assert_eq!(EXPECTED_HASH.to_owned(), stake_distribution.compute_hash());
78 }
79
80 #[test]
81 fn test_hash_fail_for_different_stake() {
82 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
83 let mut signers = fixtures.signers_with_stake();
84 signers[0].stake += 1;
85 let stake_distribution =
86 MithrilStakeDistribution::new(Epoch(1), signers, &fake_data::protocol_parameters());
87
88 assert_ne!(EXPECTED_HASH.to_owned(), stake_distribution.compute_hash());
89 }
90
91 #[test]
92 fn test_hash_fail_for_different_epoch() {
93 let fixtures = MithrilFixtureBuilder::default().with_signers(10).build();
94 let stake_distribution = MithrilStakeDistribution::new(
95 Epoch(2),
96 fixtures.signers_with_stake(),
97 &fake_data::protocol_parameters(),
98 );
99
100 assert_ne!(EXPECTED_HASH.to_owned(), stake_distribution.compute_hash());
101 }
102
103 #[test]
104 fn test_independence_protocol_parameters() {
105 let signers = MithrilFixtureBuilder::default()
106 .with_signers(10)
107 .build()
108 .signers_with_stake();
109 let protocol_parameters = ProtocolParameters {
110 k: 100,
111 m: 0,
112 phi_f: 0.0,
113 };
114 let stake_distribution =
115 MithrilStakeDistribution::new(Epoch(1), signers, &protocol_parameters);
116
117 assert_eq!(EXPECTED_HASH.to_owned(), stake_distribution.compute_hash());
118 }
119}