diff --git a/.github/workflows/prover.yml b/.github/workflows/prover.yml index 3194c9e32..038841b82 100644 --- a/.github/workflows/prover.yml +++ b/.github/workflows/prover.yml @@ -7,7 +7,12 @@ on: branches: [main] jobs: - build: + eval_perf: + permissions: + # Needed to install the toolchain. + contents: write + # Needed to post the performance report comments. + issues: write runs-on: ubuntu-latest steps: @@ -44,8 +49,14 @@ jobs: with: persist-credentials: false - - name: Build prover guest code - run: cargo build --profile prover-ci -F "prover" - working-directory: provers/sp1 + - name: Run performance evaluation + run: | + cargo run --profile prover-ci -- \ + --post-to-gh \ + --github-token "${{ secrets.GITHUB_TOKEN }}" \ + --pr-number "${{ github.event.pull_request.number }}" \ + --commit-hash "${{ github.sha }}" \ + working-directory: provers/perf env: - RUSTFLAGS: "-C link-arg=-fuse-ld=lld" + RUSTFLAGS: "-C target-cpu=native -C link-arg=-fuse-ld=lld" + diff --git a/.gitignore b/.gitignore index d02fe3899..b002f8a7a 100644 --- a/.gitignore +++ b/.gitignore @@ -263,6 +263,4 @@ provers/**/*.id provers/**/*.proof proving_keys/ -provers/test-util/el/el_proofs/ -provers/test-util/cl/cl_proofs/ provers/sp1/proofs/ diff --git a/Cargo.lock b/Cargo.lock index a390674e7..88f257791 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "Inflector" @@ -3874,12 +3874,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4234,9 +4234,9 @@ checksum = "95765f67b4b18863968b4a1bd5bb576f732b29a4a28c7cd84c09fa3e2875f33c" [[package]] name = "fastrand" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fastrlp" @@ -6133,9 +6133,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libgit2-sys" @@ -11452,15 +11452,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -13364,6 +13364,26 @@ dependencies = [ "strata-rpc-types", ] +[[package]] +name = "strata-provers-perf" +version = "0.1.0" +dependencies = [ + "anyhow", + "bincode", + "clap", + "reqwest 0.12.7", + "serde", + "serde_json", + "sp1-prover", + "sp1-sdk", + "strata-sp1-adapter", + "strata-test-utils", + "strata-zkvm", + "strata-zkvm-tests", + "time", + "tokio", +] + [[package]] name = "strata-python-utils" version = "0.5.0" @@ -13861,6 +13881,7 @@ dependencies = [ "bincode", "bitcoin", "borsh", + "cfg-if", "hex", "serde_json", "strata-native-zkvm-adapter", @@ -14132,14 +14153,15 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.10.1" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b3000ce72..3da15eec1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,7 @@ members = [ "bin/strata-client", "bin/strata-reth", "bin/prover-client", + "provers/perf", # integration tests "tests", @@ -189,6 +190,7 @@ bincode = "1.3" bitcoin = { version = "=0.32.5", features = ["serde"] } borsh = { version = "1.5.0", features = ["derive"] } bytes = "1.6.0" +cfg-if = "1.0.0" chrono = "0.4.38" clap = "4" digest = "0.10" diff --git a/crates/zkvm/adapters/native/src/host.rs b/crates/zkvm/adapters/native/src/host.rs index 378f7d219..d60fb3458 100644 --- a/crates/zkvm/adapters/native/src/host.rs +++ b/crates/zkvm/adapters/native/src/host.rs @@ -1,8 +1,7 @@ use std::{fmt, sync::Arc}; use strata_zkvm::{ - Proof, ProofReceipt, ProofReport, ProofType, PublicValues, VerificationKey, ZkVmError, - ZkVmHost, ZkVmResult, + Proof, ProofReceipt, ProofType, PublicValues, VerificationKey, ZkVmError, ZkVmHost, ZkVmResult, }; use crate::{env::NativeMachine, input::NativeMachineInputBuilder, proof::NativeProofReceipt}; @@ -45,14 +44,6 @@ impl ZkVmHost for NativeHost { fn verify_inner(&self, _proof: &NativeProofReceipt) -> ZkVmResult<()> { Ok(()) } - - fn perf_report<'a>( - &self, - _input: NativeMachine, - _proof_type: ProofType, - ) -> ZkVmResult { - Ok(ProofReport { cycles: 0 }) - } } impl fmt::Display for NativeHost { diff --git a/crates/zkvm/adapters/risc0/src/host.rs b/crates/zkvm/adapters/risc0/src/host.rs index 9de409a55..01a7d136a 100644 --- a/crates/zkvm/adapters/risc0/src/host.rs +++ b/crates/zkvm/adapters/risc0/src/host.rs @@ -4,8 +4,7 @@ use hex::encode; use risc0_zkvm::{compute_image_id, default_prover, sha::Digest, Journal, ProverOpts}; use serde::{de::DeserializeOwned, Serialize}; use strata_zkvm::{ - ProofReport, ProofType, PublicValues, VerificationKey, ZkVmError, ZkVmHost, ZkVmInputBuilder, - ZkVmResult, + ProofType, PublicValues, VerificationKey, ZkVmError, ZkVmHost, ZkVmInputBuilder, ZkVmResult, }; use crate::{input::Risc0ProofInputBuilder, proof::Risc0ProofReceipt}; @@ -26,6 +25,11 @@ impl Risc0Host { id, } } + + // TODO: consider moving to ZkVkHost trait. + pub fn get_elf(&self) -> &[u8] { + &self.elf + } } impl ZkVmHost for Risc0Host { @@ -81,14 +85,6 @@ impl ZkVmHost for Risc0Host { .map_err(|e| ZkVmError::ProofVerificationError(e.to_string()))?; Ok(()) } - - fn perf_report<'a>( - &self, - _input: as ZkVmInputBuilder<'a>>::Input, - _proof_type: ProofType, - ) -> ZkVmResult { - Ok(ProofReport { cycles: 0 }) - } } impl fmt::Display for Risc0Host { @@ -113,6 +109,7 @@ mod tests { const TEST_ELF: &[u8] = include_bytes!("../tests/elf/risc0-zkvm-elf"); #[test] + #[ignore] fn test_mock_prover() { let input: u32 = 1; let host = Risc0Host::init(TEST_ELF); @@ -137,6 +134,7 @@ mod tests { } #[test] + #[ignore] fn test_mock_prover_with_public_param() { let input: u32 = 1; let zkvm = Risc0Host::init(TEST_ELF); diff --git a/crates/zkvm/adapters/sp1/src/host.rs b/crates/zkvm/adapters/sp1/src/host.rs index ccbdc36f3..4bd69ca9c 100644 --- a/crates/zkvm/adapters/sp1/src/host.rs +++ b/crates/zkvm/adapters/sp1/src/host.rs @@ -3,8 +3,7 @@ use std::fmt; use serde::{de::DeserializeOwned, Serialize}; use sp1_sdk::{HashableKey, ProverClient, SP1ProvingKey, SP1VerifyingKey}; use strata_zkvm::{ - ProofReport, ProofType, PublicValues, VerificationKey, ZkVmError, ZkVmHost, ZkVmInputBuilder, - ZkVmResult, + ProofType, PublicValues, VerificationKey, ZkVmError, ZkVmHost, ZkVmInputBuilder, ZkVmResult, }; use crate::{input::SP1ProofInputBuilder, proof::SP1ProofReceipt}; @@ -49,6 +48,11 @@ impl SP1Host { verifying_key, } } + + // TODO: consider moving to ZkVkHost trait. + pub fn get_elf(&self) -> &[u8] { + &self.elf + } } impl ZkVmHost for SP1Host { @@ -102,14 +106,6 @@ impl ZkVmHost for SP1Host { Ok(()) } - - fn perf_report<'a>( - &self, - _input: as ZkVmInputBuilder<'a>>::Input, - _proof_type: ProofType, - ) -> ZkVmResult { - Ok(ProofReport { cycles: 0 }) - } } impl fmt::Display for SP1Host { diff --git a/crates/zkvm/hosts/Cargo.toml b/crates/zkvm/hosts/Cargo.toml index 10b1372c0..063fe6024 100644 --- a/crates/zkvm/hosts/Cargo.toml +++ b/crates/zkvm/hosts/Cargo.toml @@ -12,10 +12,10 @@ strata-sp1-guest-builder = { path = "../../../provers/sp1", optional = true } strata-risc0-adapter = { workspace = true, optional = true } strata-risc0-guest-builder = { path = "../../../provers/risc0", optional = true } -strata-primitives.workspace = true +# native +strata-native-zkvm-adapter = { workspace = true, optional = true } -# TODO: make it optional, via the native feature. -strata-native-zkvm-adapter.workspace = true +strata-primitives.workspace = true strata-proofimpl-btc-blockspace.workspace = true strata-proofimpl-checkpoint.workspace = true strata-proofimpl-cl-agg.workspace = true @@ -25,11 +25,12 @@ strata-proofimpl-l1-batch.workspace = true bincode.workspace = true borsh.workspace = true -cfg-if = "1.0.0" +cfg-if.workspace = true serde.workspace = true thiserror.workspace = true [features] -native = [] +default = [] +native = ["strata-native-zkvm-adapter"] risc0 = ["strata-risc0-adapter/prover", "strata-risc0-guest-builder/prover"] sp1 = ["strata-sp1-adapter/prover", "strata-sp1-guest-builder/prover"] diff --git a/crates/zkvm/hosts/src/lib.rs b/crates/zkvm/hosts/src/lib.rs index 13752d83f..2ffb57d3a 100644 --- a/crates/zkvm/hosts/src/lib.rs +++ b/crates/zkvm/hosts/src/lib.rs @@ -1,30 +1,37 @@ -// TODO figure out the cfg-if. +#[macro_use] +extern crate cfg_if; -#[cfg(feature = "native")] -pub mod native; -#[cfg(feature = "native")] -use strata_native_zkvm_adapter::NativeHost; -#[cfg(feature = "native")] -pub fn get_native_host(vm: ProofVm) -> &'static NativeHost { - native::get_host(vm) +cfg_if! { + if #[cfg(feature = "native")] { + pub mod native; + use strata_native_zkvm_adapter::NativeHost; + + pub fn get_native_host(vm: ProofVm) -> &'static NativeHost { + native::get_host(vm) + } + } } -#[cfg(feature = "risc0")] -pub mod risc0; -#[cfg(feature = "risc0")] -use strata_risc0_adapter::Risc0Host; -#[cfg(feature = "risc0")] -pub fn get_risc0_host(vm: ProofVm) -> &'static Risc0Host { - risc0::get_host(vm) +cfg_if! { + if #[cfg(feature = "risc0")] { + pub mod risc0; + use strata_risc0_adapter::Risc0Host; + + pub fn get_risc0_host(vm: ProofVm) -> &'static Risc0Host { + risc0::get_host(vm) + } + } } -#[cfg(feature = "sp1")] -pub mod sp1; -#[cfg(feature = "sp1")] -use strata_sp1_adapter::SP1Host; -#[cfg(feature = "sp1")] -pub fn get_sp1_host(vm: ProofVm) -> &'static SP1Host { - sp1::get_host(vm) +cfg_if! { + if #[cfg(feature = "sp1")] { + pub mod sp1; + use strata_sp1_adapter::SP1Host; + + pub fn get_sp1_host(vm: ProofVm) -> &'static SP1Host { + sp1::get_host(vm) + } + } } /// An identifier of different prover types. diff --git a/crates/zkvm/zkvm/src/host.rs b/crates/zkvm/zkvm/src/host.rs index b5275b63b..3e6fe7603 100644 --- a/crates/zkvm/zkvm/src/host.rs +++ b/crates/zkvm/zkvm/src/host.rs @@ -4,8 +4,8 @@ use borsh::BorshDeserialize; use serde::{de::DeserializeOwned, Serialize}; use crate::{ - input::ZkVmInputBuilder, ProofReceipt, ProofReport, ProofType, PublicValues, VerificationKey, - ZkVmError, ZkVmProofError, ZkVmResult, + input::ZkVmInputBuilder, ProofReceipt, ProofType, PublicValues, VerificationKey, ZkVmError, + ZkVmProofError, ZkVmResult, }; /// A trait implemented by the prover ("host") of a zkVM program. @@ -58,11 +58,4 @@ pub trait ZkVmHost: Send + Sync + Clone + Display + 'static { fn verify(&self, proof: &ProofReceipt) -> ZkVmResult<()> { self.verify_inner(&proof.clone().try_into()?) } - - /// Generates a performance report for the given input and proof type. - fn perf_report<'a>( - &self, - input: as ZkVmInputBuilder<'a>>::Input, - proof_type: ProofType, - ) -> ZkVmResult; } diff --git a/crates/zkvm/zkvm/src/proof.rs b/crates/zkvm/zkvm/src/proof.rs index 4368812d0..ebc07b8f5 100644 --- a/crates/zkvm/zkvm/src/proof.rs +++ b/crates/zkvm/zkvm/src/proof.rs @@ -77,12 +77,6 @@ pub struct ProofReceipt { public_values: PublicValues, } -/// A proof report containing a performance stats about proof generation. -#[derive(Debug, Clone)] -pub struct ProofReport { - pub cycles: u64, -} - impl ProofReceipt { /// Creates a new [`ProofReceipt`] from proof and it's associated public values pub fn new(proof: Proof, public_values: PublicValues) -> Self { diff --git a/crates/zkvm/zkvm/src/prover.rs b/crates/zkvm/zkvm/src/prover.rs index ba6fe2023..bf5f8a2ca 100644 --- a/crates/zkvm/zkvm/src/prover.rs +++ b/crates/zkvm/zkvm/src/prover.rs @@ -1,7 +1,7 @@ use tracing::error; use crate::{ - host::ZkVmHost, input::ZkVmInputBuilder, ProofReceipt, ProofReport, ProofType, PublicValues, + host::ZkVmHost, input::ZkVmInputBuilder, ProofReceipt, ProofType, PublicValues, ZkVmInputResult, ZkVmResult, }; @@ -42,16 +42,4 @@ pub trait ZkVmProver { Ok(receipt) } - - /// Outputs the useful performance stats related to proving. - fn perf_stats<'a, H>(input: &'a Self::Input, host: &H) -> ZkVmResult - where - H: ZkVmHost, - H::Input<'a>: ZkVmInputBuilder<'a>, - { - let zkvm_input = Self::prepare_input::>(input)?; - let report = host.perf_report(zkvm_input, Self::proof_type())?; - - Ok(report) - } } diff --git a/provers/perf/Cargo.toml b/provers/perf/Cargo.toml new file mode 100644 index 000000000..6b784aa5b --- /dev/null +++ b/provers/perf/Cargo.toml @@ -0,0 +1,22 @@ +[package] +edition = "2021" +name = "strata-provers-perf" +version = "0.1.0" + +[dependencies] +strata-sp1-adapter = { workspace = true, features = ["mock", "prover"] } +strata-test-utils.workspace = true +strata-zkvm.workspace = true +strata-zkvm-tests = { path = "../tests/", features = ["mock", "sp1"] } + +sp1-prover = "3.0.0" +sp1-sdk = "3.0.0" + +anyhow = "1.0.83" +bincode = "1.3.3" +clap = { version = "4.5.9", features = ["derive"] } +reqwest = { version = "0.12.4", features = ["json"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0.94" +time = "0.3.26" +tokio = { version = "1.39.0", features = ["full"] } diff --git a/provers/perf/src/lib.rs b/provers/perf/src/lib.rs new file mode 100644 index 000000000..cf74ab9af --- /dev/null +++ b/provers/perf/src/lib.rs @@ -0,0 +1,57 @@ +use strata_zkvm::{ProofType, ZkVmHost, ZkVmInputBuilder, ZkVmProver, ZkVmResult}; +use strata_zkvm_tests::{ + proof_generators::{ + BtcBlockProofGenerator, CheckpointProofGenerator, ClProofGenerator, ElProofGenerator, + L1BatchProofGenerator, L2BatchProofGenerator, + }, + ProofGenerator, +}; + +mod reports; +/// A proof report containing a performance stats about proof generation. +#[derive(Debug, Clone)] +pub struct ProofReport { + pub cycles: u64, + pub report_name: String, +} + +/// An extension trait that supports performance report for [`ZkVmHost`]. +pub trait ZkVmHostPerf: ZkVmHost { + /// Generates a performance report for the given input and proof type. + fn perf_report<'a>( + &self, + input: as ZkVmInputBuilder<'a>>::Input, + proof_type: ProofType, + report_name: String, + ) -> ZkVmResult; +} + +/// An extension trait for the [`ProofGenerator`] to enhance it with report generation. +pub trait ProofGeneratorPerf: ProofGenerator { + /// Generates a proof report based on the input. + fn gen_proof_report(&self, input: &Self::Input, report_name: String) -> ZkVmResult + where + Self::H: ZkVmHostPerf, + { + let input: <::P as ZkVmProver>::Input = self.get_input(input)?; + let host = self.get_host(); + + let zkvm_input = + ::prepare_input::<::Input<'_>>(&input)?; + let report = host.perf_report( + zkvm_input, + ::proof_type(), + report_name, + )?; + + Ok(report) + } +} + +// Default implementations for each [`ProofGenerator`] to support proof report generation. +impl ProofGeneratorPerf for BtcBlockProofGenerator {} +impl ProofGeneratorPerf for ElProofGenerator {} +impl ProofGeneratorPerf for ClProofGenerator {} +impl ProofGeneratorPerf for L1BatchProofGenerator {} +impl ProofGeneratorPerf for L2BatchProofGenerator {} +impl ProofGeneratorPerf for CheckpointProofGenerator {} diff --git a/provers/perf/src/main.rs b/provers/perf/src/main.rs new file mode 100644 index 000000000..1fa0b2f11 --- /dev/null +++ b/provers/perf/src/main.rs @@ -0,0 +1,268 @@ +use anyhow::Result; +use clap::{command, Parser}; +use reqwest::Client; +use serde::Serialize; +use serde_json::json; +use strata_provers_perf::{ProofGeneratorPerf, ProofReport, ZkVmHostPerf}; +use strata_test_utils::{bitcoin::get_btc_chain, l2::gen_params}; +use strata_zkvm_tests::{CheckpointBatchInfo, TestProverGenerators, TEST_SP1_GENERATORS}; + +#[tokio::main] +async fn main() -> Result<(), Box> { + sp1_sdk::utils::setup_logger(); + let args = EvalArgs::parse(); + + let mut results_text = vec![format_header(&args)]; + let sp1_reports = run_generator_programs(&TEST_SP1_GENERATORS); + results_text.push(format_results(&sp1_reports, "SP1".to_owned())); + + // Print results + println!("{}", results_text.join("\n")); + + if args.post_to_gh { + // Post to GitHub PR + let message = format_github_message(&results_text); + post_to_github_pr(&args, &message).await?; + } + + if !sp1_reports.iter().all(|r| r.success) { + println!("Some programs failed. Please check the results above."); + std::process::exit(1); + } + + Ok(()) +} + +/// Flags for CLI invocation being parsed. +#[derive(Parser, Clone)] +#[command(about = "Evaluate the performance of SP1 on programs.")] +struct EvalArgs { + /// Whether to post on github or run locally and only log the results. + #[arg(long, default_value_t = false)] + pub post_to_gh: bool, + + /// The GitHub token for authentication. + #[arg(long, default_value = "")] + pub github_token: String, + + /// The GitHub PR number. + #[arg(long, default_value = "")] + pub pr_number: String, + + /// The commit hash. + #[arg(long, default_value = "local_commit")] + pub commit_hash: String, +} + +/// Basic data about the performance of a certain [`ZkVmProver`]. +/// +/// TODO: Currently, only program and cycles are used, populalate the rest +/// as part of full execution with timings reporting. +#[derive(Debug, Serialize)] +pub struct PerformanceReport { + program: String, + cycles: u64, + success: bool, +} + +impl From for PerformanceReport { + fn from(value: ProofReport) -> Self { + PerformanceReport { + program: value.report_name, + cycles: value.cycles, + success: true, + } + } +} + +/// Runs all prover generators from [`TestProverGenerators`] against test inputs. +/// +/// Generates [`PerformanceReport`] for each invocation. +fn run_generator_programs( + generator: &TestProverGenerators, +) -> Vec { + let mut reports = vec![]; + + // Init test params. + let params = gen_params(); + let rollup_params = params.rollup(); + + let l1_start_height = (rollup_params.genesis_l1_height + 1) as u32; + let l1_end_height = l1_start_height + 1; + + let l2_start_height = 1; + let l2_end_height = 3; + + let btc_block_id = 40321; + let btc_chain = get_btc_chain(); + let btc_block = btc_chain.get_block(btc_block_id); + let strata_block_id = 1; + + // btc_blockspace + println!("Generating a report for BTC_BLOCKSPACE"); + let btc_blockspace = generator.btc_blockspace(); + let btc_blockspace_report = btc_blockspace + .gen_proof_report(btc_block, "BTC_BLOCKSPACE".to_owned()) + .unwrap(); + + reports.push(btc_blockspace_report.into()); + + // el_block + println!("Generating a report for EL_BLOCK"); + let el_block = generator.el_block(); + let el_block_report = el_block + .gen_proof_report(&strata_block_id, "EL_BLOCK".to_owned()) + .unwrap(); + + reports.push(el_block_report.into()); + + // cl_block + println!("Generating a report for CL_BLOCK"); + let cl_block = generator.cl_block(); + let cl_block_report = cl_block + .gen_proof_report(&strata_block_id, "CL_BLOCK".to_owned()) + .unwrap(); + + reports.push(cl_block_report.into()); + + // l1_batch + println!("Generating a report for L1_BATCH"); + let l1_batch = generator.l1_batch(); + let l1_batch_report = l1_batch + .gen_proof_report(&(l1_start_height, l1_end_height), "L1_BATCH".to_owned()) + .unwrap(); + + reports.push(l1_batch_report.into()); + + // l2_block + println!("Generating a report for L2_BATCH"); + let l2_block = generator.l2_batch(); + let l2_block_report = l2_block + .gen_proof_report(&(l2_start_height, l2_end_height), "L2_BATCH".to_owned()) + .unwrap(); + + reports.push(l2_block_report.into()); + + // checkpoint + println!("Generating a report for CHECKPOINT"); + let checkpoint = generator.checkpoint(); + let checkpoint_test_input = CheckpointBatchInfo { + l1_range: (l1_start_height.into(), l1_end_height.into()), + l2_range: (l2_start_height, l2_end_height), + }; + let checkpoint_report = checkpoint + .gen_proof_report(&checkpoint_test_input, "CHECKPOINT".to_owned()) + .unwrap(); + reports.push(checkpoint_report.into()); + + reports +} + +/// Returns a formatted header for the performance report with basic PR data. +fn format_header(args: &EvalArgs) -> String { + let mut detail_text = String::new(); + + if args.post_to_gh { + detail_text.push_str(&format!("*Commit*: {}\n", &args.commit_hash[..8])); + } else { + detail_text.push_str("*Local execution*\n"); + } + + detail_text +} + +/// Returns formatted results for the [`PerformanceReport`]s shaped in a table. +fn format_results(results: &[PerformanceReport], host_name: String) -> String { + let mut table_text = String::new(); + table_text.push('\n'); + table_text.push_str("| program | cycles | success |\n"); + table_text.push_str("|-------------------|-------------|----------|"); + + for result in results.iter() { + table_text.push_str(&format!( + "\n| {:<17} | {:>11} | {:<7} |", + result.program, + result.cycles, + if result.success { "✅" } else { "❌" } + )); + } + table_text.push('\n'); + + format!("*{} Performance Test Results*\n {}", host_name, table_text) +} + +/// Posts the message to the PR on the github. +/// +/// Updates an existing previous comment (if there is one) or posts a new comment. +async fn post_to_github_pr( + args: &EvalArgs, + message: &str, +) -> Result<(), Box> { + let client = Client::new(); + + // Get all comments on the PR + const BASE_URL: &str = "https://api.github.com/repos/alpenlabs/strata"; + let comments_url = format!("{}/issues/{}/comments", BASE_URL, &args.pr_number); + let comments_response = client + .get(&comments_url) + .header("Authorization", format!("token {}", &args.github_token)) + .header("User-Agent", "strata-perf-bot") + .send() + .await?; + + let comments: Vec = comments_response.json().await?; + + // Look for an existing comment from our bot + let bot_comment = comments.iter().find(|comment| { + comment["user"]["login"] + .as_str() + .map(|login| login == "github-actions[bot]") + .unwrap_or(false) + }); + + if let Some(existing_comment) = bot_comment { + // Update the existing comment + let comment_url = existing_comment["url"].as_str().unwrap(); + let response = client + .patch(comment_url) + .header("Authorization", format!("token {}", &args.github_token)) + .header("User-Agent", "strata-perf-bot") + .json(&json!({ + "body": message + })) + .send() + .await?; + + if !response.status().is_success() { + return Err(format!("Failed to update comment: {:?}", response.text().await?).into()); + } + } else { + // Create a new comment + let response = client + .post(&comments_url) + .header("Authorization", format!("token {}", &args.github_token)) + .header("User-Agent", "strata-perf-bot") + .json(&json!({ + "body": message + })) + .send() + .await?; + + if !response.status().is_success() { + return Err(format!("Failed to post comment: {:?}", response.text().await?).into()); + } + } + + Ok(()) +} + +fn format_github_message(results_text: &[String]) -> String { + let mut formatted_message = String::new(); + + for line in results_text { + formatted_message.push_str(&line.replace('*', "**")); + formatted_message.push('\n'); + } + + formatted_message +} diff --git a/provers/perf/src/reports.rs b/provers/perf/src/reports.rs new file mode 100644 index 000000000..2f06a152b --- /dev/null +++ b/provers/perf/src/reports.rs @@ -0,0 +1,18 @@ +use sp1_prover::utils::get_cycles; +use strata_sp1_adapter::SP1Host; + +use crate::{ProofReport, ZkVmHostPerf}; + +impl ZkVmHostPerf for SP1Host { + fn perf_report<'a>( + &self, + input: as strata_zkvm::ZkVmInputBuilder<'a>>::Input, + _proof_type: strata_zkvm::ProofType, + report_name: String, + ) -> strata_zkvm::ZkVmResult { + Ok(ProofReport { + cycles: get_cycles(self.get_elf(), &input), + report_name, + }) + } +} diff --git a/provers/test-util/cl/cl_witness_1.bin b/provers/test-util/cl/cl_witness_1.bin deleted file mode 100644 index 1f30a5200..000000000 Binary files a/provers/test-util/cl/cl_witness_1.bin and /dev/null differ diff --git a/provers/test-util/cl/cl_witness_2.bin b/provers/test-util/cl/cl_witness_2.bin deleted file mode 100644 index b48526e7f..000000000 Binary files a/provers/test-util/cl/cl_witness_2.bin and /dev/null differ diff --git a/provers/test-util/cl/cl_witness_3.bin b/provers/test-util/cl/cl_witness_3.bin deleted file mode 100644 index 40ae0933e..000000000 Binary files a/provers/test-util/cl/cl_witness_3.bin and /dev/null differ diff --git a/provers/test-util/el/witness_1.json b/provers/test-util/el/witness_1.json deleted file mode 100644 index 207ce6ec7..000000000 --- a/provers/test-util/el/witness_1.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "parent_header": { - "parent_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "ommers_hash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "beneficiary": "0x0000000000000000000000000000000000000000", - "state_root": "0x351714af72d74259f45cd7eab0b04527cd40e74836a45abcae50f92d919d988f", - "transactions_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "receipts_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "withdrawals_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "difficulty": "0x0", - "number": 0, - "gas_limit": 30000000, - "gas_used": 0, - "timestamp": 0, - "mix_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "nonce": 66, - "base_fee_per_gas": 1000000000, - "blob_gas_used": null, - "excess_blob_gas": null, - "parent_beacon_block_root": null, - "requests_root": null, - "extra_data": "0x5343" - }, - "beneficiary": "0x0000000000000000000000000000000000000000", - "gas_limit": 30000000, - "timestamp": 1727739191, - "extra_data": "0x726574682f76312e302e332f6d61636f73", - "mix_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "pre_state_trie": { - "data": { - "Digest": "0x351714af72d74259f45cd7eab0b04527cd40e74836a45abcae50f92d919d988f" - } - }, - "pre_state_storage": {}, - "contracts": [], - "ancestor_headers": [], - "transactions": [], - "withdrawals": [] -} diff --git a/provers/test-util/el/witness_2.json b/provers/test-util/el/witness_2.json deleted file mode 100644 index 87db6d7e1..000000000 --- a/provers/test-util/el/witness_2.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "parent_header": { - "parent_hash": "0x37ad61cff1367467a98cf7c54c4ac99e989f1fbb1bc1e646235e90c065c565ba", - "ommers_hash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "beneficiary": "0x0000000000000000000000000000000000000000", - "state_root": "0x351714af72d74259f45cd7eab0b04527cd40e74836a45abcae50f92d919d988f", - "transactions_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "receipts_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "withdrawals_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "difficulty": "0x0", - "number": 1, - "gas_limit": 30000000, - "gas_used": 0, - "timestamp": 1727739191, - "mix_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "nonce": 0, - "base_fee_per_gas": 875000000, - "blob_gas_used": null, - "excess_blob_gas": null, - "parent_beacon_block_root": null, - "requests_root": null, - "extra_data": "0x726574682f76312e302e332f6d61636f73" - }, - "beneficiary": "0x0000000000000000000000000000000000000000", - "gas_limit": 30000000, - "timestamp": 1727739192, - "extra_data": "0x726574682f76312e302e332f6d61636f73", - "mix_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "pre_state_trie": { - "data": { - "Digest": "0x351714af72d74259f45cd7eab0b04527cd40e74836a45abcae50f92d919d988f" - } - }, - "pre_state_storage": {}, - "contracts": [], - "ancestor_headers": [], - "transactions": [], - "withdrawals": [] -} diff --git a/provers/test-util/el/witness_3.json b/provers/test-util/el/witness_3.json deleted file mode 100644 index 96b462ea7..000000000 --- a/provers/test-util/el/witness_3.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "parent_header": { - "parent_hash": "0x934c2f460ae12db8e116f14fc28940006b888de617616f32e7b241e8c0805419", - "ommers_hash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "beneficiary": "0x0000000000000000000000000000000000000000", - "state_root": "0x351714af72d74259f45cd7eab0b04527cd40e74836a45abcae50f92d919d988f", - "transactions_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "receipts_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "withdrawals_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "difficulty": "0x0", - "number": 2, - "gas_limit": 30000000, - "gas_used": 0, - "timestamp": 1727739192, - "mix_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "nonce": 0, - "base_fee_per_gas": 765625000, - "blob_gas_used": null, - "excess_blob_gas": null, - "parent_beacon_block_root": null, - "requests_root": null, - "extra_data": "0x726574682f76312e302e332f6d61636f73" - }, - "beneficiary": "0x0000000000000000000000000000000000000000", - "gas_limit": 30000000, - "timestamp": 1727739193, - "extra_data": "0x726574682f76312e302e332f6d61636f73", - "mix_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "pre_state_trie": { - "data": { - "Digest": "0x351714af72d74259f45cd7eab0b04527cd40e74836a45abcae50f92d919d988f" - } - }, - "pre_state_storage": {}, - "contracts": [], - "ancestor_headers": [], - "transactions": [], - "withdrawals": [] -} diff --git a/provers/test-util/el/witness_4.json b/provers/test-util/el/witness_4.json deleted file mode 100644 index e59464e4d..000000000 --- a/provers/test-util/el/witness_4.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "parent_header": { - "parent_hash": "0xef9244b6bd2f9b97c791faba80bbacc3ecfa5bbfdd71a9864774b328b4ed402d", - "ommers_hash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", - "beneficiary": "0x0000000000000000000000000000000000000000", - "state_root": "0x351714af72d74259f45cd7eab0b04527cd40e74836a45abcae50f92d919d988f", - "transactions_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "receipts_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "withdrawals_root": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", - "logs_bloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "difficulty": "0x0", - "number": 3, - "gas_limit": 30000000, - "gas_used": 0, - "timestamp": 1727739193, - "mix_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "nonce": 0, - "base_fee_per_gas": 669921875, - "blob_gas_used": null, - "excess_blob_gas": null, - "parent_beacon_block_root": null, - "requests_root": null, - "extra_data": "0x726574682f76312e302e332f6d61636f73" - }, - "beneficiary": "0x0000000000000000000000000000000000000000", - "gas_limit": 30000000, - "timestamp": 1727739194, - "extra_data": "0x726574682f76312e302e332f6d61636f73", - "mix_hash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "pre_state_trie": { - "data": { - "Digest": "0x351714af72d74259f45cd7eab0b04527cd40e74836a45abcae50f92d919d988f" - } - }, - "pre_state_storage": {}, - "contracts": [], - "ancestor_headers": [], - "transactions": [], - "withdrawals": [] -} diff --git a/provers/test-util/el_block_witness_input.bin b/provers/test-util/el_block_witness_input.bin deleted file mode 100644 index 4bfcab496..000000000 Binary files a/provers/test-util/el_block_witness_input.bin and /dev/null differ diff --git a/provers/tests/Cargo.toml b/provers/tests/Cargo.toml index 553164607..2de9c8c69 100644 --- a/provers/tests/Cargo.toml +++ b/provers/tests/Cargo.toml @@ -4,7 +4,6 @@ name = "strata-zkvm-tests" version = "0.1.0" [dependencies] -strata-native-zkvm-adapter.workspace = true strata-primitives.workspace = true strata-proofimpl-btc-blockspace.workspace = true strata-proofimpl-checkpoint.workspace = true @@ -15,13 +14,7 @@ strata-proofimpl-l1-batch.workspace = true strata-state.workspace = true strata-test-utils.workspace = true strata-zkvm.workspace = true - -anyhow.workspace = true -bincode.workspace = true -bitcoin.workspace = true -borsh.workspace = true -hex.workspace = true -serde_json.workspace = true +strata-zkvm-hosts.workspace = true # sp1 strata-sp1-adapter = { workspace = true, optional = true, features = [ @@ -39,15 +32,33 @@ strata-risc0-guest-builder = { path = "../risc0", optional = true, features = [ "prover", ] } -#TODO: specify features accordingly. -strata-zkvm-hosts = { workspace = true, features = ["sp1", "native"] } +# native +strata-native-zkvm-adapter = { workspace = true, optional = true } + +anyhow.workspace = true +bincode.workspace = true +bitcoin.workspace = true +borsh.workspace = true +cfg-if.workspace = true +hex.workspace = true +serde_json.workspace = true [features] -default = [] +default = ["native"] mock = [ "strata-sp1-guest-builder/mock", "strata-sp1-adapter/mock", "strata-risc0-adapter/mock", ] -risc0 = ["strata-risc0-adapter", "strata-risc0-guest-builder"] -sp1 = ["strata-sp1-adapter", "strata-sp1-guest-builder"] +native = ["strata-native-zkvm-adapter", "strata-zkvm-hosts/native"] +risc0 = [ + "strata-risc0-adapter", + "strata-risc0-guest-builder", + "strata-zkvm-hosts/risc0", +] +sp1 = [ + "strata-sp1-adapter", + "strata-sp1-guest-builder", + "strata-zkvm-hosts/sp1", +] +test = [] diff --git a/provers/tests/src/provers/btc.rs b/provers/tests/src/btc.rs similarity index 65% rename from provers/tests/src/provers/btc.rs rename to provers/tests/src/btc.rs index e91fb6ca3..99b549c3c 100644 --- a/provers/tests/src/provers/btc.rs +++ b/provers/tests/src/btc.rs @@ -16,8 +16,11 @@ impl BtcBlockProofGenerator { } } -impl ProofGenerator for BtcBlockProofGenerator { +impl ProofGenerator for BtcBlockProofGenerator { type Input = Block; + type P = BtcBlockspaceProver; + type H = H; + fn get_input(&self, block: &Block) -> ZkVmResult { let params = gen_params(); let rollup_params = params.rollup(); @@ -32,18 +35,18 @@ impl ProofGenerator for BtcBlockProofGenerator format!("btc_block_{}", block.block_hash()) } - fn get_host(&self) -> impl ZkVmHost { + fn get_host(&self) -> H { self.host.clone() } } #[cfg(test)] -mod test { +mod tests { use strata_test_utils::bitcoin::get_btc_chain; use super::*; - fn test_proof(generator: BtcBlockProofGenerator) { + fn test_proof(generator: &BtcBlockProofGenerator) { let btc_chain = get_btc_chain(); let block = btc_chain.get_block(40321); @@ -51,23 +54,20 @@ mod test { } #[test] - #[cfg(not(any(feature = "risc0", feature = "sp1")))] + #[cfg(feature = "native")] fn test_native() { - use crate::provers::TEST_NATIVE_GENERATORS; - test_proof(TEST_NATIVE_GENERATORS.btc_blockspace()); + test_proof(crate::TEST_NATIVE_GENERATORS.btc_blockspace()); } #[test] - #[cfg(feature = "risc0")] + #[cfg(all(feature = "risc0", feature = "test"))] fn test_risc0() { - use crate::provers::TEST_RISC0_GENERATORS; - test_proof(TEST_RISC0_GENERATORS.btc_blockspace()); + test_proof(crate::TEST_RISC0_GENERATORS.btc_blockspace()); } #[test] - #[cfg(feature = "sp1")] + #[cfg(all(feature = "sp1", feature = "test"))] fn test_sp1() { - use crate::provers::TEST_SP1_GENERATORS; - test_proof(TEST_SP1_GENERATORS.btc_blockspace()); + test_proof(crate::TEST_SP1_GENERATORS.btc_blockspace()); } } diff --git a/provers/tests/src/provers/checkpoint.rs b/provers/tests/src/checkpoint.rs similarity index 84% rename from provers/tests/src/provers/checkpoint.rs rename to provers/tests/src/checkpoint.rs index 0018b467a..482368eaf 100644 --- a/provers/tests/src/provers/checkpoint.rs +++ b/provers/tests/src/checkpoint.rs @@ -31,8 +31,11 @@ pub struct CheckpointBatchInfo { pub l2_range: (u64, u64), } -impl ProofGenerator for CheckpointProofGenerator { +impl ProofGenerator for CheckpointProofGenerator { type Input = CheckpointBatchInfo; + type P = CheckpointProver; + type H = H; + fn get_input(&self, batch_info: &CheckpointBatchInfo) -> ZkVmResult { let params = gen_params(); let rollup_params = params.rollup(); @@ -72,13 +75,13 @@ impl ProofGenerator for CheckpointProofGenerator< ) } - fn get_host(&self) -> impl ZkVmHost { + fn get_host(&self) -> H { self.host.clone() } } #[allow(dead_code)] -fn test_proof(checkpoint_prover: CheckpointProofGenerator) { +fn test_proof(checkpoint_prover: &CheckpointProofGenerator) { let params = gen_params(); let rollup_params = params.rollup(); let l1_start_height = (rollup_params.genesis_l1_height + 1) as u32; @@ -98,27 +101,25 @@ fn test_proof(checkpoint_prover: CheckpointProofGenerator) { } #[cfg(test)] -mod test { +mod tests { use super::*; #[test] + #[cfg(feature = "native")] fn test_native() { - use crate::provers::TEST_NATIVE_GENERATORS; - test_proof(TEST_NATIVE_GENERATORS.checkpoint()); + test_proof(crate::TEST_NATIVE_GENERATORS.checkpoint()); } #[test] - #[cfg(feature = "risc0")] + #[cfg(all(feature = "risc0", feature = "test"))] fn test_risc0() { - use crate::provers::TEST_RISC0_GENERATORS; - test_proof(TEST_RISC0_GENERATORS.checkpoint()); + test_proof(crate::TEST_RISC0_GENERATORS.checkpoint()); } #[test] - #[cfg(feature = "sp1")] + #[cfg(all(feature = "sp1", feature = "test"))] fn test_sp1() { - use crate::provers::TEST_SP1_GENERATORS; - test_proof(TEST_SP1_GENERATORS.checkpoint()); + test_proof(crate::TEST_SP1_GENERATORS.checkpoint()); } } diff --git a/provers/tests/src/provers/cl.rs b/provers/tests/src/cl.rs similarity index 74% rename from provers/tests/src/provers/cl.rs rename to provers/tests/src/cl.rs index f693d9f87..2b7f0c319 100644 --- a/provers/tests/src/provers/cl.rs +++ b/provers/tests/src/cl.rs @@ -19,8 +19,10 @@ impl ClProofGenerator { } } -impl ProofGenerator for ClProofGenerator { +impl ProofGenerator for ClProofGenerator { type Input = u64; + type P = ClStfProver; + type H = H; fn get_input(&self, block_num: &u64) -> ZkVmResult { // Generate EL proof required for aggregation @@ -47,7 +49,7 @@ impl ProofGenerator for ClProofGenerator { format!("cl_block_{}", block_num) } - fn get_host(&self) -> impl ZkVmHost { + fn get_host(&self) -> H { self.host.clone() } } @@ -56,30 +58,27 @@ impl ProofGenerator for ClProofGenerator { mod tests { use super::*; - fn test_proof(cl_prover: ClProofGenerator) { + fn test_proof(cl_prover: &ClProofGenerator) { let height = 1; let _ = cl_prover.get_proof(&height).unwrap(); } #[test] - #[cfg(not(any(feature = "risc0", feature = "sp1")))] + #[cfg(feature = "native")] fn test_native() { - use crate::provers::TEST_NATIVE_GENERATORS; - test_proof(TEST_NATIVE_GENERATORS.cl_block()); + test_proof(crate::TEST_NATIVE_GENERATORS.cl_block()); } #[test] - #[cfg(feature = "risc0")] + #[cfg(all(feature = "risc0", feature = "test"))] fn test_risc0() { - use crate::provers::TEST_RISC0_GENERATORS; - test_proof(TEST_RISC0_GENERATORS.cl_block()); + test_proof(crate::TEST_RISC0_GENERATORS.cl_block()); } #[test] - #[cfg(feature = "sp1")] + #[cfg(all(feature = "sp1", feature = "test"))] fn test_sp1() { - use crate::provers::TEST_SP1_GENERATORS; - test_proof(TEST_SP1_GENERATORS.cl_block()); + test_proof(crate::TEST_SP1_GENERATORS.cl_block()); } } diff --git a/provers/tests/src/provers/el.rs b/provers/tests/src/el.rs similarity index 63% rename from provers/tests/src/provers/el.rs rename to provers/tests/src/el.rs index a7174ba69..08b1a264e 100644 --- a/provers/tests/src/provers/el.rs +++ b/provers/tests/src/el.rs @@ -15,8 +15,11 @@ impl ElProofGenerator { } } -impl ProofGenerator for ElProofGenerator { +impl ProofGenerator for ElProofGenerator { type Input = u64; + type P = EvmEeProver; + type H = H; + fn get_input(&self, block_num: &u64) -> ZkVmResult { let input = EvmSegment::initialize_from_saved_ee_data(*block_num, *block_num) .get_input(block_num) @@ -28,7 +31,7 @@ impl ProofGenerator for ElProofGenerator { format!("el_{}", block_num) } - fn get_host(&self) -> impl ZkVmHost { + fn get_host(&self) -> H { self.host.clone() } } @@ -38,29 +41,26 @@ mod tests { use super::*; - fn test_proof(el_prover: ElProofGenerator) { + fn test_proof(el_prover: &ElProofGenerator) { let height = 1; let _ = el_prover.get_proof(&height).unwrap(); } #[test] - #[cfg(not(any(feature = "risc0", feature = "sp1")))] + #[cfg(feature = "native")] fn test_native() { - use crate::provers::TEST_NATIVE_GENERATORS; - test_proof(TEST_NATIVE_GENERATORS.el_block()); + test_proof(crate::TEST_NATIVE_GENERATORS.el_block()); } #[test] - #[cfg(feature = "risc0")] + #[cfg(all(feature = "risc0", feature = "test"))] fn test_risc0() { - use crate::provers::TEST_RISC0_GENERATORS; - test_proof(TEST_RISC0_GENERATORS.el_block()); + test_proof(crate::TEST_RISC0_GENERATORS.el_block()); } #[test] - #[cfg(feature = "sp1")] + #[cfg(all(feature = "sp1", feature = "test"))] fn test_sp1() { - use crate::provers::TEST_SP1_GENERATORS; - test_proof(TEST_SP1_GENERATORS.el_block()); + test_proof(crate::TEST_SP1_GENERATORS.el_block()); } } diff --git a/provers/tests/src/provers/generators.rs b/provers/tests/src/generators.rs similarity index 51% rename from provers/tests/src/provers/generators.rs rename to provers/tests/src/generators.rs index ca3acc1f1..899e82149 100644 --- a/provers/tests/src/provers/generators.rs +++ b/provers/tests/src/generators.rs @@ -1,6 +1,5 @@ use core::panic; -// A container enum for all the test prover generators. -use std::{collections::HashMap, sync::LazyLock}; +use std::collections::HashMap; use btc::BtcBlockProofGenerator; use checkpoint::CheckpointProofGenerator; @@ -8,31 +7,8 @@ use cl::ClProofGenerator; use el::ElProofGenerator; use l1_batch::L1BatchProofGenerator; use l2_batch::L2BatchProofGenerator; -use strata_native_zkvm_adapter::NativeHost; -#[cfg(feature = "risc0")] -use strata_risc0_adapter::Risc0Host; -#[cfg(feature = "sp1")] -use strata_sp1_adapter::SP1Host; use strata_zkvm::ZkVmHost; -#[cfg(feature = "risc0")] -use strata_zkvm_hosts::get_risc0_host; -#[cfg(feature = "sp1")] -use strata_zkvm_hosts::get_sp1_host; -use strata_zkvm_hosts::{get_native_host, ProofVm}; - -/// Test prover generator for the SP1 Host. -#[cfg(feature = "sp1")] -pub static TEST_SP1_GENERATORS: LazyLock> = - std::sync::LazyLock::new(|| TestProverGenerators::init(|vm| get_sp1_host(vm).clone())); - -/// Test prover generator for the RISC0 Host. -#[cfg(feature = "risc0")] -pub static TEST_RISC0_GENERATORS: LazyLock> = - std::sync::LazyLock::new(|| TestProverGenerators::init(|vm| get_risc0_host(vm).clone())); - -/// Test prover generator for the Native Host. -pub static TEST_NATIVE_GENERATORS: LazyLock> = - std::sync::LazyLock::new(|| TestProverGenerators::init(|vm| get_native_host(vm).clone())); +use strata_zkvm_hosts::ProofVm; use super::{btc, checkpoint, cl, el, l1_batch, l2_batch}; @@ -54,14 +30,14 @@ pub struct TestProverGenerators { } impl TestProverGenerators { - fn init(host_provider: F) -> Self + pub fn init(host_provider: F) -> Self where F: Fn(ProofVm) -> H, { let mut generators = HashMap::new(); // TODO: refactor deeper to remove clones. - // Likely not critical right now due to its being used in tests and perf CI (later). + // Likely not critical right now due to its being used in tests and perf CI. let btc_prover = BtcBlockProofGenerator::new(host_provider(ProofVm::BtcProving)); let l1_batch_prover = L1BatchProofGenerator::new(btc_prover.clone(), host_provider(ProofVm::L1Batch)); @@ -75,72 +51,60 @@ impl TestProverGenerators { host_provider(ProofVm::Checkpoint), ); - generators.insert( - ProofVm::BtcProving, - TestGenerator::BtcBlock(btc_prover.clone()), - ); - generators.insert( - ProofVm::L1Batch, - TestGenerator::L1Batch(l1_batch_prover.clone()), - ); - generators.insert( - ProofVm::ELProving, - TestGenerator::ElBlock(el_prover.clone()), - ); - generators.insert( - ProofVm::CLProving, - TestGenerator::ClBlock(cl_prover.clone()), - ); + generators.insert(ProofVm::BtcProving, TestGenerator::BtcBlock(btc_prover)); + generators.insert(ProofVm::L1Batch, TestGenerator::L1Batch(l1_batch_prover)); + generators.insert(ProofVm::ELProving, TestGenerator::ElBlock(el_prover)); + generators.insert(ProofVm::CLProving, TestGenerator::ClBlock(cl_prover)); generators.insert( ProofVm::CLAggregation, - TestGenerator::L2Batch(l2_batch_prover.clone()), + TestGenerator::L2Batch(l2_batch_prover), ); generators.insert( ProofVm::Checkpoint, - TestGenerator::Checkpoint(checkpoint_prover.clone()), + TestGenerator::Checkpoint(checkpoint_prover), ); Self { generators } } - pub fn btc_blockspace(&self) -> BtcBlockProofGenerator { + pub fn btc_blockspace(&self) -> &BtcBlockProofGenerator { match self.generators.get(&ProofVm::BtcProving).unwrap() { - TestGenerator::BtcBlock(value) => value.clone(), + TestGenerator::BtcBlock(value) => value, _ => panic!("unexpected"), } } - pub fn el_block(&self) -> ElProofGenerator { + pub fn el_block(&self) -> &ElProofGenerator { match self.generators.get(&ProofVm::ELProving).unwrap() { - TestGenerator::ElBlock(value) => value.clone(), + TestGenerator::ElBlock(value) => value, _ => panic!("unexpected"), } } - pub fn cl_block(&self) -> ClProofGenerator { + pub fn cl_block(&self) -> &ClProofGenerator { match self.generators.get(&ProofVm::CLProving).unwrap() { - TestGenerator::ClBlock(value) => value.clone(), + TestGenerator::ClBlock(value) => value, _ => panic!("unexpected"), } } - pub fn l1_batch(&self) -> L1BatchProofGenerator { + pub fn l1_batch(&self) -> &L1BatchProofGenerator { match self.generators.get(&ProofVm::L1Batch).unwrap() { - TestGenerator::L1Batch(value) => value.clone(), + TestGenerator::L1Batch(value) => value, _ => panic!("unexpected"), } } - pub fn l2_batch(&self) -> L2BatchProofGenerator { + pub fn l2_batch(&self) -> &L2BatchProofGenerator { match self.generators.get(&ProofVm::CLAggregation).unwrap() { - TestGenerator::L2Batch(value) => value.clone(), + TestGenerator::L2Batch(value) => value, _ => panic!("unexpected"), } } - pub fn checkpoint(&self) -> CheckpointProofGenerator { + pub fn checkpoint(&self) -> &CheckpointProofGenerator { match self.generators.get(&ProofVm::Checkpoint).unwrap() { - TestGenerator::Checkpoint(value) => value.clone(), + TestGenerator::Checkpoint(value) => value, _ => panic!("unexpected"), } } diff --git a/provers/tests/src/provers/l1_batch.rs b/provers/tests/src/l1_batch.rs similarity index 75% rename from provers/tests/src/provers/l1_batch.rs rename to provers/tests/src/l1_batch.rs index b6a87a66a..beef53e5e 100644 --- a/provers/tests/src/provers/l1_batch.rs +++ b/provers/tests/src/l1_batch.rs @@ -20,8 +20,11 @@ impl L1BatchProofGenerator { } } -impl ProofGenerator for L1BatchProofGenerator { +impl ProofGenerator for L1BatchProofGenerator { type Input = (u32, u32); + type P = L1BatchProver; + type H = H; + fn get_input(&self, heights: &(u32, u32)) -> ZkVmResult { let (start_height, end_height) = *heights; @@ -50,19 +53,18 @@ impl ProofGenerator for L1BatchProofGenerator { format!("l1_batch_{}_{}", start_height, end_height) } - fn get_host(&self) -> impl ZkVmHost { + fn get_host(&self) -> H { self.host.clone() } } #[cfg(test)] -mod test { +mod tests { use strata_test_utils::l2::gen_params; - use strata_zkvm::ZkVmHost; use super::*; - fn test_proof(l1_batch_proof_generator: L1BatchProofGenerator) { + fn test_proof(l1_batch_proof_generator: &L1BatchProofGenerator) { let params = gen_params(); let rollup_params = params.rollup(); let l1_start_height = (rollup_params.genesis_l1_height + 1) as u32; @@ -74,23 +76,20 @@ mod test { } #[test] - #[cfg(not(any(feature = "risc0", feature = "sp1")))] + #[cfg(feature = "native")] fn test_native() { - use crate::provers::TEST_NATIVE_GENERATORS; - test_proof(TEST_NATIVE_GENERATORS.l1_batch()); + test_proof(crate::TEST_NATIVE_GENERATORS.l1_batch()); } #[test] - #[cfg(feature = "risc0")] + #[cfg(all(feature = "risc0", feature = "test"))] fn test_risc0() { - use crate::provers::TEST_RISC0_GENERATORS; - test_proof(TEST_RISC0_GENERATORS.l1_batch()); + test_proof(crate::TEST_RISC0_GENERATORS.l1_batch()); } #[test] - #[cfg(feature = "sp1")] + #[cfg(all(feature = "sp1", feature = "test"))] fn test_sp1() { - use crate::provers::TEST_SP1_GENERATORS; - test_proof(TEST_SP1_GENERATORS.l1_batch()); + test_proof(crate::TEST_SP1_GENERATORS.l1_batch()); } } diff --git a/provers/tests/src/provers/l2_batch.rs b/provers/tests/src/l2_batch.rs similarity index 68% rename from provers/tests/src/provers/l2_batch.rs rename to provers/tests/src/l2_batch.rs index 1c385e6e8..39705aaa8 100644 --- a/provers/tests/src/provers/l2_batch.rs +++ b/provers/tests/src/l2_batch.rs @@ -18,8 +18,10 @@ impl L2BatchProofGenerator { } } -impl ProofGenerator for L2BatchProofGenerator { +impl ProofGenerator for L2BatchProofGenerator { type Input = (u64, u64); + type P = ClAggProver; + type H = H; fn get_input(&self, heights: &(u64, u64)) -> ZkVmResult { let (start_height, end_height) = *heights; @@ -39,39 +41,34 @@ impl ProofGenerator for L2BatchProofGenerator { format!("l2_batch_{}_{}", start_height, end_height) } - fn get_host(&self) -> impl ZkVmHost { + fn get_host(&self) -> H { self.host.clone() } } #[cfg(test)] -mod test { - use strata_zkvm::ZkVmHost; - +mod tests { use super::*; - fn test_proof(cl_agg_prover: L2BatchProofGenerator) { + fn test_proof(cl_agg_prover: &L2BatchProofGenerator) { let _ = cl_agg_prover.get_proof(&(1, 3)).unwrap(); } #[test] - #[cfg(not(any(feature = "risc0", feature = "sp1")))] + #[cfg(feature = "native")] fn test_native() { - use crate::provers::TEST_NATIVE_GENERATORS; - test_proof(TEST_NATIVE_GENERATORS.l2_batch()); + test_proof(crate::TEST_NATIVE_GENERATORS.l2_batch()); } #[test] - #[cfg(feature = "risc0")] + #[cfg(all(feature = "risc0", feature = "test"))] fn test_risc0() { - use crate::provers::TEST_RISC0_GENERATORS; - test_proof(TEST_RISC0_GENERATORS.l2_batch()); + test_proof(crate::TEST_RISC0_GENERATORS.l2_batch()); } #[test] - #[cfg(feature = "sp1")] + #[cfg(all(feature = "sp1", feature = "test"))] fn test_sp1() { - use crate::provers::TEST_SP1_GENERATORS; - test_proof(TEST_SP1_GENERATORS.l2_batch()); + test_proof(crate::TEST_SP1_GENERATORS.l2_batch()); } } diff --git a/provers/tests/src/lib.rs b/provers/tests/src/lib.rs index f410b4010..770aa951c 100644 --- a/provers/tests/src/lib.rs +++ b/provers/tests/src/lib.rs @@ -1 +1,145 @@ -pub mod provers; +#[macro_use] +extern crate cfg_if; +use std::{fs, path::PathBuf, sync::LazyLock}; + +use strata_zkvm::{ProofReceipt, ZkVmHost, ZkVmProofError, ZkVmProver, ZkVmResult}; +mod btc; +mod checkpoint; +mod cl; +mod el; +mod generators; +mod l1_batch; +mod l2_batch; + +pub mod proof_generators { + pub use crate::{ + btc::BtcBlockProofGenerator, checkpoint::CheckpointProofGenerator, cl::ClProofGenerator, + el::ElProofGenerator, l1_batch::L1BatchProofGenerator, l2_batch::L2BatchProofGenerator, + }; +} +pub use checkpoint::CheckpointBatchInfo; +pub use generators::TestProverGenerators; + +cfg_if! { + if #[cfg(feature = "risc0")] { + use strata_risc0_adapter::Risc0Host; + + /// Test prover generator for the RISC0 Host. + pub static TEST_RISC0_GENERATORS: LazyLock> = + std::sync::LazyLock::new(|| TestProverGenerators::init(|vm| strata_zkvm_hosts::get_risc0_host(vm).clone())); + } +} + +cfg_if! { + if #[cfg(feature = "sp1")] { + use strata_sp1_adapter::SP1Host; + + /// Test prover generator for the SP1 Host. + pub static TEST_SP1_GENERATORS: LazyLock> = + std::sync::LazyLock::new(|| TestProverGenerators::init(|vm| strata_zkvm_hosts::get_sp1_host(vm).clone())); + } +} + +cfg_if! { + if #[cfg(feature = "native")] { + use strata_native_zkvm_adapter::NativeHost; + + /// Test prover generator for the Native Host. + pub static TEST_NATIVE_GENERATORS: LazyLock> = + std::sync::LazyLock::new(|| TestProverGenerators::init(|vm| strata_zkvm_hosts::get_native_host(vm).clone())); + } +} + +pub trait ProofGenerator { + type Input; + type P: ZkVmProver; + type H: ZkVmHost; + + /// An input required to generate a proof. + fn get_input(&self, input: &Self::Input) -> ZkVmResult<::Input>; + + // A host to generate the proof against. + fn get_host(&self) -> Self::H; + + /// Generates a unique proof ID based on the input. + /// The proof ID will be the hash of the input and potentially other unique identifiers. + fn get_proof_id(&self, input: &Self::Input) -> String; + + /// Retrieves a proof from cache or generates it if not found. + fn get_proof(&self, input: &Self::Input) -> ZkVmResult { + // 1. Create the unique proof ID + let proof_id = format!("{}_{}.proof", self.get_proof_id(input), self.get_host()); + println!("Getting proof for {}", proof_id); + let proof_file = get_cache_dir().join(proof_id); + + // 2. Check if the proof file exists + if proof_file.exists() { + println!("Proof found in cache, returning the cached proof...",); + let proof = read_proof_from_file(&proof_file)?; + let host = self.get_host(); + verify_proof(&proof, &host)?; + return Ok(proof); + } + + // 3. Generate the proof + println!("Proof not found in cache, generating proof..."); + let proof = self.gen_proof(input)?; + + // Verify the proof + verify_proof(&proof, &self.get_host())?; + + // Save the proof to cache + write_proof_to_file(&proof, &proof_file).unwrap(); + + Ok(proof) + } + + /// Generates a proof based on the input. + fn gen_proof(&self, input: &Self::Input) -> ZkVmResult { + let input = self.get_input(input)?; + let host = self.get_host(); + ::prove(&input, &host) + } +} + +/// Returns the cache directory for proofs. +fn get_cache_dir() -> std::path::PathBuf { + let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + manifest_dir.join("proofs") +} + +/// Reads a proof from a file. +fn read_proof_from_file(proof_file: &std::path::Path) -> Result { + use std::{fs::File, io::Read}; + + let mut file = File::open(proof_file).expect("Failed to open proof file"); + + let mut buffer = Vec::new(); + file.read_to_end(&mut buffer) + .expect("Failed to read proof file"); + let proof_receipt: ProofReceipt = bincode::deserialize(&buffer)?; + + Ok(proof_receipt) +} + +/// Writes a proof to a file. +fn write_proof_to_file(proof: &ProofReceipt, proof_file: &std::path::Path) -> Result<(), String> { + use std::{fs::File, io::Write}; + + let cache_dir = get_cache_dir(); + if !cache_dir.exists() { + fs::create_dir(&cache_dir).expect("Failed to create 'proofs' directory"); + } + + let mut file = File::create(proof_file).expect("Failed to create proof file"); + + file.write_all(&bincode::serialize(&proof).expect("serialization of proof failed")) + .expect("Failed to write proof to file"); + + Ok(()) +} + +/// Verifies a proof independently. +fn verify_proof(proof: &ProofReceipt, host: &impl ZkVmHost) -> ZkVmResult<()> { + host.verify(proof) +} diff --git a/provers/tests/src/provers/mod.rs b/provers/tests/src/provers/mod.rs deleted file mode 100644 index a15478701..000000000 --- a/provers/tests/src/provers/mod.rs +++ /dev/null @@ -1,115 +0,0 @@ -use std::{fs, path::PathBuf}; - -use strata_zkvm::{ProofReceipt, ProofReport, ZkVmHost, ZkVmProofError, ZkVmProver, ZkVmResult}; -pub mod btc; -mod checkpoint; -pub mod cl; -pub mod el; -mod generators; -pub mod l1_batch; -pub mod l2_batch; - -pub use generators::TEST_NATIVE_GENERATORS; -#[cfg(feature = "risc0")] -pub use generators::TEST_RISC0_GENERATORS; -#[cfg(feature = "sp1")] -pub use generators::TEST_SP1_GENERATORS; - -pub trait ProofGenerator { - type Input; - - /// An input required to generate a proof. - fn get_input(&self, input: &Self::Input) -> ZkVmResult; - - // A host to generate the proof against. - fn get_host(&self) -> impl ZkVmHost; - - /// Generates a unique proof ID based on the input. - /// The proof ID will be the hash of the input and potentially other unique identifiers. - fn get_proof_id(&self, input: &Self::Input) -> String; - - /// Retrieves a proof from cache or generates it if not found. - fn get_proof(&self, input: &Self::Input) -> ZkVmResult { - // 1. Create the unique proof ID - let proof_id = format!("{}_{}.proof", self.get_proof_id(input), self.get_host()); - println!("Getting proof for {}", proof_id); - let proof_file = get_cache_dir().join(proof_id); - - // 2. Check if the proof file exists - if proof_file.exists() { - println!("Proof found in cache, returning the cached proof...",); - let proof = read_proof_from_file(&proof_file)?; - let host = self.get_host(); - verify_proof(&proof, &host)?; - return Ok(proof); - } - - // 3. Generate the proof - println!("Proof not found in cache, generating proof..."); - let proof = self.gen_proof(input)?; - - // Verify the proof - verify_proof(&proof, &self.get_host())?; - - // Save the proof to cache - write_proof_to_file(&proof, &proof_file).unwrap(); - - Ok(proof) - } - - /// Generates a proof based on the input. - fn gen_proof(&self, input: &Self::Input) -> ZkVmResult { - let input = self.get_input(input)?; - let host = self.get_host(); -

