diff --git a/tooling/backend_interface/src/cli/mod.rs b/tooling/backend_interface/src/cli/mod.rs index 848c5e11e81..d1eebb1ba8e 100644 --- a/tooling/backend_interface/src/cli/mod.rs +++ b/tooling/backend_interface/src/cli/mod.rs @@ -5,6 +5,7 @@ mod gates; mod info; mod prove; mod verify; +mod version; mod write_vk; pub(crate) use contract::ContractCommand; @@ -12,6 +13,7 @@ pub(crate) use gates::GatesCommand; pub(crate) use info::InfoCommand; pub(crate) use prove::ProveCommand; pub(crate) use verify::VerifyCommand; +pub(crate) use version::VersionCommand; pub(crate) use write_vk::WriteVkCommand; #[test] diff --git a/tooling/backend_interface/src/cli/version.rs b/tooling/backend_interface/src/cli/version.rs new file mode 100644 index 00000000000..83ab72a870e --- /dev/null +++ b/tooling/backend_interface/src/cli/version.rs @@ -0,0 +1,29 @@ +use std::path::Path; + +use crate::BackendError; + +use super::string_from_stderr; + +/// VersionCommand will call the backend binary +/// to query installed version. +pub(crate) struct VersionCommand; + +impl VersionCommand { + pub(crate) fn run(self, binary_path: &Path) -> Result { + let mut command = std::process::Command::new(binary_path); + + command.arg("--version"); + + let output = command.output()?; + if output.status.success() { + match String::from_utf8(output.stdout) { + Ok(result) => Ok(result), + Err(_) => Err(BackendError::CommandFailed( + "Unexpected output from --version check.".to_owned(), + )), + } + } else { + Err(BackendError::CommandFailed(string_from_stderr(&output.stderr))) + } + } +} diff --git a/tooling/backend_interface/src/lib.rs b/tooling/backend_interface/src/lib.rs index d6a9cd0d293..6c91c181a92 100644 --- a/tooling/backend_interface/src/lib.rs +++ b/tooling/backend_interface/src/lib.rs @@ -10,6 +10,8 @@ mod smart_contract; use acvm::acir::circuit::Opcode; use bb_abstraction_leaks::ACVM_BACKEND_BARRETENBERG; +use bb_abstraction_leaks::BB_VERSION; +use cli::VersionCommand; pub use download::download_backend; const BACKENDS_DIR: &str = ".nargo/backends"; @@ -104,6 +106,33 @@ impl Backend { fn crs_directory(&self) -> PathBuf { self.backend_directory().join("crs") } + + fn assert_correct_version(&self) -> Result<&PathBuf, BackendError> { + let binary_path = self.binary_path(); + if binary_path.to_string_lossy().contains(ACVM_BACKEND_BARRETENBERG) { + match VersionCommand.run(binary_path) { + // If version matches then do nothing. + Ok(version_string) if version_string == BB_VERSION => (), + + // If version doesn't match then download the correct version. + Ok(version_string) => { + println!("`{ACVM_BACKEND_BARRETENBERG}` version `{version_string}` is different from expected `{BB_VERSION}`. Downloading expected version..."); + let bb_url = std::env::var("BB_BINARY_URL") + .unwrap_or_else(|_| bb_abstraction_leaks::BB_DOWNLOAD_URL.to_owned()); + download_backend(&bb_url, binary_path)?; + } + + // If `bb` fails to report its version, then attempt to fix it by re-downloading the binary. + Err(_) => { + println!("Could not determine version of `{ACVM_BACKEND_BARRETENBERG}`. Downloading expected version..."); + let bb_url = std::env::var("BB_BINARY_URL") + .unwrap_or_else(|_| bb_abstraction_leaks::BB_DOWNLOAD_URL.to_owned()); + download_backend(&bb_url, binary_path)?; + } + } + } + Ok(binary_path) + } } pub struct BackendOpcodeSupport { diff --git a/tooling/backend_interface/src/proof_system.rs b/tooling/backend_interface/src/proof_system.rs index ffdb7531ed1..cbb4a61be8a 100644 --- a/tooling/backend_interface/src/proof_system.rs +++ b/tooling/backend_interface/src/proof_system.rs @@ -13,6 +13,7 @@ use crate::{Backend, BackendError, BackendOpcodeSupport}; impl Backend { pub fn get_exact_circuit_size(&self, circuit: &Circuit) -> Result { let binary_path = self.assert_binary_exists()?; + self.assert_correct_version()?; let temp_directory = tempdir().expect("could not create a temporary directory"); let temp_directory = temp_directory.path().to_path_buf(); @@ -28,6 +29,7 @@ impl Backend { pub fn get_backend_info(&self) -> Result<(Language, BackendOpcodeSupport), BackendError> { let binary_path = self.assert_binary_exists()?; + self.assert_correct_version()?; InfoCommand { crs_path: self.crs_directory() }.run(binary_path) } @@ -38,6 +40,7 @@ impl Backend { is_recursive: bool, ) -> Result, BackendError> { let binary_path = self.assert_binary_exists()?; + self.assert_correct_version()?; let temp_directory = tempdir().expect("could not create a temporary directory"); let temp_directory = temp_directory.path().to_path_buf(); @@ -78,6 +81,7 @@ impl Backend { is_recursive: bool, ) -> Result { let binary_path = self.assert_binary_exists()?; + self.assert_correct_version()?; let temp_directory = tempdir().expect("could not create a temporary directory"); let temp_directory = temp_directory.path().to_path_buf(); diff --git a/tooling/backend_interface/src/smart_contract.rs b/tooling/backend_interface/src/smart_contract.rs index 5f56557cad4..50afd47287b 100644 --- a/tooling/backend_interface/src/smart_contract.rs +++ b/tooling/backend_interface/src/smart_contract.rs @@ -9,6 +9,7 @@ use tempfile::tempdir; impl Backend { pub fn eth_contract(&self, circuit: &Circuit) -> Result { let binary_path = self.assert_binary_exists()?; + self.assert_correct_version()?; let temp_directory = tempdir().expect("could not create a temporary directory"); let temp_directory_path = temp_directory.path().to_path_buf(); diff --git a/tooling/bb_abstraction_leaks/build.rs b/tooling/bb_abstraction_leaks/build.rs index baf3cfdf6a6..1ae5a28f5a8 100644 --- a/tooling/bb_abstraction_leaks/build.rs +++ b/tooling/bb_abstraction_leaks/build.rs @@ -35,6 +35,7 @@ fn main() -> Result<(), String> { }; println!("cargo:rustc-env=BB_BINARY_URL={}", get_bb_download_url(arch, os)); + println!("cargo:rustc-env=BB_VERSION={}", VERSION); Ok(()) } diff --git a/tooling/bb_abstraction_leaks/src/lib.rs b/tooling/bb_abstraction_leaks/src/lib.rs index 799e14c36f0..e0fdc467c53 100644 --- a/tooling/bb_abstraction_leaks/src/lib.rs +++ b/tooling/bb_abstraction_leaks/src/lib.rs @@ -5,6 +5,7 @@ use acvm::FieldElement; pub const ACVM_BACKEND_BARRETENBERG: &str = "acvm-backend-barretenberg"; pub const BB_DOWNLOAD_URL: &str = env!("BB_BINARY_URL"); +pub const BB_VERSION: &str = env!("BB_VERSION"); /// Embed the Solidity verifier file const ULTRA_VERIFIER_CONTRACT: &str = include_str!("contract.sol");