mod.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 mod bytes; 20 mod parse; 21 mod serialize; 22 mod to_address; 23 mod to_bits; 24 mod to_fields; 25 26 use crate::Identifier; 27 use alphavm_console_network::prelude::*; 28 use alphavm_console_types::{Address, Boolean, Field}; 29 30 /// Returns `true` if the string consists of lowercase alphanumeric characters. 31 fn is_lowercase_alphanumeric(s: &str) -> bool { 32 s.chars().all(|c| matches!(c, '0'..='9' | 'a'..='z' | '_')) 33 } 34 35 /// A program ID is of the form `{name}.{network}`. 36 #[derive(Copy, Clone, PartialEq, Eq, Hash)] 37 pub struct ProgramID<N: Network> { 38 /// The program name. 39 name: Identifier<N>, 40 /// The network-level domain (NLD). 41 network: Identifier<N>, 42 } 43 44 impl<N: Network> From<&ProgramID<N>> for ProgramID<N> { 45 /// Returns a copy of the program ID. 46 fn from(program_id: &ProgramID<N>) -> Self { 47 *program_id 48 } 49 } 50 51 impl<N: Network> TryFrom<(Identifier<N>, Identifier<N>)> for ProgramID<N> { 52 type Error = Error; 53 54 /// Initializes a program ID from a name and network-level domain identifier. 55 fn try_from((name, network): (Identifier<N>, Identifier<N>)) -> Result<Self> { 56 // Ensure the name is lowercase alphabets and numbers. 57 ensure!(is_lowercase_alphanumeric(&name.to_string()), "Program name is invalid: {name}"); 58 // Construct the program ID. 59 let id = Self { name, network }; 60 // Ensure the program network-level domain is `alpha`. 61 ensure!(id.is_alpha(), "Program network is invalid: {network}"); 62 // Return the program ID. 63 Ok(id) 64 } 65 } 66 67 impl<N: Network> TryFrom<String> for ProgramID<N> { 68 type Error = Error; 69 70 /// Initializes a program ID from a name and network-level domain identifier. 71 fn try_from(program_id: String) -> Result<Self> { 72 Self::from_str(&program_id) 73 } 74 } 75 76 impl<N: Network> TryFrom<&String> for ProgramID<N> { 77 type Error = Error; 78 79 /// Initializes a program ID from a name and network-level domain identifier. 80 fn try_from(program_id: &String) -> Result<Self> { 81 Self::from_str(program_id) 82 } 83 } 84 85 impl<N: Network> TryFrom<&str> for ProgramID<N> { 86 type Error = Error; 87 88 /// Initializes a program ID from a name and network-level domain identifier. 89 fn try_from(program_id: &str) -> Result<Self> { 90 // Split the program ID into a name and network-level domain. 91 let mut split = program_id.split('.'); 92 // Parse the name and network. 93 if let (Some(name), Some(network), None) = (split.next(), split.next(), split.next()) { 94 // Ensure the name is lowercase alphabets and numbers. 95 ensure!(is_lowercase_alphanumeric(name), "Program name is invalid: {name}"); 96 // Construct the program ID. 97 Self::try_from((Identifier::from_str(name)?, Identifier::from_str(network)?)) 98 } else { 99 bail!("Invalid program ID '{program_id}'") 100 } 101 } 102 } 103 104 impl<N: Network> ProgramID<N> { 105 /// Returns the program name. 106 #[inline] 107 pub const fn name(&self) -> &Identifier<N> { 108 &self.name 109 } 110 111 /// Returns the network-level domain (NLD). 112 #[inline] 113 pub const fn network(&self) -> &Identifier<N> { 114 &self.network 115 } 116 117 /// Returns `true` if the network-level domain is `alpha`. 118 #[inline] 119 pub fn is_alpha(&self) -> bool { 120 self.network() == &Identifier::from_str("alpha").expect("Failed to parse Alpha domain") 121 } 122 } 123 124 impl<N: Network> Ord for ProgramID<N> { 125 /// Ordering is determined by the network first, then the program name second. 126 fn cmp(&self, other: &Self) -> Ordering { 127 match self.network == other.network { 128 true => self.name.to_string().cmp(&other.name.to_string()), 129 false => self.network.to_string().cmp(&other.network.to_string()), 130 } 131 } 132 } 133 134 impl<N: Network> PartialOrd for ProgramID<N> { 135 /// Ordering is determined by the network first, then the program name second. 136 fn partial_cmp(&self, other: &Self) -> Option<Ordering> { 137 Some(self.cmp(other)) 138 } 139 } 140 141 impl<N: Network> Equal<Self> for ProgramID<N> { 142 type Output = Boolean<N>; 143 144 /// Returns `true` if `self` and `other` are equal. 145 fn is_equal(&self, other: &Self) -> Self::Output { 146 Boolean::new(self == other) 147 } 148 149 /// Returns `true` if `self` and `other` are **not** equal. 150 fn is_not_equal(&self, other: &Self) -> Self::Output { 151 Boolean::new(self != other) 152 } 153 } 154 155 #[cfg(test)] 156 mod tests { 157 use super::*; 158 use alphavm_console_network::MainnetV0; 159 160 type CurrentNetwork = MainnetV0; 161 162 #[test] 163 fn test_partial_ord() -> Result<()> { 164 let import1 = ProgramID::<CurrentNetwork>::from_str("bar.alpha")?; 165 let import2 = ProgramID::<CurrentNetwork>::from_str("foo.alpha")?; 166 167 let import3 = ProgramID::<CurrentNetwork>::from_str("bar.alpha")?; 168 let import4 = ProgramID::<CurrentNetwork>::from_str("foo.alpha")?; 169 170 assert_eq!(import1.partial_cmp(&import1), Some(Ordering::Equal)); 171 assert_eq!(import1.partial_cmp(&import2), Some(Ordering::Less)); 172 assert_eq!(import1.partial_cmp(&import3), Some(Ordering::Equal)); 173 assert_eq!(import1.partial_cmp(&import4), Some(Ordering::Less)); 174 175 assert_eq!(import2.partial_cmp(&import1), Some(Ordering::Greater)); 176 assert_eq!(import2.partial_cmp(&import2), Some(Ordering::Equal)); 177 assert_eq!(import2.partial_cmp(&import3), Some(Ordering::Greater)); 178 assert_eq!(import2.partial_cmp(&import4), Some(Ordering::Equal)); 179 180 assert_eq!(import3.partial_cmp(&import1), Some(Ordering::Equal)); 181 assert_eq!(import3.partial_cmp(&import2), Some(Ordering::Less)); 182 assert_eq!(import3.partial_cmp(&import3), Some(Ordering::Equal)); 183 assert_eq!(import3.partial_cmp(&import4), Some(Ordering::Less)); 184 185 assert_eq!(import4.partial_cmp(&import1), Some(Ordering::Greater)); 186 assert_eq!(import4.partial_cmp(&import2), Some(Ordering::Equal)); 187 assert_eq!(import4.partial_cmp(&import3), Some(Ordering::Greater)); 188 assert_eq!(import4.partial_cmp(&import4), Some(Ordering::Equal)); 189 190 Ok(()) 191 } 192 }