/ synthesizer / src / restrictions / serialize.rs
serialize.rs
  1  // Copyright (c) 2025 ADnet Contributors
  2  // This file is part of the AlphaVM 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  
 16  use super::*;
 17  
 18  use alphavm_utilities::DeserializeExt;
 19  
 20  impl<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  
 34  impl<'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)]
 50  mod 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.alpha", "hello.alpha", "abc_def.alpha", "a1234.alpha"];
 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  }