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 }