leo_ast/constructor/
mod.rs1mod admin;
18pub use admin::*;
19
20mod checksum;
21pub use checksum::*;
22
23mod noupgrade;
24pub use noupgrade::*;
25
26use crate::{Annotation, Block, Indent, IntegerType, Location, NetworkName, Node, NodeID, Type};
27use leo_span::{Span, sym};
28
29use anyhow::{anyhow, bail};
30use serde::{Deserialize, Serialize};
31use snarkvm::prelude::{Address, Literal, Locator, Network};
32use std::{fmt, str::FromStr};
33
34#[derive(Clone, Default, Eq, PartialEq, Serialize, Deserialize)]
36pub struct Constructor {
37 pub annotations: Vec<Annotation>,
39 pub block: Block,
41 pub span: Span,
43 pub id: NodeID,
45}
46
47#[derive(Clone, Debug, Eq, PartialEq)]
49pub enum UpgradeVariant {
50 Admin { address: String },
51 Custom,
52 Checksum { mapping: Location, key: String, key_type: Type },
53 NoUpgrade,
54}
55
56impl Constructor {
57 pub fn get_upgrade_variant_with_network(&self, network: NetworkName) -> anyhow::Result<UpgradeVariant> {
58 match network {
59 NetworkName::MainnetV0 => self.get_upgrade_variant::<snarkvm::prelude::MainnetV0>(),
60 NetworkName::TestnetV0 => self.get_upgrade_variant::<snarkvm::prelude::TestnetV0>(),
61 NetworkName::CanaryV0 => self.get_upgrade_variant::<snarkvm::prelude::CanaryV0>(),
62 }
63 }
64
65 pub fn get_upgrade_variant<N: Network>(&self) -> anyhow::Result<UpgradeVariant> {
67 if self.annotations.len() != 1 {
69 bail!(
70 "A constructor must have exactly one of the following annotations: `@admin`, `@checksum`, `@custom`, or `@noupgrade`."
71 );
72 }
73 let annotation = &self.annotations[0];
75 match annotation.identifier.name {
76 sym::admin => {
77 let Some(address_string) = annotation.map.get(&sym::address) else {
79 bail!("An `@admin` annotation must have an 'address' key.")
80 };
81 let address = Address::<N>::from_str(address_string)
83 .map_err(|e| anyhow!("Invalid address in `@admin` annotation: `{e}`."))?;
84 Ok(UpgradeVariant::Admin { address: address.to_string() })
85 }
86 sym::checksum => {
87 let Some(mapping_string) = annotation.map.get(&sym::mapping) else {
89 bail!("A `@checksum` annotation must have a 'mapping' key.")
90 };
91 let mapping = Locator::<N>::from_str(mapping_string)
93 .map_err(|e| anyhow!("Invalid mapping in `@checksum` annotation: `{e}`."))?;
94
95 let Some(key_string) = annotation.map.get(&sym::key) else {
97 bail!("A `@checksum` annotation must have a 'key' key.")
98 };
99 let key = Literal::<N>::from_str(key_string)
101 .map_err(|e| anyhow!("Invalid key in `@checksum` annotation: `{e}`."))?;
102 let key_type = get_type_from_snarkvm_literal(&key);
104 Ok(UpgradeVariant::Checksum { mapping: mapping.into(), key: key.to_string(), key_type })
105 }
106 sym::custom => Ok(UpgradeVariant::Custom),
107 sym::noupgrade => Ok(UpgradeVariant::NoUpgrade),
108 _ => bail!(
109 "Invalid annotation on constructor: `{}`. Expected one of `@admin`, `@checksum`, `@custom`, or `@noupgrade`.",
110 annotation.identifier.name
111 ),
112 }
113 }
114}
115
116impl fmt::Display for Constructor {
117 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118 for annotation in &self.annotations {
119 writeln!(f, "{annotation}")?;
120 }
121
122 writeln!(f, "async constructor() {{")?;
123 for stmt in self.block.statements.iter() {
124 writeln!(f, "{}{}", Indent(stmt), stmt.semicolon())?;
125 }
126 write!(f, "}}")
127 }
128}
129
130impl fmt::Debug for Constructor {
131 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
132 write!(f, "{self}")
133 }
134}
135
136crate::simple_node_impl!(Constructor);
137
138fn get_type_from_snarkvm_literal<N: Network>(literal: &Literal<N>) -> Type {
140 match literal {
141 Literal::Field(_) => Type::Field,
142 Literal::Group(_) => Type::Group,
143 Literal::Address(_) => Type::Address,
144 Literal::Scalar(_) => Type::Scalar,
145 Literal::Boolean(_) => Type::Boolean,
146 Literal::String(_) => Type::String,
147 Literal::I8(_) => Type::Integer(IntegerType::I8),
148 Literal::I16(_) => Type::Integer(IntegerType::I16),
149 Literal::I32(_) => Type::Integer(IntegerType::I32),
150 Literal::I64(_) => Type::Integer(IntegerType::I64),
151 Literal::I128(_) => Type::Integer(IntegerType::I128),
152 Literal::U8(_) => Type::Integer(IntegerType::U8),
153 Literal::U16(_) => Type::Integer(IntegerType::U16),
154 Literal::U32(_) => Type::Integer(IntegerType::U32),
155 Literal::U64(_) => Type::Integer(IntegerType::U64),
156 Literal::U128(_) => Type::Integer(IntegerType::U128),
157 Literal::Signature(_) => Type::Signature,
158 }
159}