snarkvm_ledger_block/transaction/deployment/
mod.rs1#![allow(clippy::type_complexity)]
17
18mod bytes;
19mod serialize;
20mod string;
21
22use crate::Transaction;
23use console::{
24 network::prelude::*,
25 program::{Identifier, ProgramID},
26 types::Field,
27};
28use synthesizer_program::Program;
29use synthesizer_snark::{Certificate, VerifyingKey};
30
31#[derive(Clone, PartialEq, Eq)]
32pub struct Deployment<N: Network> {
33 edition: u16,
35 program: Program<N>,
37 verifying_keys: Vec<(Identifier<N>, (VerifyingKey<N>, Certificate<N>))>,
39}
40
41impl<N: Network> Deployment<N> {
42 pub fn new(
44 edition: u16,
45 program: Program<N>,
46 verifying_keys: Vec<(Identifier<N>, (VerifyingKey<N>, Certificate<N>))>,
47 ) -> Result<Self> {
48 let deployment = Self { edition, program, verifying_keys };
50 deployment.check_is_ordered()?;
52 Ok(deployment)
54 }
55
56 pub fn check_is_ordered(&self) -> Result<()> {
58 let program_id = self.program.id();
59
60 ensure!(
62 self.edition == N::EDITION,
63 "Deployed the wrong edition (expected '{}', found '{}').",
64 N::EDITION,
65 self.edition
66 );
67 ensure!(
69 !self.program.functions().is_empty(),
70 "No functions present in the deployment for program '{program_id}'"
71 );
72 ensure!(
74 !self.verifying_keys.is_empty(),
75 "No verifying keys present in the deployment for program '{program_id}'"
76 );
77
78 if self.program.functions().len() != self.verifying_keys.len() {
80 bail!("Deployment has an incorrect number of verifying keys, according to the program.");
81 }
82
83 ensure!(
85 self.program.functions().len() <= N::MAX_FUNCTIONS,
86 "Deployment has too many functions (maximum is '{}')",
87 N::MAX_FUNCTIONS
88 );
89
90 for ((function_name, function), (name, _)) in self.program.functions().iter().zip_eq(&self.verifying_keys) {
92 if function_name != function.name() {
94 bail!("The function key is '{function_name}', but the function name is '{}'", function.name())
95 }
96 if name != function.name() {
98 bail!("The verifier key is '{name}', but the function name is '{}'", function.name())
99 }
100 }
101
102 ensure!(
103 !has_duplicates(self.verifying_keys.iter().map(|(name, ..)| name)),
104 "A duplicate function name was found"
105 );
106
107 Ok(())
108 }
109
110 pub fn size_in_bytes(&self) -> Result<u64> {
112 Ok(u64::try_from(self.to_bytes_le()?.len())?)
113 }
114
115 pub fn len(&self) -> usize {
117 self.program.functions().len()
118 }
119
120 pub fn is_empty(&self) -> bool {
122 self.program.functions().is_empty()
123 }
124
125 pub const fn edition(&self) -> u16 {
127 self.edition
128 }
129
130 pub const fn program(&self) -> &Program<N> {
132 &self.program
133 }
134
135 pub const fn program_id(&self) -> &ProgramID<N> {
137 self.program.id()
138 }
139
140 pub const fn verifying_keys(&self) -> &Vec<(Identifier<N>, (VerifyingKey<N>, Certificate<N>))> {
142 &self.verifying_keys
143 }
144
145 pub fn num_combined_variables(&self) -> Result<u64> {
147 let mut num_combined_variables = 0u64;
149 for (_, (vk, _)) in &self.verifying_keys {
151 num_combined_variables = num_combined_variables
155 .checked_add(vk.num_variables())
156 .ok_or_else(|| anyhow!("Overflow when counting variables for '{}'", self.program_id()))?;
157 }
158 Ok(num_combined_variables)
160 }
161
162 pub fn num_combined_constraints(&self) -> Result<u64> {
164 let mut num_combined_constraints = 0u64;
166 for (_, (vk, _)) in &self.verifying_keys {
168 num_combined_constraints = num_combined_constraints
172 .checked_add(vk.circuit_info.num_constraints as u64)
173 .ok_or_else(|| anyhow!("Overflow when counting constraints for '{}'", self.program_id()))?;
174 }
175 Ok(num_combined_constraints)
177 }
178
179 pub fn to_deployment_id(&self) -> Result<Field<N>> {
181 Ok(*Transaction::deployment_tree(self)?.root())
182 }
183}
184
185#[cfg(test)]
186pub mod test_helpers {
187 use super::*;
188 use console::network::MainnetV0;
189 use synthesizer_process::Process;
190
191 use once_cell::sync::OnceCell;
192
193 type CurrentNetwork = MainnetV0;
194 type CurrentAleo = circuit::network::AleoV0;
195
196 pub(crate) fn sample_deployment(rng: &mut TestRng) -> Deployment<CurrentNetwork> {
197 static INSTANCE: OnceCell<Deployment<CurrentNetwork>> = OnceCell::new();
198 INSTANCE
199 .get_or_init(|| {
200 let (string, program) = Program::<CurrentNetwork>::parse(
202 r"
203program testing.aleo;
204
205mapping store:
206 key as u32.public;
207 value as u32.public;
208
209function compute:
210 input r0 as u32.private;
211 add r0 r0 into r1;
212 output r1 as u32.public;",
213 )
214 .unwrap();
215 assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
216
217 let process = Process::load().unwrap();
219 let deployment = process.deploy::<CurrentAleo, _>(&program, rng).unwrap();
221 Deployment::from_str(&deployment.to_string()).unwrap()
224 })
225 .clone()
226 }
227}