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 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        // # num_sps_sub_slot: u8,
123        // # num_sp_intervals_extra: u8,
124        // # sub_slot_iters: u64,
125        // # signage_point_index: u8,
126        // # required_iters: u64,
127        let ssi: u64 = 100_001 * 64 * 4;
128        let sp_interval_iters = ssi / NUM_SPS_SUB_SLOT as u64;
129
130        // Invalid signage point index
131        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        // required_iters too high
140        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        // required_iters too high
153        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        // required_iters too low (0)
166        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        // Overflow
215        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}