diff --git a/Cargo.lock b/Cargo.lock index 59889fb088..21b1074ae0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5525,6 +5525,7 @@ version = "3.0.0" dependencies = [ "anstyle", "anyhow", + "cargo_metadata", "clap", "ctrlc", "dirs", diff --git a/crates/build/src/build.rs b/crates/build/src/build.rs index 3279a8ea78..37ee7392ac 100644 --- a/crates/build/src/build.rs +++ b/crates/build/src/build.rs @@ -48,6 +48,8 @@ pub fn execute_build_program( let target_elf_paths = generate_elf_paths(&program_metadata, Some(args))?; + print_elf_paths_cargo_directives(&target_elf_paths); + Ok(target_elf_paths) } @@ -67,7 +69,10 @@ pub(crate) fn build_program_internal(path: &str, args: Option) { .unwrap_or(false); if skip_program_build { // Still need to set ELF env vars even if build is skipped. - generate_elf_paths(&metadata, args.as_ref()).expect("failed to collect target ELF paths"); + let target_elf_paths = generate_elf_paths(&metadata, args.as_ref()) + .expect("failed to collect target ELF paths"); + + print_elf_paths_cargo_directives(&target_elf_paths); println!( "cargo:warning=Build skipped for {} at {} due to SP1_SKIP_PROGRAM_BUILD flag", @@ -88,7 +93,10 @@ pub(crate) fn build_program_internal(path: &str, args: Option) { .unwrap_or(false); if is_clippy_driver { // Still need to set ELF env vars even if build is skipped. - generate_elf_paths(&metadata, args.as_ref()).expect("failed to collect target ELF paths"); + let target_elf_paths = generate_elf_paths(&metadata, args.as_ref()) + .expect("failed to collect target ELF paths"); + + print_elf_paths_cargo_directives(&target_elf_paths); println!("cargo:warning=Skipping build due to clippy invocation."); return; @@ -107,9 +115,8 @@ pub(crate) fn build_program_internal(path: &str, args: Option) { println!("cargo:warning={} built at {}", root_package_name, current_datetime()); } -/// Collects the list of targets that would be built and their output ELF file paths. Also prints -/// cargo directives setting relevant `SP1_ELF_` environment variables. -fn generate_elf_paths( +/// Collects the list of targets that would be built and their output ELF file paths. +pub fn generate_elf_paths( metadata: &cargo_metadata::Metadata, args: Option<&BuildArgs>, ) -> Result> { @@ -164,9 +171,12 @@ fn generate_elf_paths( } } + Ok(target_elf_paths) +} + +/// Prints cargo directives setting relevant `SP1_ELF_` environment variables. +fn print_elf_paths_cargo_directives(target_elf_paths: &[(String, Utf8PathBuf)]) { for (target_name, elf_path) in target_elf_paths.iter() { println!("cargo:rustc-env=SP1_ELF_{}={}", target_name, elf_path); } - - Ok(target_elf_paths) } diff --git a/crates/build/src/lib.rs b/crates/build/src/lib.rs index 1ce2a09c4c..1dbbec1347 100644 --- a/crates/build/src/lib.rs +++ b/crates/build/src/lib.rs @@ -2,7 +2,7 @@ mod build; mod command; mod utils; use build::build_program_internal; -pub use build::execute_build_program; +pub use build::{execute_build_program, generate_elf_paths}; use clap::Parser; diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 8067734268..cf2e8cb4b2 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -43,3 +43,4 @@ regex = "1.5.4" prettytable-rs = "0.10" textwrap = "0.16.0" ctrlc = "3.4.2" +cargo_metadata = "0.18.1" \ No newline at end of file diff --git a/crates/cli/src/commands/vkey.rs b/crates/cli/src/commands/vkey.rs index a8aeb1c183..734b470970 100644 --- a/crates/cli/src/commands/vkey.rs +++ b/crates/cli/src/commands/vkey.rs @@ -1,31 +1,63 @@ -use std::fs::File; +use std::{fs::File, io::Read}; use anyhow::Result; -use clap::Parser; +use clap::{Args, Parser}; +use sp1_build::{generate_elf_paths, BuildArgs}; use sp1_sdk::{HashableKey, ProverClient}; -use std::io::Read; #[derive(Parser)] #[command(name = "vkey", about = "View the verification key hash for a program.")] pub struct VkeyCmd { /// Path to the ELF. - #[arg(long, required = true)] - elf: String, + #[clap(flatten)] + elf: Elf, +} + +#[derive(Debug, Clone, Args)] +#[group(required = true, multiple = false)] +pub struct Elf { + /// The path to the ELF file + #[arg(long = "elf")] + path: Option, + /// The crate used to generate the ELF file + #[arg(long)] + program: Option, } impl VkeyCmd { pub fn run(&self) -> Result<()> { - // Read the elf file contents - let mut file = File::open(self.elf.clone()).unwrap(); - let mut elf = Vec::new(); - file.read_to_end(&mut elf).unwrap(); + let elf_paths = if let Some(path) = &self.elf.path { + vec![(None, path.clone())] + } else if let Some(program) = &self.elf.program { + let metadata_cmd = cargo_metadata::MetadataCommand::new(); + let metadata = metadata_cmd.exec()?; + let build_args = BuildArgs { packages: vec![program.clone()], ..Default::default() }; + + generate_elf_paths(&metadata, Some(&build_args))? + .into_iter() + .map(|(target, path)| (Some(target), path.to_string())) + .collect() + } else { + unreachable!() + }; + + for (target, elf_path) in elf_paths { + // Read the elf file contents + let mut file = File::open(elf_path)?; + let mut elf = Vec::new(); + file.read_to_end(&mut elf)?; - // Get the verification key - let prover = ProverClient::new(); - let (_, vk) = prover.setup(&elf); + // Get the verification key + let prover = ProverClient::new(); + let (_, vk) = prover.setup(&elf); - // Print the verification key hash - println!("Verification Key Hash:\n{}", vk.vk.bytes32()); + // Print the verification key hash + if let Some(target) = target { + println!("Verification Key Hash for '{target}':\n{}", vk.vk.bytes32()); + } else { + println!("Verification Key Hash:\n{}", vk.vk.bytes32()); + } + } Ok(()) } diff --git a/crates/test-artifacts/programs/Cargo.lock b/crates/test-artifacts/programs/Cargo.lock index 46b406d8f0..b404318c5a 100644 --- a/crates/test-artifacts/programs/Cargo.lock +++ b/crates/test-artifacts/programs/Cargo.lock @@ -1732,9 +1732,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr",