snarkvm_ledger/
is_solution_limit_reached.rs1use super::*;
17
18pub(super) const MAINNET_STAKE_REQUIREMENTS_PER_SOLUTION: [(i64, u64); 9] = [
20 (1754006399i64, 100_000_000_000u64), (1761955199i64, 250_000_000_000u64), (1769903999i64, 500_000_000_000u64), (1777593599i64, 750_000_000_000u64), (1785542399i64, 1_000_000_000_000u64), (1793491199i64, 1_250_000_000_000u64), (1801439999i64, 1_500_000_000_000u64), (1809129599i64, 2_000_000_000_000u64), (1817078399i64, 2_500_000_000_000u64), ];
30
31pub(super) const CANARY_AND_TESTNET_STAKE_REQUIREMENTS_PER_SOLUTION: [(i64, u64); 9] = [
33 (1754006399i64, 1_000_000_000u64), (1761955199i64, 2_500_000_000u64), (1769903999i64, 5_000_000_000u64), (1777593599i64, 7_500_000_000u64), (1785542399i64, 10_000_000_000u64), (1793491199i64, 12_500_000_000u64), (1801439999i64, 15_000_000_000u64), (1809129599i64, 20_000_000_000u64), (1817078399i64, 25_000_000_000u64), ];
43
44pub fn stake_requirements_per_solution<N: Network>() -> &'static [(i64, u64)] {
53 match N::ID {
54 console::network::MainnetV0::ID => &MAINNET_STAKE_REQUIREMENTS_PER_SOLUTION,
55 console::network::TestnetV0::ID | console::network::CanaryV0::ID => {
56 &CANARY_AND_TESTNET_STAKE_REQUIREMENTS_PER_SOLUTION
57 }
58 _ => &MAINNET_STAKE_REQUIREMENTS_PER_SOLUTION,
59 }
60}
61
62pub fn maximum_allowed_solutions_per_epoch<N: Network>(prover_stake: u64, current_time: i64) -> u64 {
64 let stake_requirements = stake_requirements_per_solution::<N>();
65
66 if current_time < stake_requirements.first().map(|(t, _)| *t).unwrap_or(i64::MAX) {
68 return u64::MAX;
69 }
70
71 let minimum_stake_per_solution_per_epoch = match stake_requirements.binary_search_by_key(¤t_time, |(t, _)| *t)
73 {
74 Ok(index) => stake_requirements[index].1,
76 Err(index) => stake_requirements[index.saturating_sub(1)].1,
78 };
79
80 prover_stake.saturating_div(minimum_stake_per_solution_per_epoch)
82}
83
84impl<N: Network, C: ConsensusStorage<N>> Ledger<N, C> {
85 pub fn num_remaining_solutions(&self, prover_address: &Address<N>, additional_solutions_in_block: u64) -> u64 {
87 let prover_stake = self.get_bonded_amount(prover_address).unwrap_or(0);
89
90 let maximum_allowed_solutions = maximum_allowed_solutions_per_epoch::<N>(prover_stake, self.latest_timestamp());
92
93 let prover_num_solutions_in_epoch = *self.epoch_provers_cache.read().get(prover_address).unwrap_or(&0);
95
96 let num_solutions = (prover_num_solutions_in_epoch as u64).saturating_add(additional_solutions_in_block);
98
99 maximum_allowed_solutions.saturating_sub(num_solutions)
101 }
102
103 pub fn is_solution_limit_reached(&self, prover_address: &Address<N>, additional_solutions_in_block: u64) -> bool {
105 let num_remaining_solutions = self.num_remaining_solutions(prover_address, additional_solutions_in_block);
107
108 num_remaining_solutions == 0
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 type CurrentNetwork = console::network::MainnetV0;
118
119 const ITERATIONS: u64 = 100;
120
121 #[test]
122 fn test_solution_limit_per_epoch() {
123 let mut rng = TestRng::default();
124 let stake_requirements = stake_requirements_per_solution::<CurrentNetwork>();
125
126 for _ in 0..ITERATIONS {
127 for window in stake_requirements.windows(2) {
128 let (prev_time, stake_per_solution) = window[0];
129 let (next_time, _) = window[1];
130
131 let timestamp = rng.gen_range(prev_time..next_time);
133 let prover_stake: u64 = rng.r#gen();
135 let expected_num_solutions = prover_stake / stake_per_solution;
136
137 assert_eq!(
138 maximum_allowed_solutions_per_epoch::<CurrentNetwork>(prover_stake, timestamp),
139 expected_num_solutions,
140 );
141 }
142 }
143 }
144
145 #[test]
146 fn test_solution_limit_before_enforcement() {
147 let mut rng = TestRng::default();
148 let stake_requirements = stake_requirements_per_solution::<CurrentNetwork>();
149
150 let first_timestamp = stake_requirements.first().unwrap().0;
152 let time_before_first = first_timestamp - 1;
153
154 let prover_stake = 0;
156 assert_eq!(maximum_allowed_solutions_per_epoch::<CurrentNetwork>(prover_stake, time_before_first), u64::MAX);
157
158 for _ in 0..ITERATIONS {
160 assert_eq!(
161 maximum_allowed_solutions_per_epoch::<CurrentNetwork>(rng.r#gen(), rng.gen_range(0..time_before_first)),
162 u64::MAX
163 );
164 }
165 }
166
167 #[test]
168 fn test_solution_limit_after_final_timestamp() {
169 let mut rng = TestRng::default();
170 let stake_requirements = stake_requirements_per_solution::<CurrentNetwork>();
171 let (last_timestamp, stake_per_solution) = *stake_requirements.last().unwrap();
172
173 for _ in 0..ITERATIONS {
175 let prover_stake: u64 = rng.r#gen();
176 let time_after_last = rng.gen_range(last_timestamp..i64::MAX);
177 let expected_num_solutions = prover_stake / stake_per_solution;
178
179 assert_eq!(
180 maximum_allowed_solutions_per_epoch::<CurrentNetwork>(prover_stake, time_after_last),
181 expected_num_solutions
182 );
183 }
184 }
185
186 #[test]
187 fn test_solution_limit_exact_timestamps() {
188 let mut rng = TestRng::default();
189 let stake_requirements = stake_requirements_per_solution::<CurrentNetwork>();
190 for &(timestamp, stake_per_solution) in stake_requirements.iter() {
192 let expected_num_solutions = rng.gen_range(1..=100);
193 let prover_stake = expected_num_solutions * stake_per_solution;
194
195 assert_eq!(
196 maximum_allowed_solutions_per_epoch::<CurrentNetwork>(prover_stake, timestamp),
197 expected_num_solutions,
198 );
199 }
200 }
201}