snarkvm_synthesizer_process/stack/
deploy.rs1use super::*;
17
18use rand::{SeedableRng, rngs::StdRng};
19
20impl<N: Network> Stack<N> {
21 #[inline]
23 pub fn deploy<A: circuit::Aleo<Network = N>, R: Rng + CryptoRng>(&self, rng: &mut R) -> Result<Deployment<N>> {
24 let timer = timer!("Stack::deploy");
25
26 ensure!(!self.program.functions().is_empty(), "Program '{}' has no functions", self.program.id());
28
29 let mut verifying_keys = Vec::with_capacity(self.program.functions().len());
31
32 for function_name in self.program.functions().keys() {
33 self.synthesize_key::<A, R>(function_name, rng)?;
35 lap!(timer, "Synthesize key for {function_name}");
36
37 let proving_key = self.get_proving_key(function_name)?;
39 let verifying_key = self.get_verifying_key(function_name)?;
41 lap!(timer, "Retrieve the keys for {function_name}");
42
43 let certificate = Certificate::certify(&function_name.to_string(), &proving_key, &verifying_key)?;
45 lap!(timer, "Certify the circuit");
46
47 verifying_keys.push((*function_name, (verifying_key, certificate)));
49 }
50
51 finish!(timer);
52
53 Deployment::new(*self.program_edition, self.program.clone(), verifying_keys, None, None)
55 }
56
57 #[inline]
59 pub fn verify_deployment<A: circuit::Aleo<Network = N>, R: Rng + CryptoRng>(
60 &self,
61 _consensus_version: ConsensusVersion,
62 deployment: &Deployment<N>,
63 rng: &mut R,
64 ) -> Result<()> {
65 let timer = timer!("Stack::verify_deployment");
66
67 deployment.check_is_ordered()?;
71 ensure!(&self.program == deployment.program(), "The stack program does not match the deployment program");
73 if let Some(program_checksum) = deployment.program_checksum() {
75 ensure!(
76 program_checksum == self.program_checksum,
77 "The deployment checksum does not match the stack checksum"
78 );
79 }
80
81 let program_id = self.program.id();
85
86 ensure!(deployment.num_combined_variables()? <= N::MAX_DEPLOYMENT_VARIABLES);
88 ensure!(deployment.num_combined_constraints()? <= N::MAX_DEPLOYMENT_CONSTRAINTS);
90
91 let mut call_stacks = Vec::with_capacity(deployment.verifying_keys().len());
93
94 let root_tvk = None;
96 let caller = None;
98
99 ensure!(
101 deployment.program().functions().len() == deployment.verifying_keys().len(),
102 "The number of functions in the program does not match the number of verifying keys"
103 );
104
105 #[cfg(not(any(test, feature = "test")))]
106 if (ConsensusVersion::V1..=ConsensusVersion::V7).contains(&_consensus_version) {
109 finish!(timer);
110 return Ok(());
111 }
112
113 let seed = u64::from_bytes_le(&deployment.to_deployment_id()?.to_bytes_le()?[0..8])?;
117 let mut seeded_rng = rand_chacha::ChaChaRng::seed_from_u64(seed);
118
119 for (function, (_, (verifying_key, _))) in
121 deployment.program().functions().values().zip_eq(deployment.verifying_keys())
122 {
123 let burner_private_key = PrivateKey::new(rng)?;
125 let burner_address = Address::try_from(&burner_private_key)?;
127 let input_types = function.input_types();
129 let program_checksum = match self.program().contains_constructor() {
131 true => Some(self.program_checksum_as_field()?),
132 false => None,
133 };
134 let inputs = input_types
136 .iter()
137 .map(|input_type| match input_type {
138 ValueType::ExternalRecord(locator) => {
139 let stack = self.get_external_stack(locator.program_id())?;
141 stack.sample_value(
143 &burner_address,
144 &ValueType::Record(*locator.resource()).into(),
145 &mut seeded_rng,
146 )
147 }
148 _ => self.sample_value(&burner_address, &input_type.into(), &mut seeded_rng),
149 })
150 .collect::<Result<Vec<_>>>()?;
151 lap!(timer, "Sample the inputs");
152 let is_root = true;
154
155 let request = Request::sign(
157 &burner_private_key,
158 *program_id,
159 *function.name(),
160 inputs.into_iter(),
161 &input_types,
162 root_tvk,
163 is_root,
164 program_checksum,
165 rng,
166 )?;
167 lap!(timer, "Compute the request for {}", function.name());
168 let assignments = Assignments::<N>::default();
170 let Some(constraint_limit) = verifying_key.circuit_info.num_constraints.checked_sub(1) else {
172 bail!("The constraint limit of 0 for function '{}' is invalid", function.name());
174 };
175 let variable_limit = verifying_key.num_variables();
177 let call_stack = CallStack::CheckDeployment(
179 vec![request],
180 burner_private_key,
181 assignments.clone(),
182 Some(constraint_limit as u64),
183 Some(variable_limit),
184 );
185 call_stacks.push((function.name(), call_stack, assignments));
187 }
188
189 let rngs = (0..call_stacks.len()).map(|_| StdRng::from_seed(seeded_rng.r#gen())).collect::<Vec<_>>();
191 cfg_into_iter!(call_stacks).zip_eq(deployment.verifying_keys()).zip_eq(rngs).try_for_each(
192 |(((function_name, call_stack, assignments), (_, (verifying_key, certificate))), mut rng)| {
193 if let Err(err) = self.execute_function::<A, _>(call_stack, caller, root_tvk, &mut rng) {
195 bail!("Failed to synthesize the circuit for '{function_name}': {err}")
196 }
197 match assignments.read().last() {
199 None => bail!("The assignment for function '{function_name}' is missing in '{program_id}'"),
200 Some((assignment, _metrics)) => {
201 if !certificate.verify(&function_name.to_string(), assignment, verifying_key) {
203 bail!("The certificate for function '{function_name}' is invalid in '{program_id}'")
204 }
205 }
206 };
207 Ok(())
208 },
209 )?;
210
211 finish!(timer);
212
213 Ok(())
214 }
215}