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