parse.rs
1 // Copyright (c) 2025-2026 ACDC Network 2 // This file is part of the alphavm library. 3 // 4 // Alpha Chain | Delta Chain Protocol 5 // International Monetary Graphite. 6 // 7 // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com). 8 // They built world-class ZK infrastructure. We installed the EASY button. 9 // Their cryptography: elegant. Our modifications: bureaucracy-compatible. 10 // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours. 11 // 12 // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0 13 // All modifications and new work: CC0 1.0 Universal Public Domain Dedication. 14 // No rights reserved. No permission required. No warranty. No refunds. 15 // 16 // https://creativecommons.org/publicdomain/zero/1.0/ 17 // SPDX-License-Identifier: CC0-1.0 18 19 use super::*; 20 21 static STATE_PATH_PREFIX: &str = "path"; 22 23 impl<N: Network> Parser for StatePath<N> { 24 /// Parses a string into the state path. 25 #[inline] 26 fn parse(string: &str) -> ParserResult<'_, Self> { 27 // Prepare a parser for the Alpha state path. 28 let parse_state_path = recognize(pair( 29 pair(tag(STATE_PATH_PREFIX), tag("1")), 30 many1(terminated(one_of("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), many0(char('_')))), 31 )); 32 33 // Parse the state path from the string. 34 map_res(parse_state_path, |state_path: &str| -> Result<_, Error> { 35 Self::from_str(&state_path.replace('_', "")) 36 })(string) 37 } 38 } 39 40 impl<N: Network> FromStr for StatePath<N> { 41 type Err = Error; 42 43 /// Reads in the state path string. 44 fn from_str(state_path: &str) -> Result<Self, Self::Err> { 45 // Decode the state path string from bech32m. 46 let (hrp, data, variant) = bech32::decode(state_path)?; 47 if hrp != STATE_PATH_PREFIX { 48 bail!("Failed to decode state path: '{hrp}' is an invalid prefix") 49 } else if data.is_empty() { 50 bail!("Failed to decode state path: data field is empty") 51 } else if variant != bech32::Variant::Bech32m { 52 bail!("Found an state path that is not bech32m encoded: {state_path}"); 53 } 54 // Decode the state path data from u5 to u8, and into the state path. 55 Ok(Self::read_le(&Vec::from_base32(&data)?[..])?) 56 } 57 } 58 59 impl<N: Network> Debug for StatePath<N> { 60 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 61 Display::fmt(self, f) 62 } 63 } 64 65 impl<N: Network> Display for StatePath<N> { 66 /// Writes the state path as a bech32m string. 67 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 68 // Convert the state path to bytes. 69 let bytes = self.to_bytes_le().map_err(|_| fmt::Error)?; 70 // Encode the bytes into bech32m. 71 let string = 72 bech32::encode(STATE_PATH_PREFIX, bytes.to_base32(), bech32::Variant::Bech32m).map_err(|_| fmt::Error)?; 73 // Output the string. 74 Display::fmt(&string, f) 75 } 76 } 77 78 #[cfg(test)] 79 mod tests { 80 use super::*; 81 use alphavm_console_network::MainnetV0; 82 83 type CurrentNetwork = MainnetV0; 84 85 const ITERATIONS: usize = 100; 86 87 #[test] 88 fn test_parse() { 89 let mut rng = TestRng::default(); 90 91 // Ensure type and empty value fails. 92 assert!(StatePath::<CurrentNetwork>::parse(&format!("{STATE_PATH_PREFIX}1")).is_err()); 93 assert!(StatePath::<CurrentNetwork>::parse("").is_err()); 94 95 for _ in 0..ITERATIONS { 96 // Sample the state path. 97 let expected = 98 crate::state_path::test_helpers::sample_global_state_path::<CurrentNetwork>(None, &mut rng).unwrap(); 99 100 let expected = format!("{expected}"); 101 let (remainder, candidate) = StatePath::<CurrentNetwork>::parse(&expected).unwrap(); 102 assert_eq!(format!("{expected}"), candidate.to_string()); 103 assert_eq!(STATE_PATH_PREFIX, candidate.to_string().split('1').next().unwrap()); 104 assert_eq!("", remainder); 105 } 106 } 107 108 #[test] 109 fn test_string() { 110 let mut rng = TestRng::default(); 111 112 for _ in 0..ITERATIONS { 113 // Sample the state path. 114 let expected = 115 crate::state_path::test_helpers::sample_global_state_path::<CurrentNetwork>(None, &mut rng).unwrap(); 116 117 // Check the string representation. 118 let candidate = format!("{expected}"); 119 assert_eq!(expected, StatePath::from_str(&candidate).unwrap()); 120 assert_eq!(STATE_PATH_PREFIX, candidate.split('1').next().unwrap()); 121 } 122 } 123 124 #[test] 125 fn test_display() { 126 let mut rng = TestRng::default(); 127 128 for _ in 0..ITERATIONS { 129 // Sample the state path. 130 let expected = 131 crate::state_path::test_helpers::sample_global_state_path::<CurrentNetwork>(None, &mut rng).unwrap(); 132 133 let candidate = expected.to_string(); 134 assert_eq!(format!("{expected}"), candidate); 135 assert_eq!(STATE_PATH_PREFIX, candidate.split('1').next().unwrap()); 136 137 let candidate_recovered = StatePath::<CurrentNetwork>::from_str(&candidate.to_string()).unwrap(); 138 assert_eq!(expected, candidate_recovered); 139 } 140 } 141 }