snarkvm_debug/package/
is_build_required.rs1use super::*;
16
17impl<N: Network> Package<N> {
18 pub fn is_build_required<A: crate::circuit::Aleo<Network = N, BaseField = N::Field>>(&self) -> bool {
20 let build_directory = self.build_directory();
22 if !build_directory.exists() {
24 return true;
25 }
26
27 if !AVMFile::<N>::main_exists_at(&build_directory) {
29 return true;
30 }
31
32 let avm_file = match AVMFile::open(&build_directory, &self.program_id, true) {
34 Ok(file) => file,
36 Err(_) => return true,
38 };
39
40 let program = self.program();
42 if avm_file.program() != program {
43 return true;
44 }
45
46 for function_name in program.functions().keys() {
48 if !ProverFile::exists_at(&build_directory, function_name) {
50 return true;
52 }
53 if !VerifierFile::exists_at(&build_directory, function_name) {
55 return true;
57 }
58 }
59
60 false
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68 use snarkvm_console::network::Testnet3;
69 use std::{fs::File, io::Write};
70
71 type CurrentNetwork = Testnet3;
72 type Aleo = crate::circuit::AleoV0;
73
74 fn temp_dir() -> PathBuf {
75 tempfile::tempdir().expect("Failed to open temporary directory").into_path()
76 }
77
78 fn initialize_unbuilt_package(valid: bool) -> Result<Package<Testnet3>> {
79 let directory = temp_dir();
81
82 let program_id = ProgramID::<CurrentNetwork>::from_str("token.aleo").unwrap();
83
84 let program_string = match valid {
85 true => program_with_id("token.aleo"),
86 false => program_with_id("invalid_id.aleo"),
87 };
88
89 let path = directory.join("main.aleo");
91 let mut file = File::create(path).unwrap();
92 file.write_all(program_string.as_bytes()).unwrap();
93
94 let _manifest_file = Manifest::create(&directory, &program_id).unwrap();
96
97 let build_directory = directory.join("build");
99 std::fs::create_dir_all(build_directory).unwrap();
100
101 Package::<Testnet3>::open(&directory)
103 }
104
105 fn program_with_id(id: &str) -> String {
106 format!(
107 r"program {id};
108
109record token:
110 owner as address.private;
111 token_amount as u64.private;
112
113function compute:
114 input r0 as token.record;
115 add.w r0.token_amount r0.token_amount into r1;
116 output r1 as u64.private;"
117 )
118 }
119
120 #[test]
121 fn test_for_new_package() {
122 let package = initialize_unbuilt_package(true).unwrap();
123 assert!(package.is_build_required::<Aleo>());
124 }
125
126 #[test]
127 fn test_when_avm_file_does_not_exist() {
128 let package = initialize_unbuilt_package(true).unwrap();
129 assert!(package.build_directory().exists());
130 assert!(!AVMFile::<CurrentNetwork>::main_exists_at(&package.build_directory()));
131 assert!(package.is_build_required::<Aleo>());
132 }
133
134 #[test]
135 fn test_fails_when_avm_and_package_program_ids_do_not_match() {
136 let package = initialize_unbuilt_package(false);
137 assert!(package.is_err());
138 }
139
140 #[test]
141 fn test_when_prover_and_verifier_files_do_not_exist() {
142 let package = initialize_unbuilt_package(true).unwrap();
143 assert!(package.build_directory().exists());
144
145 assert!(!AVMFile::<CurrentNetwork>::main_exists_at(&package.build_directory()));
146 assert!(AVMFile::<CurrentNetwork>::create(&package.build_directory(), package.program().clone(), true).is_ok());
147 assert!(AVMFile::<CurrentNetwork>::main_exists_at(&package.build_directory()));
148
149 let avm_file = AVMFile::open(&package.build_directory(), &package.program_id, true).unwrap();
150 assert_eq!(avm_file.program().id(), &package.program_id);
151 assert_eq!(avm_file.program(), package.program());
152
153 assert!(
154 package
155 .program()
156 .functions()
157 .keys()
158 .filter(|k| {
159 ProverFile::exists_at(&package.build_directory(), k)
160 || VerifierFile::exists_at(&package.build_directory(), k)
161 })
162 .peekable()
163 .peek()
164 .is_none()
165 );
166
167 assert!(package.is_build_required::<Aleo>());
168 }
169
170 #[test]
171 fn test_prebuilt_package_does_not_rebuild() {
172 let package = initialize_unbuilt_package(true).unwrap();
173 assert!(package.is_build_required::<Aleo>());
174
175 package.build::<Aleo>(None).unwrap();
176 assert!(!package.is_build_required::<Aleo>());
177 }
178}