chik_protocol/
pot_iterations.rs

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        // # num_sps_sub_slot: u32,
125        // # num_sp_intervals_extra: u8,
126        // # sub_slot_iters: u64,
127        // # signage_point_index: u8,
128        // # required_iters: u64,
129        let ssi: u64 = 100_001 * 64 * 4;
130        let sp_interval_iters = ssi / NUM_SPS_SUB_SLOT as u64;
131
132        // Invalid signage point index
133        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        // required_iters too high
142        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        // required_iters too high
155        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        // required_iters too low (0)
168        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        // Overflow
217        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}