build.rs
1 // Copyright (c) 2019-2025 Alpha-Delta Network Inc. 2 // This file is part of the alphavm library. 3 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at: 7 8 // http://www.apache.org/licenses/LICENSE-2.0 9 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 use super::*; 17 18 impl<N: Network> Package<N> { 19 /// Builds the package. 20 pub fn build<A: crate::circuit::Alpha<Network = N, BaseField = N::Field>>(&self) -> Result<()> { 21 // Skip the 'build' if the program is already built. 22 if !self.is_build_required::<A>() { 23 return Ok(()); 24 } 25 26 // Retrieve the main program. 27 let program = self.program(); 28 // Retrieve the program ID. 29 let program_id = program.id(); 30 31 dev_println!("⏳ Compiling '{}'...\n", program_id.to_string()); 32 33 // Prepare the build directory. 34 let build_directory = self.build_directory(); 35 // Create the build directory if it does not exist. 36 if !build_directory.exists() { 37 std::fs::create_dir_all(&build_directory)?; 38 } 39 40 // Construct the process. 41 let process = self.get_process()?; 42 43 // Synthesize each proving and verifying key. 44 for function_name in program.functions().keys() { 45 process.synthesize_key::<A, _>(program_id, function_name, &mut rand::thread_rng())?; 46 } 47 48 // Load each function circuit. 49 for function_name in program.functions().keys() { 50 // Retrieve the program. 51 let stack = process.get_stack(program_id)?; 52 let program = stack.program(); 53 // Retrieve the function from the program. 54 let function = program.get_function(function_name)?; 55 // Save all the prover and verifier files for any function calls that are made. 56 for instruction in function.instructions() { 57 if let Instruction::Call(call) = instruction { 58 // Get the external stack and resource. 59 let (external_stack, resource) = match call.operator() { 60 CallOperator::Locator(locator) => { 61 (Some(process.get_stack(locator.program_id())?), locator.resource()) 62 } 63 CallOperator::Resource(resource) => (None, resource), 64 }; 65 // Retrieve the program. 66 let program = match &external_stack { 67 Some(external_stack) => external_stack.program(), 68 None => program, 69 }; 70 // If this is a function call, save its corresponding prover and verifier files. 71 if program.contains_function(resource) { 72 // Set the function name to the resource, in this scope. 73 let function_name = resource; 74 // Retrieve the proving key. 75 let proving_key = process.get_proving_key(program.id(), resource)?; 76 // Retrieve the verifying key. 77 let verifying_key = process.get_verifying_key(program.id(), resource)?; 78 79 // Prepare the build directory for the imported program. 80 let import_build_directory = 81 self.build_directory().join(format!("{}-{}", program.id().name(), program.id().network())); 82 // Create the build directory if it does not exist. 83 if !import_build_directory.exists() { 84 std::fs::create_dir_all(&import_build_directory)?; 85 } 86 87 // Create the prover. 88 let _prover = ProverFile::create(&import_build_directory, function_name, proving_key)?; 89 // Create the verifier. 90 let _verifier = VerifierFile::create(&import_build_directory, function_name, verifying_key)?; 91 } 92 } 93 } 94 95 // Retrieve the proving key. 96 let proving_key = process.get_proving_key(program_id, function_name)?; 97 // Retrieve the verifying key. 98 let verifying_key = process.get_verifying_key(program_id, function_name)?; 99 100 // Create the prover. 101 let _prover = ProverFile::create(&build_directory, function_name, proving_key)?; 102 // Create the verifier. 103 let _verifier = VerifierFile::create(&build_directory, function_name, verifying_key)?; 104 } 105 106 // Lastly, write the AVM file. 107 let _avm_file = AVMFile::create(&build_directory, program.clone(), true)?; 108 109 // Ensure the build directory exists. 110 if !self.build_directory().exists() { 111 bail!("Build directory does not exist: {}", self.build_directory().display()); 112 } 113 114 Ok(()) 115 } 116 } 117 118 #[cfg(test)] 119 mod tests { 120 type CurrentAlpha = alphavm_circuit::network::AlphaV0; 121 122 #[test] 123 fn test_build() { 124 // Samples a new package at a temporary directory. 125 let (directory, package) = crate::package::test_helpers::sample_token_package(); 126 127 // Ensure the build directory does *not* exist. 128 assert!(!package.build_directory().exists()); 129 // Build the package. 130 package.build::<CurrentAlpha>().unwrap(); 131 // Ensure the build directory exists. 132 assert!(package.build_directory().exists()); 133 134 // Proactively remove the temporary directory (to conserve space). 135 std::fs::remove_dir_all(directory).unwrap(); 136 } 137 138 #[test] 139 fn test_build_with_import() { 140 // Samples a new package at a temporary directory. 141 let (directory, package) = crate::package::test_helpers::sample_wallet_package(); 142 143 // Ensure the build directory does *not* exist. 144 assert!(!package.build_directory().exists()); 145 // Build the package. 146 package.build::<CurrentAlpha>().unwrap(); 147 // Ensure the build directory exists. 148 assert!(package.build_directory().exists()); 149 150 // Proactively remove the temporary directory (to conserve space). 151 std::fs::remove_dir_all(directory).unwrap(); 152 } 153 154 #[test] 155 #[ignore] 156 fn test_build_with_import_credits() { 157 // Samples a new package at a temporary directory. 158 let (directory, package) = crate::package::test_helpers::sample_transfer_package(); 159 160 // Ensure the build directory does *not* exist. 161 assert!(!package.build_directory().exists()); 162 // Build the package. 163 package.build::<CurrentAlpha>().unwrap(); 164 // Ensure the build directory exists. 165 assert!(package.build_directory().exists()); 166 167 // Proactively remove the temporary directory (to conserve space). 168 std::fs::remove_dir_all(directory).unwrap(); 169 } 170 }