mod.rs
1 // Copyright (C) 2019-2025 ADnet Contributors 2 // This file is part of the ADL library. 3 4 // The ADL library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 9 // The ADL library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 14 // You should have received a copy of the GNU General Public License 15 // along with the ADL library. If not, see <https://www.gnu.org/licenses/>. 16 17 use crate::{Annotation, Block, Indent, IntegerType, Location, NetworkName, Node, NodeID, Type}; 18 use adl_span::{Span, sym}; 19 20 use anyhow::{anyhow, bail}; 21 use serde::{Deserialize, Serialize}; 22 use snarkvm::prelude::{Address, Literal, Locator, Network}; 23 use std::{fmt, str::FromStr}; 24 25 /// A constructor definition. 26 #[derive(Clone, Default, Eq, PartialEq, Serialize, Deserialize)] 27 pub struct Constructor { 28 /// Annotations on the constructor. 29 pub annotations: Vec<Annotation>, 30 /// The body of the constructor. 31 pub block: Block, 32 /// The entire span of the constructor definition. 33 pub span: Span, 34 /// The ID of the node. 35 pub id: NodeID, 36 } 37 38 /// The upgrade variant. 39 #[derive(Clone, Debug, Eq, PartialEq)] 40 pub enum UpgradeVariant { 41 Admin { address: String }, 42 Custom, 43 Checksum { mapping: Location, key: String, key_type: Type }, 44 NoUpgrade, 45 } 46 47 impl Constructor { 48 #[allow(deprecated)] 49 pub fn get_upgrade_variant_with_network(&self, network: NetworkName) -> anyhow::Result<UpgradeVariant> { 50 match network { 51 // ALPHA networks 52 NetworkName::AlphaMainnetV0 => self.get_upgrade_variant::<snarkvm::prelude::MainnetV0>(), 53 NetworkName::AlphaTestnetV0 => self.get_upgrade_variant::<snarkvm::prelude::TestnetV0>(), 54 NetworkName::AlphaCanaryV0 => self.get_upgrade_variant::<snarkvm::prelude::CanaryV0>(), 55 // DELTA networks 56 NetworkName::DeltaMainnetV0 => self.get_upgrade_variant::<snarkvm::prelude::MainnetV0>(), 57 NetworkName::DeltaTestnetV0 => self.get_upgrade_variant::<snarkvm::prelude::TestnetV0>(), 58 NetworkName::DeltaCanaryV0 => self.get_upgrade_variant::<snarkvm::prelude::CanaryV0>(), 59 // Legacy Aleo networks (deprecated) 60 NetworkName::MainnetV0 => self.get_upgrade_variant::<snarkvm::prelude::MainnetV0>(), 61 NetworkName::TestnetV0 => self.get_upgrade_variant::<snarkvm::prelude::TestnetV0>(), 62 NetworkName::CanaryV0 => self.get_upgrade_variant::<snarkvm::prelude::CanaryV0>(), 63 } 64 } 65 66 /// Checks that the constructor's annotations are valid and returns the upgrade variant. 67 pub fn get_upgrade_variant<N: Network>(&self) -> anyhow::Result<UpgradeVariant> { 68 // Check that there is exactly one annotation. 69 if self.annotations.len() != 1 { 70 bail!( 71 "A constructor must have exactly one of the following annotations: `@admin`, `@checksum`, `@custom`, or `@noupgrade`." 72 ); 73 } 74 // Get the annotation. 75 let annotation = &self.annotations[0]; 76 match annotation.identifier.name { 77 sym::admin => { 78 // Parse the address string from the annotation. 79 let Some(address_string) = annotation.map.get(&sym::address) else { 80 bail!("An `@admin` annotation must have an 'address' key.") 81 }; 82 // Parse the address. 83 let address = Address::<N>::from_str(address_string) 84 .map_err(|e| anyhow!("Invalid address in `@admin` annotation: `{e}`."))?; 85 Ok(UpgradeVariant::Admin { address: address.to_string() }) 86 } 87 sym::checksum => { 88 // Parse the mapping string from the annotation. 89 let Some(mapping_string) = annotation.map.get(&sym::mapping) else { 90 bail!("A `@checksum` annotation must have a 'mapping' key.") 91 }; 92 // Parse the mapping string as a locator. 93 let mapping = Locator::<N>::from_str(mapping_string) 94 .map_err(|e| anyhow!("Invalid mapping in `@checksum` annotation: `{e}`."))?; 95 96 // Parse the key string from the annotation. 97 let Some(key_string) = annotation.map.get(&sym::key) else { 98 bail!("A `@checksum` annotation must have a 'key' key.") 99 }; 100 // Parse the key as a plaintext value. 101 let key = Literal::<N>::from_str(key_string) 102 .map_err(|e| anyhow!("Invalid key in `@checksum` annotation: `{e}`."))?; 103 // Get the literal type. 104 let key_type = get_type_from_snarkvm_literal(&key); 105 Ok(UpgradeVariant::Checksum { mapping: mapping.into(), key: key.to_string(), key_type }) 106 } 107 sym::custom => Ok(UpgradeVariant::Custom), 108 sym::noupgrade => Ok(UpgradeVariant::NoUpgrade), 109 _ => bail!( 110 "Invalid annotation on constructor: `{}`. Expected one of `@admin`, `@checksum`, `@custom`, or `@noupgrade`.", 111 annotation.identifier.name 112 ), 113 } 114 } 115 } 116 117 impl fmt::Display for Constructor { 118 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 119 for annotation in &self.annotations { 120 writeln!(f, "{annotation}")?; 121 } 122 123 writeln!(f, "async constructor() {{")?; 124 for stmt in self.block.statements.iter() { 125 writeln!(f, "{}{}", Indent(stmt), stmt.semicolon())?; 126 } 127 write!(f, "}}") 128 } 129 } 130 131 impl fmt::Debug for Constructor { 132 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 133 write!(f, "{self}") 134 } 135 } 136 137 crate::simple_node_impl!(Constructor); 138 139 // A helper function to get the type from a snarkVM literal. 140 fn get_type_from_snarkvm_literal<N: Network>(literal: &Literal<N>) -> Type { 141 match literal { 142 Literal::Field(_) => Type::Field, 143 Literal::Group(_) => Type::Group, 144 Literal::Address(_) => Type::Address, 145 Literal::Scalar(_) => Type::Scalar, 146 Literal::Boolean(_) => Type::Boolean, 147 Literal::String(_) => Type::String, 148 Literal::I8(_) => Type::Integer(IntegerType::I8), 149 Literal::I16(_) => Type::Integer(IntegerType::I16), 150 Literal::I32(_) => Type::Integer(IntegerType::I32), 151 Literal::I64(_) => Type::Integer(IntegerType::I64), 152 Literal::I128(_) => Type::Integer(IntegerType::I128), 153 Literal::U8(_) => Type::Integer(IntegerType::U8), 154 Literal::U16(_) => Type::Integer(IntegerType::U16), 155 Literal::U32(_) => Type::Integer(IntegerType::U32), 156 Literal::U64(_) => Type::Integer(IntegerType::U64), 157 Literal::U128(_) => Type::Integer(IntegerType::U128), 158 Literal::Signature(_) => Type::Signature, 159 } 160 }