string.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 pub static SOLUTION_ID_PREFIX: &str = "solution"; 22 23 impl<N: Network> FromStr for SolutionID<N> { 24 type Err = Error; 25 26 /// Reads in the solution ID string. 27 fn from_str(solution_id: &str) -> Result<Self, Self::Err> { 28 // Decode the solution ID string from bech32m. 29 let (hrp, data, variant) = bech32::decode(solution_id)?; 30 if hrp != SOLUTION_ID_PREFIX { 31 bail!("Failed to decode solution ID: '{hrp}' is an invalid prefix") 32 } else if data.is_empty() { 33 bail!("Failed to decode solution ID: data field is empty") 34 } else if variant != bech32::Variant::Bech32m { 35 bail!("Found a solution ID that is not bech32m encoded: {solution_id}"); 36 } 37 // Decode the solution ID data from u5 to u8, and into the solution ID. 38 Ok(Self::read_le(&Vec::from_base32(&data)?[..])?) 39 } 40 } 41 42 impl<N: Network> Debug for SolutionID<N> { 43 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 44 Display::fmt(self, f) 45 } 46 } 47 48 impl<N: Network> Display for SolutionID<N> { 49 /// Writes the solution ID as a bech32m string. 50 fn fmt(&self, f: &mut Formatter) -> fmt::Result { 51 // Convert the solution ID to bytes. 52 let bytes = self.to_bytes_le().map_err(|_| fmt::Error)?; 53 // Encode the bytes into bech32m. 54 let string = 55 bech32::encode(SOLUTION_ID_PREFIX, bytes.to_base32(), bech32::Variant::Bech32m).map_err(|_| fmt::Error)?; 56 // Output the string. 57 Display::fmt(&string, f) 58 } 59 } 60 61 #[cfg(test)] 62 mod tests { 63 use super::*; 64 use console::network::MainnetV0; 65 66 type CurrentNetwork = MainnetV0; 67 68 const ITERATIONS: u64 = 1_000; 69 70 #[test] 71 fn test_string() -> Result<()> { 72 // Ensure type and empty value fails. 73 assert!(SolutionID::<CurrentNetwork>::from_str(&format!("{SOLUTION_ID_PREFIX}1")).is_err()); 74 assert!(SolutionID::<CurrentNetwork>::from_str("").is_err()); 75 76 let mut rng = TestRng::default(); 77 78 for _ in 0..ITERATIONS { 79 // Sample a new solution ID. 80 let expected = SolutionID::<CurrentNetwork>::from(rng.r#gen::<u64>()); 81 82 // Check the string representation. 83 let candidate = format!("{expected}"); 84 assert_eq!(expected, SolutionID::from_str(&candidate)?); 85 assert_eq!(SOLUTION_ID_PREFIX, candidate.split('1').next().unwrap()); 86 } 87 Ok(()) 88 } 89 90 #[test] 91 fn test_display() -> Result<()> { 92 let mut rng = TestRng::default(); 93 94 for _ in 0..ITERATIONS { 95 // Sample a new solution ID. 96 let expected = SolutionID::<CurrentNetwork>::from(rng.r#gen::<u64>()); 97 98 let candidate = expected.to_string(); 99 assert_eq!(format!("{expected}"), candidate); 100 assert_eq!(SOLUTION_ID_PREFIX, candidate.split('1').next().unwrap()); 101 102 let candidate_recovered = SolutionID::<CurrentNetwork>::from_str(&candidate.to_string())?; 103 assert_eq!(expected, candidate_recovered); 104 } 105 Ok(()) 106 } 107 }