1use chik_traits::chik_error::{Error, Result};
2
3fn add_catch_overflow(a: u64, b: u64) -> Result<u64> {
4 a.checked_add(b).ok_or(Error::InvalidPotIteration)
5}
6
7fn mult_catch_overflow(a: u64, b: u64) -> Result<u64> {
8 a.checked_mul(b).ok_or(Error::InvalidPotIteration)
9}
10
11fn mod_catch_error(a: u64, b: u64) -> Result<u64> {
12 a.checked_rem(b).ok_or(Error::InvalidPotIteration)
13}
14
15fn div_catch_error(a: u64, b: u64) -> Result<u64> {
16 a.checked_div(b).ok_or(Error::InvalidPotIteration)
17}
18
19pub fn is_overflow_block(
20 num_sps_sub_slot: u8,
21 num_sp_intervals_extra: u8,
22 signage_point_index: u8,
23) -> Result<bool> {
24 if signage_point_index >= num_sps_sub_slot {
25 return Err(Error::InvalidPotIteration);
26 }
27 Ok(signage_point_index
28 >= num_sps_sub_slot
29 .checked_sub(num_sp_intervals_extra)
30 .ok_or(Error::InvalidPotIteration)?)
31}
32
33pub fn calculate_sp_interval_iters(num_sps_sub_slot: u8, sub_slot_iters: u64) -> Result<u64> {
34 if mod_catch_error(sub_slot_iters, num_sps_sub_slot as u64)? != 0 {
35 return Err(Error::InvalidPotIteration);
36 }
37 div_catch_error(sub_slot_iters, num_sps_sub_slot as u64)
38}
39
40pub fn calculate_sp_iters(
41 num_sps_sub_slot: u8,
42 sub_slot_iters: u64,
43 signage_point_index: u8,
44) -> Result<u64> {
45 if signage_point_index >= num_sps_sub_slot {
46 return Err(Error::InvalidPotIteration);
47 }
48 mult_catch_overflow(
49 calculate_sp_interval_iters(num_sps_sub_slot, sub_slot_iters)?,
50 signage_point_index as u64,
51 )
52}
53
54pub fn calculate_ip_iters(
55 num_sps_sub_slot: u8,
56 num_sp_intervals_extra: u8,
57 sub_slot_iters: u64,
58 signage_point_index: u8,
59 required_iters: u64,
60) -> Result<u64> {
61 let sp_interval_iters = calculate_sp_interval_iters(num_sps_sub_slot, sub_slot_iters)?;
62 let sp_iters = calculate_sp_iters(num_sps_sub_slot, sub_slot_iters, signage_point_index)?;
63 if mod_catch_error(sp_iters, sp_interval_iters)? != 0
64 || sp_iters > sub_slot_iters
65 || required_iters >= sp_interval_iters
66 || required_iters == 0
67 {
68 return Err(Error::InvalidPotIteration);
69 }
70 mod_catch_error(
71 add_catch_overflow(
72 add_catch_overflow(
73 sp_iters,
74 mult_catch_overflow(num_sp_intervals_extra as u64, sp_interval_iters)?,
75 )?,
76 required_iters,
77 )?,
78 sub_slot_iters,
79 )
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85 static NUM_SPS_SUB_SLOT: u8 = 32;
86 static NUM_SP_INTERVALS_EXTRA: u8 = 3;
87
88 #[test]
89 fn test_is_overflow_block() {
90 assert!(
91 !is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 27)
92 .expect("valid SP index")
93 );
94 assert!(
95 !is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 28)
96 .expect("valid SP index")
97 );
98 assert!(
99 is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 29)
100 .expect("valid SP index")
101 );
102 assert!(
103 is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 30)
104 .expect("valid SP index")
105 );
106 assert!(
107 is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 31)
108 .expect("valid SP index")
109 );
110 assert!(is_overflow_block(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, 32).is_err());
111 }
112
113 #[test]
114 fn test_calculate_sp_iters() {
115 let ssi: u64 = 100_001 * 64 * 4;
116 assert!(calculate_sp_iters(NUM_SPS_SUB_SLOT, ssi, 32).is_err());
117 calculate_sp_iters(NUM_SPS_SUB_SLOT, ssi, 31).expect("valid_result");
118 }
119
120 #[test]
121 fn test_calculate_ip_iters() {
122 let ssi: u64 = 100_001 * 64 * 4;
128 let sp_interval_iters = ssi / NUM_SPS_SUB_SLOT as u64;
129
130 assert_eq!(
132 calculate_ip_iters(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, 123, 100_000)
133 .unwrap_err(),
134 Error::InvalidPotIteration
135 );
136
137 let sp_iters = sp_interval_iters * 13;
138
139 assert_eq!(
141 calculate_ip_iters(
142 NUM_SPS_SUB_SLOT,
143 NUM_SP_INTERVALS_EXTRA,
144 ssi,
145 13,
146 sp_interval_iters
147 )
148 .unwrap_err(),
149 Error::InvalidPotIteration
150 );
151
152 assert_eq!(
154 calculate_ip_iters(
155 NUM_SPS_SUB_SLOT,
156 NUM_SP_INTERVALS_EXTRA,
157 ssi,
158 13,
159 sp_interval_iters * 12
160 )
161 .unwrap_err(),
162 Error::InvalidPotIteration
163 );
164
165 assert_eq!(
167 calculate_ip_iters(NUM_SPS_SUB_SLOT, NUM_SP_INTERVALS_EXTRA, ssi, 255, 0).unwrap_err(),
168 Error::InvalidPotIteration
169 );
170
171 let required_iters = sp_interval_iters - 1;
172 let ip_iters = calculate_ip_iters(
173 NUM_SPS_SUB_SLOT,
174 NUM_SP_INTERVALS_EXTRA,
175 ssi,
176 13,
177 required_iters,
178 )
179 .expect("should be valid");
180 assert_eq!(
181 ip_iters,
182 sp_iters + (NUM_SP_INTERVALS_EXTRA as u64 * sp_interval_iters) + required_iters
183 );
184
185 let required_iters = 1_u64;
186 let ip_iters = calculate_ip_iters(
187 NUM_SPS_SUB_SLOT,
188 NUM_SP_INTERVALS_EXTRA,
189 ssi,
190 13,
191 required_iters,
192 )
193 .expect("valid");
194 assert_eq!(
195 ip_iters,
196 sp_iters + (NUM_SP_INTERVALS_EXTRA as u64 * sp_interval_iters) + required_iters
197 );
198
199 let required_iters: u64 = ssi * 4 / 300;
200 let ip_iters = calculate_ip_iters(
201 NUM_SPS_SUB_SLOT,
202 NUM_SP_INTERVALS_EXTRA,
203 ssi,
204 13,
205 required_iters,
206 )
207 .expect("valid");
208 assert_eq!(
209 ip_iters,
210 sp_iters + (NUM_SP_INTERVALS_EXTRA as u64 * sp_interval_iters) + required_iters
211 );
212 assert!(sp_iters < ip_iters);
213
214 let sp_iters = sp_interval_iters * (NUM_SPS_SUB_SLOT - 1) as u64;
216 let ip_iters = calculate_ip_iters(
217 NUM_SPS_SUB_SLOT,
218 NUM_SP_INTERVALS_EXTRA,
219 ssi,
220 NUM_SPS_SUB_SLOT - 1,
221 required_iters,
222 )
223 .expect("valid");
224 assert_eq!(
225 ip_iters,
226 (sp_iters + (NUM_SP_INTERVALS_EXTRA as u64 * sp_interval_iters) + required_iters) % ssi
227 );
228 assert!(sp_iters > ip_iters);
229 }
230}