snarkvm_synthesizer/restrictions/helpers/
block_range.rs

1// Copyright (c) 2019-2025 Provable Inc.
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use console::{
17    network::Network,
18    prelude::{Deserialize, Deserializer, EnumAccess, One, Result, Serialize, Serializer, VariantAccess, Visitor, de},
19    types::Field,
20};
21
22use core::{
23    fmt,
24    ops::{Range, RangeFrom, RangeInclusive, RangeTo},
25};
26
27#[derive(Debug, Clone, PartialEq, Eq)]
28pub enum BlockRange {
29    Range(Range<u32>),
30    RangeFrom(RangeFrom<u32>),
31    RangeTo(RangeTo<u32>),
32    RangeInclusive(RangeInclusive<u32>),
33    FullRange,
34}
35
36impl BlockRange {
37    /// Returns `true` if the block range contains the specified block height.
38    pub fn contains(&self, height: u32) -> bool {
39        match self {
40            BlockRange::Range(range) => range.contains(&height),
41            BlockRange::RangeFrom(range) => range.contains(&height),
42            BlockRange::RangeTo(range) => range.contains(&height),
43            BlockRange::RangeInclusive(range) => range.contains(&height),
44            BlockRange::FullRange => true,
45        }
46    }
47}
48
49impl BlockRange {
50    /// Returns a unique field element encoding of the block range.
51    pub fn to_fields<N: Network>(&self) -> Result<Vec<Field<N>>> {
52        match self {
53            BlockRange::Range(range) => {
54                Ok(vec![Field::from_u8(0), Field::from_u32(range.start), Field::from_u32(range.end)])
55            }
56            BlockRange::RangeFrom(range) => Ok(vec![Field::from_u8(1), Field::from_u32(range.start), -Field::one()]),
57            BlockRange::RangeTo(range) => Ok(vec![Field::from_u8(2), -Field::one(), Field::from_u32(range.end)]),
58            BlockRange::RangeInclusive(range) => {
59                Ok(vec![Field::from_u8(3), Field::from_u32(*range.start()), Field::from_u32(*range.end())])
60            }
61            BlockRange::FullRange => Ok(vec![Field::from_u8(4), -Field::one(), -Field::one()]),
62        }
63    }
64}
65
66impl Serialize for BlockRange {
67    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
68    where
69        S: Serializer,
70    {
71        match self {
72            BlockRange::Range(range) => {
73                serializer.serialize_newtype_variant("BlockRange", 0, "Range", &(range.start, range.end))
74            }
75            BlockRange::RangeFrom(range) => {
76                serializer.serialize_newtype_variant("BlockRange", 1, "RangeFrom", &range.start)
77            }
78            BlockRange::RangeTo(range) => serializer.serialize_newtype_variant("BlockRange", 2, "RangeTo", &range.end),
79            BlockRange::RangeInclusive(range) => {
80                serializer.serialize_newtype_variant("BlockRange", 3, "RangeInclusive", &(range.start(), range.end()))
81            }
82            BlockRange::FullRange => serializer.serialize_newtype_variant("BlockRange", 4, "FullRange", &()),
83        }
84    }
85}
86
87impl<'de> Deserialize<'de> for BlockRange {
88    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
89    where
90        D: Deserializer<'de>,
91    {
92        enum Field {
93            Range,
94            RangeFrom,
95            RangeTo,
96            RangeInclusive,
97            FullRange,
98        }
99
100        impl<'de> Deserialize<'de> for Field {
101            fn deserialize<D>(deserializer: D) -> Result<Field, D::Error>
102            where
103                D: Deserializer<'de>,
104            {
105                struct FieldVisitor;
106
107                impl Visitor<'_> for FieldVisitor {
108                    type Value = Field;
109
110                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
111                        formatter.write_str("`Range`, `RangeFrom`, `RangeTo`, `RangeInclusive`, or `FullRange`")
112                    }
113
114                    fn visit_str<E>(self, value: &str) -> Result<Field, E>
115                    where
116                        E: de::Error,
117                    {
118                        match value {
119                            "Range" => Ok(Field::Range),
120                            "RangeFrom" => Ok(Field::RangeFrom),
121                            "RangeTo" => Ok(Field::RangeTo),
122                            "RangeInclusive" => Ok(Field::RangeInclusive),
123                            "FullRange" => Ok(Field::FullRange),
124                            _ => Err(de::Error::unknown_field(value, FIELDS)),
125                        }
126                    }
127                }
128
129                deserializer.deserialize_identifier(FieldVisitor)
130            }
131        }
132
133        struct BlockRangeVisitor;
134
135        impl<'de> Visitor<'de> for BlockRangeVisitor {
136            type Value = BlockRange;
137
138            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
139                formatter.write_str("struct BlockRange")
140            }
141
142            fn visit_enum<A>(self, data: A) -> Result<BlockRange, A::Error>
143            where
144                A: EnumAccess<'de>,
145            {
146                let (field, variant) = data.variant()?;
147                match field {
148                    Field::Range => {
149                        let (start, end): (u32, u32) = variant.newtype_variant()?;
150                        Ok(BlockRange::Range(start..end))
151                    }
152                    Field::RangeFrom => {
153                        let start: u32 = variant.newtype_variant()?;
154                        Ok(BlockRange::RangeFrom(RangeFrom { start }))
155                    }
156                    Field::RangeTo => {
157                        let end: u32 = variant.newtype_variant()?;
158                        Ok(BlockRange::RangeTo(RangeTo { end }))
159                    }
160                    Field::RangeInclusive => {
161                        let (start, end): (u32, u32) = variant.newtype_variant()?;
162                        Ok(BlockRange::RangeInclusive(RangeInclusive::new(start, end)))
163                    }
164                    Field::FullRange => {
165                        variant.unit_variant()?;
166                        Ok(BlockRange::FullRange)
167                    }
168                }
169            }
170        }
171
172        const FIELDS: &[&str] = &["Range", "RangeFrom", "RangeTo", "RangeInclusive", "FullRange"];
173        deserializer.deserialize_enum("BlockRange", FIELDS, BlockRangeVisitor)
174    }
175}
176
177#[cfg(test)]
178mod tests {
179    use super::*;
180
181    type CurrentNetwork = console::network::MainnetV0;
182
183    #[test]
184    fn test_serialize_range() {
185        let range = BlockRange::Range(1..10);
186        let serialized = serde_json::to_string(&range).unwrap();
187        assert_eq!(serialized, r#"{"Range":[1,10]}"#);
188    }
189
190    #[test]
191    fn test_deserialize_range() {
192        let serialized = r#"{"Range":[1,10]}"#;
193        let deserialized: BlockRange = serde_json::from_str(serialized).unwrap();
194        assert_eq!(deserialized, BlockRange::Range(1..10));
195    }
196
197    #[test]
198    fn test_serialize_range_from() {
199        let range = BlockRange::RangeFrom(RangeFrom { start: 5 });
200        let serialized = serde_json::to_string(&range).unwrap();
201        assert_eq!(serialized, r#"{"RangeFrom":5}"#);
202    }
203
204    #[test]
205    fn test_deserialize_range_from() {
206        let serialized = r#"{"RangeFrom":5}"#;
207        let deserialized: BlockRange = serde_json::from_str(serialized).unwrap();
208        assert_eq!(deserialized, BlockRange::RangeFrom(RangeFrom { start: 5 }));
209    }
210
211    #[test]
212    fn test_serialize_range_to() {
213        let range = BlockRange::RangeTo(RangeTo { end: 8 });
214        let serialized = serde_json::to_string(&range).unwrap();
215        assert_eq!(serialized, r#"{"RangeTo":8}"#);
216    }
217
218    #[test]
219    fn test_deserialize_range_to() {
220        let serialized = r#"{"RangeTo":8}"#;
221        let deserialized: BlockRange = serde_json::from_str(serialized).unwrap();
222        assert_eq!(deserialized, BlockRange::RangeTo(RangeTo { end: 8 }));
223    }
224
225    #[test]
226    fn test_serialize_range_inclusive() {
227        let range = BlockRange::RangeInclusive(RangeInclusive::new(2, 9));
228        let serialized = serde_json::to_string(&range).unwrap();
229        assert_eq!(serialized, r#"{"RangeInclusive":[2,9]}"#);
230    }
231
232    #[test]
233    fn test_deserialize_range_inclusive() {
234        let serialized = r#"{"RangeInclusive":[2,9]}"#;
235        let deserialized: BlockRange = serde_json::from_str(serialized).unwrap();
236        assert_eq!(deserialized, BlockRange::RangeInclusive(RangeInclusive::new(2, 9)));
237    }
238
239    #[test]
240    fn test_serialize_full_range() {
241        let range = BlockRange::FullRange;
242        let serialized = serde_json::to_string(&range).unwrap();
243        assert_eq!(serialized, r#"{"FullRange":null}"#);
244    }
245
246    #[test]
247    fn test_deserialize_full_range() {
248        let serialized = r#"{"FullRange":null}"#;
249        let deserialized: BlockRange = serde_json::from_str(serialized).unwrap();
250        assert_eq!(deserialized, BlockRange::FullRange);
251    }
252
253    #[test]
254    fn test_deserialize_error() {
255        let serialized = r#"{"InvalidRange":[1,2]}"#;
256        let result: Result<BlockRange, _> = serde_json::from_str(serialized);
257        assert!(result.is_err());
258    }
259
260    #[test]
261    fn test_deserialize_missing_field() {
262        let serialized = r#"{}"#;
263        let result: Result<BlockRange, _> = serde_json::from_str(serialized);
264        assert!(result.is_err());
265    }
266
267    #[test]
268    fn test_contains() {
269        let range = BlockRange::Range(1..10);
270        assert!(range.contains(1));
271        assert!(range.contains(5));
272        assert!(range.contains(9));
273        assert!(!range.contains(10));
274
275        let range = BlockRange::RangeFrom(RangeFrom { start: 5 });
276        assert!(!range.contains(4));
277        assert!(range.contains(5));
278        assert!(range.contains(6));
279
280        let range = BlockRange::RangeTo(RangeTo { end: 8 });
281        assert!(range.contains(7));
282        assert!(!range.contains(8));
283        assert!(!range.contains(9));
284
285        let range = BlockRange::RangeInclusive(RangeInclusive::new(2, 9));
286        assert!(!range.contains(1));
287        assert!(range.contains(2));
288        assert!(range.contains(9));
289        assert!(!range.contains(10));
290
291        let range = BlockRange::FullRange;
292        assert!(range.contains(0));
293        assert!(range.contains(1));
294        assert!(range.contains(1000));
295    }
296
297    #[test]
298    fn test_to_fields() {
299        let range = BlockRange::Range(1..10);
300        let fields = range.to_fields::<CurrentNetwork>().unwrap();
301        assert_eq!(fields, vec![Field::from_u8(0), Field::from_u32(1), Field::from_u32(10)]);
302
303        let range = BlockRange::RangeFrom(RangeFrom { start: 5 });
304        let fields = range.to_fields::<CurrentNetwork>().unwrap();
305        assert_eq!(fields, vec![Field::from_u8(1), Field::from_u32(5), -Field::one()]);
306
307        let range = BlockRange::RangeTo(RangeTo { end: 8 });
308        let fields = range.to_fields::<CurrentNetwork>().unwrap();
309        assert_eq!(fields, vec![Field::from_u8(2), -Field::one(), Field::from_u32(8)]);
310
311        let range = BlockRange::RangeInclusive(RangeInclusive::new(2, 9));
312        let fields = range.to_fields::<CurrentNetwork>().unwrap();
313        assert_eq!(fields, vec![Field::from_u8(3), Field::from_u32(2), Field::from_u32(9)]);
314
315        let range = BlockRange::FullRange;
316        let fields = range.to_fields::<CurrentNetwork>().unwrap();
317        assert_eq!(fields, vec![Field::from_u8(4), -Field::one(), -Field::one()]);
318    }
319}