snarkvm_synthesizer/restrictions/
serialize.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 super::*;
17
18use snarkvm_utilities::DeserializeExt;
19
20impl<N: Network + Serialize> Serialize for Restrictions<N> {
21    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
22    where
23        S: Serializer,
24    {
25        let mut state = serializer.serialize_struct("Restrictions", 4)?;
26        state.serialize_field("restrictions_id", &self.restrictions_id)?;
27        state.serialize_field("programs", &self.programs)?;
28        state.serialize_field("functions", &self.functions)?;
29        state.serialize_field("arguments", &self.arguments)?;
30        state.end()
31    }
32}
33
34impl<'de, N: Network> Deserialize<'de> for Restrictions<N> {
35    /// Deserializes the restrictions from a JSON-string.
36    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
37        let mut restrictions = serde_json::Value::deserialize(deserializer)?;
38
39        // Recover the restrictions.
40        Ok(Self {
41            restrictions_id: DeserializeExt::take_from_value::<D>(&mut restrictions, "restrictions_id")?,
42            programs: DeserializeExt::take_from_value::<D>(&mut restrictions, "programs")?,
43            functions: DeserializeExt::take_from_value::<D>(&mut restrictions, "functions")?,
44            arguments: DeserializeExt::take_from_value::<D>(&mut restrictions, "arguments")?,
45        })
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52    use console::types::Address;
53
54    use rand::seq::SliceRandom;
55
56    type CurrentNetwork = console::network::MainnetV0;
57
58    const ITERATIONS: usize = 100;
59
60    const TEST_PROGRAM_CASES: &[&str] = &["testing.aleo", "hello.aleo", "abc_def.aleo", "a1234.aleo"];
61    const TEST_FUNCTION_CASES: &[&str] = &["testing", "transfer", "hello", "foo", "bar"];
62
63    /// Randomly select a program ID from the given test cases.
64    fn sample_program_id<R: Rng + CryptoRng>(rng: &mut R) -> ProgramID<CurrentNetwork> {
65        ProgramID::from_str(TEST_PROGRAM_CASES.choose(rng).unwrap()).unwrap()
66    }
67
68    /// Randomly select a program and function name from the given test cases.
69    fn sample_locator<R: Rng + CryptoRng>(rng: &mut R) -> Locator<CurrentNetwork> {
70        let program_id = ProgramID::from_str(TEST_PROGRAM_CASES.choose(rng).unwrap()).unwrap();
71        let function_name = Identifier::from_str(TEST_FUNCTION_CASES.choose(rng).unwrap()).unwrap();
72        Locator::new(program_id, function_name)
73    }
74
75    /// Randomly sample a block range.
76    fn sample_block_range<R: Rng + CryptoRng>(rng: &mut R) -> BlockRange {
77        let variant = rng.gen_range(0..5);
78        match variant {
79            0 => {
80                let start = rng.r#gen();
81                let end = rng.gen_range(start..=u32::MAX);
82                BlockRange::Range(start..end)
83            }
84            1 => BlockRange::RangeFrom(rng.r#gen()..),
85            2 => BlockRange::RangeTo(..rng.r#gen()),
86            3 => {
87                let start = rng.r#gen();
88                let end = rng.gen_range(start..=u32::MAX);
89                BlockRange::RangeInclusive(start..=end)
90            }
91            4 => BlockRange::FullRange,
92            _ => unreachable!(),
93        }
94    }
95
96    /// Randomly sample a set of restrictions.
97    fn sample_restrictions<R: Rng + CryptoRng>(rng: &mut R) -> Restrictions<CurrentNetwork> {
98        const NUM_RESTRICTIONS: usize = 10;
99
100        let mut restrictions = Restrictions::<CurrentNetwork>::new_blank().unwrap();
101        // Add the program restrictions.
102        for _ in 0..NUM_RESTRICTIONS {
103            let program_id = sample_program_id(rng);
104            let range = sample_block_range(rng);
105            restrictions.programs.insert(program_id, range);
106        }
107        // Add the function restrictions.
108        for _ in 0..NUM_RESTRICTIONS {
109            let locator = sample_locator(rng);
110            let range = sample_block_range(rng);
111            restrictions.functions.insert(locator, range);
112        }
113        // Add the argument restrictions.
114        for _ in 0..NUM_RESTRICTIONS {
115            let locator = sample_locator(rng);
116
117            // Add the argument locators.
118            let mut arguments = IndexMap::new();
119            for _ in 0..NUM_RESTRICTIONS {
120                let argument_locator = ArgumentLocator::new(rng.r#gen(), rng.gen_range(0..16));
121
122                // Add the literals.
123                let mut literals = IndexMap::new();
124                for _ in 0..NUM_RESTRICTIONS {
125                    let literal = Literal::Address(Address::rand(rng));
126                    let range = sample_block_range(rng);
127                    literals.insert(literal, range);
128                }
129                arguments.insert(argument_locator, literals);
130            }
131            restrictions.arguments.insert(locator, arguments);
132        }
133        // Set the restrictions ID.
134        restrictions.restrictions_id = Restrictions::compute_restrictions_id(
135            &restrictions.programs,
136            &restrictions.functions,
137            &restrictions.arguments,
138        )
139        .unwrap();
140        // Return the restrictions.
141        restrictions
142    }
143
144    fn check_serde_json<T: Serialize + for<'a> Deserialize<'a> + Debug + Display + PartialEq + Eq + FromStr>(
145        expected: T,
146    ) {
147        // Serialize
148        let expected_string = expected.to_string();
149        let candidate_string = serde_json::to_string_pretty(&expected).unwrap();
150        let candidate = serde_json::from_str::<T>(&candidate_string).unwrap();
151        assert_eq!(expected, candidate);
152        assert_eq!(expected_string, candidate_string);
153        assert_eq!(expected_string, candidate.to_string());
154
155        // Deserialize
156        assert_eq!(expected, T::from_str(&expected_string).unwrap_or_else(|_| panic!("FromStr: {expected_string}")));
157        assert_eq!(expected, serde_json::from_str(&candidate_string).unwrap());
158    }
159
160    #[test]
161    fn test_serde_json() {
162        let rng = &mut TestRng::default();
163
164        for _ in 0..ITERATIONS {
165            let expected = sample_restrictions(rng);
166            check_serde_json(expected);
167        }
168    }
169}