parse.rs
1 // Copyright (c) 2019-2025 Alpha-Delta Network Inc. 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 static STATE_PATH_PREFIX: &str = "path"; 19 20 impl<N: Network> Parser for StatePath<N> { 21 /// Parses a string into the state path. 22 #[inline] 23 fn parse(string: &str) -> ParserResult<Self> { 24 // Prepare a parser for the Alpha state path. 25 let parse_state_path = recognize(pair( 26 pair(tag(STATE_PATH_PREFIX), tag("1")), 27 many1(terminated(one_of("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), many0(char('_')))), 28 )); 29 30 // Parse the state path from the string. 31 map_res(parse_state_path, |state_path: &str| -> Result<_, Error> { 32 Self::from_str(&state_path.replace('_', "")) 33 })(string) 34 } 35 } 36 37 impl<N: Network> FromStr for StatePath<N> { 38 type Err = Error; 39 40 /// Reads in the state path string. 41 fn from_str(state_path: &str) -> Result<Self, Self::Err> { 42 // Decode the state path string from bech32m. 43 let (hrp, data, variant) = bech32::decode(state_path)?; 44 if hrp != STATE_PATH_PREFIX { 45 bail!("Failed to decode state path: '{hrp}' is an invalid prefix") 46 } else if data.is_empty() { 47 bail!("Failed to decode state path: data field is empty") 48 } else if variant != bech32::Variant::Bech32m { 49 bail!("Found an state path that is not bech32m encoded: {state_path}"); 50 } 51 // Decode the state path data from u5 to u8, and into the state path. 52 Ok(Self::read_le(&Vec::from_base32(&data)?[..])?) 53 } 54 } 55 56 impl<N: Network> Debug for StatePath<N> { 57 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 58 Display::fmt(self, f) 59 } 60 } 61 62 impl<N: Network> Display for StatePath<N> { 63 /// Writes the state path as a bech32m string. 64 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 65 // Convert the state path to bytes. 66 let bytes = self.to_bytes_le().map_err(|_| fmt::Error)?; 67 // Encode the bytes into bech32m. 68 let string = 69 bech32::encode(STATE_PATH_PREFIX, bytes.to_base32(), bech32::Variant::Bech32m).map_err(|_| fmt::Error)?; 70 // Output the string. 71 Display::fmt(&string, f) 72 } 73 } 74 75 #[cfg(test)] 76 mod tests { 77 use super::*; 78 use alphavm_console_network::MainnetV0; 79 80 type CurrentNetwork = MainnetV0; 81 82 const ITERATIONS: usize = 100; 83 84 #[test] 85 fn test_parse() { 86 let mut rng = TestRng::default(); 87 88 // Ensure type and empty value fails. 89 assert!(StatePath::<CurrentNetwork>::parse(&format!("{STATE_PATH_PREFIX}1")).is_err()); 90 assert!(StatePath::<CurrentNetwork>::parse("").is_err()); 91 92 for _ in 0..ITERATIONS { 93 // Sample the state path. 94 let expected = 95 crate::state_path::test_helpers::sample_global_state_path::<CurrentNetwork>(None, &mut rng).unwrap(); 96 97 let expected = format!("{expected}"); 98 let (remainder, candidate) = StatePath::<CurrentNetwork>::parse(&expected).unwrap(); 99 assert_eq!(format!("{expected}"), candidate.to_string()); 100 assert_eq!(STATE_PATH_PREFIX, candidate.to_string().split('1').next().unwrap()); 101 assert_eq!("", remainder); 102 } 103 } 104 105 #[test] 106 fn test_string() { 107 let mut rng = TestRng::default(); 108 109 for _ in 0..ITERATIONS { 110 // Sample the state path. 111 let expected = 112 crate::state_path::test_helpers::sample_global_state_path::<CurrentNetwork>(None, &mut rng).unwrap(); 113 114 // Check the string representation. 115 let candidate = format!("{expected}"); 116 assert_eq!(expected, StatePath::from_str(&candidate).unwrap()); 117 assert_eq!(STATE_PATH_PREFIX, candidate.split('1').next().unwrap()); 118 } 119 } 120 121 #[test] 122 fn test_display() { 123 let mut rng = TestRng::default(); 124 125 for _ in 0..ITERATIONS { 126 // Sample the state path. 127 let expected = 128 crate::state_path::test_helpers::sample_global_state_path::<CurrentNetwork>(None, &mut rng).unwrap(); 129 130 let candidate = expected.to_string(); 131 assert_eq!(format!("{expected}"), candidate); 132 assert_eq!(STATE_PATH_PREFIX, candidate.split('1').next().unwrap()); 133 134 let candidate_recovered = StatePath::<CurrentNetwork>::from_str(&candidate.to_string()).unwrap(); 135 assert_eq!(expected, candidate_recovered); 136 } 137 } 138 }