#![allow(clippy::type_complexity)]
mod bytes;
mod serialize;
mod string;
use crate::Transaction;
use console::{
network::prelude::*,
program::{Identifier, ProgramID},
types::Field,
};
use synthesizer_program::Program;
use synthesizer_snark::{Certificate, VerifyingKey};
#[derive(Clone, PartialEq, Eq)]
pub struct Deployment<N: Network> {
edition: u16,
program: Program<N>,
verifying_keys: Vec<(Identifier<N>, (VerifyingKey<N>, Certificate<N>))>,
}
impl<N: Network> Deployment<N> {
pub fn new(
edition: u16,
program: Program<N>,
verifying_keys: Vec<(Identifier<N>, (VerifyingKey<N>, Certificate<N>))>,
) -> Result<Self> {
let deployment = Self { edition, program, verifying_keys };
deployment.check_is_ordered()?;
Ok(deployment)
}
pub fn check_is_ordered(&self) -> Result<()> {
let program_id = self.program.id();
ensure!(
self.edition == N::EDITION,
"Deployed the wrong edition (expected '{}', found '{}').",
N::EDITION,
self.edition
);
ensure!(
!self.program.functions().is_empty(),
"No functions present in the deployment for program '{program_id}'"
);
ensure!(
!self.verifying_keys.is_empty(),
"No verifying keys present in the deployment for program '{program_id}'"
);
if self.program.functions().len() != self.verifying_keys.len() {
bail!("Deployment has an incorrect number of verifying keys, according to the program.");
}
for ((function_name, function), (name, _)) in self.program.functions().iter().zip_eq(&self.verifying_keys) {
if function_name != function.name() {
bail!("The function key is '{function_name}', but the function name is '{}'", function.name())
}
if name != function.name() {
bail!("The verifier key is '{name}', but the function name is '{}'", function.name())
}
}
ensure!(
!has_duplicates(self.verifying_keys.iter().map(|(name, ..)| name)),
"A duplicate function name was found"
);
Ok(())
}
pub fn size_in_bytes(&self) -> Result<u64> {
Ok(u64::try_from(self.to_bytes_le()?.len())?)
}
pub const fn edition(&self) -> u16 {
self.edition
}
pub const fn program(&self) -> &Program<N> {
&self.program
}
pub const fn program_id(&self) -> &ProgramID<N> {
self.program.id()
}
pub const fn verifying_keys(&self) -> &Vec<(Identifier<N>, (VerifyingKey<N>, Certificate<N>))> {
&self.verifying_keys
}
pub fn to_deployment_id(&self) -> Result<Field<N>> {
Ok(*Transaction::deployment_tree(self, None)?.root())
}
}
#[cfg(test)]
pub mod test_helpers {
use super::*;
use console::network::Testnet3;
use synthesizer_process::Process;
use once_cell::sync::OnceCell;
type CurrentNetwork = Testnet3;
type CurrentAleo = circuit::network::AleoV0;
pub(crate) fn sample_deployment(rng: &mut TestRng) -> Deployment<CurrentNetwork> {
static INSTANCE: OnceCell<Deployment<CurrentNetwork>> = OnceCell::new();
INSTANCE
.get_or_init(|| {
let (string, program) = Program::<CurrentNetwork>::parse(
r"
program testing.aleo;
mapping store:
key as u32.public;
value as u32.public;
function compute:
input r0 as u32.private;
add r0 r0 into r1;
output r1 as u32.public;",
)
.unwrap();
assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
let process = Process::load().unwrap();
let deployment = process.deploy::<CurrentAleo, _>(&program, rng).unwrap();
Deployment::from_str(&deployment.to_string()).unwrap()
})
.clone()
}
}