::prove(&input, &host) - } - - /// Generates a proof report based on the input. - fn gen_perf_report(&self, input: &Self::Input) -> ZkVmResult { - let input = self.get_input(input)?; - let host = self.get_host(); -

::perf_stats(&input, &host) - } -} - -/// Returns the cache directory for proofs. -fn get_cache_dir() -> std::path::PathBuf { - let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - manifest_dir.join("proofs") -} - -/// Reads a proof from a file. -fn read_proof_from_file(proof_file: &std::path::Path) -> Result { - use std::{fs::File, io::Read}; - - let mut file = File::open(proof_file).expect("Failed to open proof file"); - - let mut buffer = Vec::new(); - file.read_to_end(&mut buffer) - .expect("Failed to read proof file"); - let proof_receipt: ProofReceipt = bincode::deserialize(&buffer)?; - - Ok(proof_receipt) -} - -/// Writes a proof to a file. -fn write_proof_to_file(proof: &ProofReceipt, proof_file: &std::path::Path) -> Result<(), String> { - use std::{fs::File, io::Write}; - - let cache_dir = get_cache_dir(); - if !cache_dir.exists() { - fs::create_dir(&cache_dir).expect("Failed to create 'proofs' directory"); - } - - let mut file = File::create(proof_file).expect("Failed to create proof file"); - - file.write_all(&bincode::serialize(&proof).expect("serialization of proof failed")) - .expect("Failed to write proof to file"); - - Ok(()) -} - -/// Verifies a proof independently. -fn verify_proof(proof: &ProofReceipt, host: &impl ZkVmHost) -> ZkVmResult<()> { - host.verify(proof) -}