From 705a4c038b1d4adf977cca4ed19fa792758bf71b Mon Sep 17 00:00:00 2001 From: ross-weir <29697678+ross-weir@users.noreply.github.com> Date: Thu, 30 Apr 2026 18:15:01 +1000 Subject: [PATCH] remove zkvmnetwork trait and networkproverservice --- crates/adapters/mock-zkvm/src/lib.rs | 63 +-- crates/adapters/mock-zkvm/src/network.rs | 116 ----- crates/adapters/risc0/src/lib.rs | 3 - crates/adapters/sp1/src/lib.rs | 8 - crates/adapters/sp1/src/metrics.rs | 53 --- crates/adapters/sp1/src/network.rs | 106 ----- .../sov-stf-runner/src/processes/metrics.rs | 23 - .../src/processes/prover_service/mod.rs | 2 - .../processes/prover_service/network/mod.rs | 106 ----- .../prover_service/network/prover.rs | 318 ------------- .../tests/integration/prover_service/mod.rs | 1 - .../integration/prover_service/network.rs | 439 ------------------ .../src/state_machine/zk/mod.rs | 82 ---- examples/demo-rollup/tests/prover/mod.rs | 4 - examples/demo-rollup/tests/prover/network.rs | 114 ----- 15 files changed, 1 insertion(+), 1437 deletions(-) delete mode 100644 crates/adapters/mock-zkvm/src/network.rs delete mode 100644 crates/adapters/sp1/src/metrics.rs delete mode 100644 crates/adapters/sp1/src/network.rs delete mode 100644 crates/full-node/sov-stf-runner/src/processes/prover_service/network/mod.rs delete mode 100644 crates/full-node/sov-stf-runner/src/processes/prover_service/network/prover.rs delete mode 100644 crates/full-node/sov-stf-runner/tests/integration/prover_service/network.rs delete mode 100644 examples/demo-rollup/tests/prover/network.rs diff --git a/crates/adapters/mock-zkvm/src/lib.rs b/crates/adapters/mock-zkvm/src/lib.rs index 5a9f87f947..acd0f96438 100644 --- a/crates/adapters/mock-zkvm/src/lib.rs +++ b/crates/adapters/mock-zkvm/src/lib.rs @@ -11,10 +11,6 @@ pub use guest::MockZkGuest; mod host; #[cfg(feature = "native")] pub use host::MockZkvmHost; -#[cfg(feature = "native")] -mod network; -#[cfg(feature = "native")] -pub use network::MockZkvmNetwork; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; pub mod crypto; @@ -61,9 +57,6 @@ impl Zkvm for MockZkvm { #[cfg(feature = "native")] type OuterHost = crate::host::MockZkvmHost; - - #[cfg(feature = "native")] - type Network = crate::network::MockZkvmNetwork; } /// A mock commitment to a particular zkVM program. #[derive( @@ -145,7 +138,7 @@ impl sov_rollup_interface::zk::ZkVerifier for MockZkVerifier { #[cfg(test)] mod tests { use sov_rollup_interface::crypto::PublicKey; - use sov_rollup_interface::zk::{ZkVerifier, ZkvmHost, ZkvmNetwork}; + use sov_rollup_interface::zk::{ZkVerifier, ZkvmHost}; use super::*; @@ -198,58 +191,4 @@ mod tests { Ok(()) } - - #[tokio::test] - async fn test_mock_network() -> anyhow::Result<()> { - let network = MockZkvmNetwork::new(false); - let pub_data = TestPublicData { - hint: "NetworkTest".to_owned(), - }; - - let handle = network.add_hint_and_submit(&pub_data).await?; - - // Proof should be pending - assert_eq!(network.poll(&handle).await?, None); - - // Complete the proof - network.complete_proof(handle); - - // Now poll should return the proof bytes - let proof_bytes = network - .poll(&handle) - .await? - .expect("proof should be ready after complete_proof"); - - let proof = SerializedZkProof { - raw_proof: proof_bytes, - }; - let verified = - MockZkVerifier::verify_with_proof::(&proof, &Default::default())?; - assert_eq!(verified, pub_data); - Ok(()) - } - - #[tokio::test] - async fn test_mock_network_auto_complete() -> anyhow::Result<()> { - let network = MockZkvmNetwork::new(true); - let pub_data = TestPublicData { - hint: "AutoComplete".to_owned(), - }; - - let handle = network.add_hint_and_submit(&pub_data).await?; - - // Proof should be immediately ready - let proof_bytes = network - .poll(&handle) - .await? - .expect("auto-complete proof should be immediately ready"); - - let proof = SerializedZkProof { - raw_proof: proof_bytes, - }; - let verified = - MockZkVerifier::verify_with_proof::(&proof, &Default::default())?; - assert_eq!(verified, pub_data); - Ok(()) - } } diff --git a/crates/adapters/mock-zkvm/src/network.rs b/crates/adapters/mock-zkvm/src/network.rs deleted file mode 100644 index 1ed4654c9c..0000000000 --- a/crates/adapters/mock-zkvm/src/network.rs +++ /dev/null @@ -1,116 +0,0 @@ -use std::collections::HashMap; -use std::sync::atomic::{AtomicU64, Ordering}; -use std::sync::{Arc, Mutex}; - -use serde::Serialize; - -use crate::{MockProof, MockZkGuest}; - -struct MockNetworkProof { - proof_bytes: Vec, - ready: bool, -} - -/// A mock implementation of [`sov_rollup_interface::zk::ZkvmNetwork`]. -/// -/// Proofs can be controlled in two modes: -/// - **Manual** ([`MockZkvmNetwork::new`]): proofs stay pending until -/// [`MockZkvmNetwork::complete_proof`] is called with the returned handle. -/// - **Auto-complete** ([`MockZkvmNetwork::new_auto_complete`]): proofs are -/// immediately ready when submitted. -#[derive(Clone)] -pub struct MockZkvmNetwork { - auto_complete: bool, - proofs: Arc>>, - next_handle: Arc, -} - -impl MockZkvmNetwork { - /// Creates a new `MockZkvmNetwork` where proofs remain pending until - /// [`Self::complete_proof`] is called. - pub fn new(auto_complete: bool) -> Self { - Self { - auto_complete, - proofs: Arc::new(Mutex::new(HashMap::new())), - next_handle: Arc::new(AtomicU64::new(0)), - } - } - - /// Marks a pending proof as ready, allowing [`ZkvmNetwork::poll`] to - /// return its bytes. - /// - /// # Panics - /// - /// Panics if `handle` does not correspond to a submitted proof. - pub fn complete_proof(&self, handle: u64) { - let mut proofs = self.proofs.lock().unwrap(); - let proof = proofs - .get_mut(&handle) - .expect("complete_proof called with unknown handle"); - proof.ready = true; - } - - /// Removes a proof from the internal map so that subsequent - /// [`ZkvmNetwork::poll`] calls for this handle return an error. - /// - /// # Panics - /// - /// Panics if `handle` does not correspond to a submitted proof. - pub fn fail_proof(&self, handle: u64) { - let mut proofs = self.proofs.lock().unwrap(); - assert!( - proofs.remove(&handle).is_some(), - "fail_proof called with unknown handle" - ); - } -} - -impl Default for MockZkvmNetwork { - fn default() -> Self { - Self::new(false) - } -} - -impl sov_rollup_interface::zk::ZkvmNetwork for MockZkvmNetwork { - type Guest = MockZkGuest; - type ProofHandle = u64; - - async fn add_hint_and_submit( - &self, - item: &T, - ) -> anyhow::Result { - let data = bincode::serialize(item).unwrap(); - let proof_bytes = bincode::serialize(&MockProof { - is_valid: true, - pub_data: data, - })?; - - let handle = self.next_handle.fetch_add(1, Ordering::Relaxed); - let mut proofs = self.proofs.lock().unwrap(); - proofs.insert( - handle, - MockNetworkProof { - proof_bytes, - ready: self.auto_complete, - }, - ); - Ok(handle) - } - - async fn poll(&self, handle: &Self::ProofHandle) -> anyhow::Result>> { - let proofs = self.proofs.lock().unwrap(); - match proofs.get(handle) { - Some(proof) if proof.ready => Ok(Some(proof.proof_bytes.clone())), - Some(_) => Ok(None), - None => anyhow::bail!("unknown proof handle: {handle}"), - } - } - - fn code_commitment( - &self, - ) -> anyhow::Result< - <::Verifier as sov_rollup_interface::zk::ZkVerifier>::CodeCommitment, - >{ - Ok(crate::MockCodeCommitment::default()) - } -} diff --git a/crates/adapters/risc0/src/lib.rs b/crates/adapters/risc0/src/lib.rs index 0466541371..cec9ba2225 100644 --- a/crates/adapters/risc0/src/lib.rs +++ b/crates/adapters/risc0/src/lib.rs @@ -123,9 +123,6 @@ impl sov_rollup_interface::zk::Zkvm for Risc0 { #[cfg(feature = "native")] type OuterHost = crate::host::Risc0Host<'static>; - - #[cfg(feature = "native")] - type Network = sov_rollup_interface::zk::NoopZkvmNetwork; } #[cfg(target_os = "zkvm")] diff --git a/crates/adapters/sp1/src/lib.rs b/crates/adapters/sp1/src/lib.rs index d9f5837ea4..8648f7b9f6 100644 --- a/crates/adapters/sp1/src/lib.rs +++ b/crates/adapters/sp1/src/lib.rs @@ -21,11 +21,6 @@ pub mod crypto; pub mod guest; #[cfg(feature = "native")] pub mod host; -#[cfg(feature = "native")] -pub mod network; - -#[cfg(feature = "native")] -pub mod metrics; /// Uniquely identifies a SP1 binary. Stored as a serialized version of `SP1VerifyingKey`. /// @@ -167,9 +162,6 @@ impl sov_rollup_interface::zk::Zkvm for SP1 { #[cfg(feature = "native")] type OuterHost = crate::host::SP1AggregationHost; - - #[cfg(feature = "native")] - type Network = crate::network::SP1Network; } #[cfg(target_os = "zkvm")] diff --git a/crates/adapters/sp1/src/metrics.rs b/crates/adapters/sp1/src/metrics.rs deleted file mode 100644 index fca041f50e..0000000000 --- a/crates/adapters/sp1/src/metrics.rs +++ /dev/null @@ -1,53 +0,0 @@ -//! Defines utilities for collecting runtime metrics from inside a SP1 VM -use std::io::Write; - -use sov_metrics::Metric; - -/// The type of SP1 prover that generated a proof. -#[derive(Debug)] -#[allow(dead_code)] -pub(crate) enum ProverType { - /// Local CPU prover. - Cpu, - /// Succinct proving network. - Network, -} - -impl ProverType { - /// Returns the string representation for use in metrics serialization. - pub fn as_str(&self) -> &'static str { - match self { - ProverType::Cpu => "cpu", - ProverType::Network => "network", - } - } -} - -/// Metrics emitted when the SP1 proving network fulfills a proof request. -#[derive(Debug)] -pub(crate) struct SP1ProofFulfillmentMetrics { - /// The type of prover emitting the metric. - pub prover_type: ProverType, - /// The hex-encoded proof request ID. - pub request_id: String, - /// Time from proof request creation to fulfillment, in seconds, as reported by the SP1 - /// network. - pub fulfillment_duration_secs: u64, -} - -impl Metric for SP1ProofFulfillmentMetrics { - fn measurement_name(&self) -> &'static str { - "sov_rollup_sp1_proof_fulfillment" - } - - fn serialize_for_telegraf(&self, buffer: &mut Vec) -> std::io::Result<()> { - write!( - buffer, - "{},prover_type={} request_id=\"{}\",fulfillment_duration_secs={}i", - self.measurement_name(), - self.prover_type.as_str(), - self.request_id, - self.fulfillment_duration_secs, - ) - } -} diff --git a/crates/adapters/sp1/src/network.rs b/crates/adapters/sp1/src/network.rs deleted file mode 100644 index bba8596dda..0000000000 --- a/crates/adapters/sp1/src/network.rs +++ /dev/null @@ -1,106 +0,0 @@ -//! Network prover implementation for SP1. -//! -//! Submits proof requests to the Succinct proving network and polls for results. - -use crate::guest::SP1Guest; -use serde::Serialize; -use sov_rollup_interface::zk::{ZkVerifier, ZkvmGuest, ZkvmNetwork}; -use sp1_sdk::network::proto::auction_types::FulfillmentStatus; -use sp1_sdk::network::{NetworkMode, B256}; -use sp1_sdk::prover::{ProveRequest, Prover}; -use sp1_sdk::HashableKey; -use sp1_sdk::{NetworkProver, ProverClient, ProvingKey, SP1ProvingKey, SP1Stdin}; - -/// Re-export of the proof handle type used by the SP1 network. -pub type ProofHandle = B256; - -/// SP1 network prover that submits proofs to the Succinct proving network. -pub struct SP1Network { - prover: NetworkProver, - pk: SP1ProvingKey, -} - -impl SP1Network { - /// Create a new `SP1Network` for the given ELF binary. - /// - /// Connects to the Succinct proving network (mainnet) and runs setup. - pub async fn new(elf: &[u8]) -> anyhow::Result { - let prover: NetworkProver = ProverClient::builder() - .network_for(NetworkMode::Mainnet) - .build() - .await; - let pk = prover - .setup(elf.into()) - .await - .map_err(|e| anyhow::anyhow!("SP1 network setup failed: {e}"))?; - - Ok(Self { prover, pk }) - } -} - -impl SP1Network { - async fn emit_fulfillment_metric(&self, request_id: B256) { - let proof_request = match self.prover.get_proof_request(request_id).await { - Ok(Some(req)) => req, - // Best-effort: silently skip metric if request details are unavailable. - Ok(None) | Err(_) => return, - }; - - if let Some(fulfilled_at) = proof_request.fulfilled_at { - let fulfillment_duration_secs = fulfilled_at - proof_request.created_at; - sov_metrics::track_metrics(|tracker| { - tracker.submit(crate::metrics::SP1ProofFulfillmentMetrics { - prover_type: crate::metrics::ProverType::Network, - request_id: format!("{request_id}"), - fulfillment_duration_secs, - }); - }); - } - } -} - -impl ZkvmNetwork for SP1Network { - type Guest = SP1Guest; - type ProofHandle = ProofHandle; - - async fn add_hint_and_submit( - &self, - item: &T, - ) -> anyhow::Result { - let mut stdin = SP1Stdin::new(); - stdin.write(item); - - let request_id = self - .prover - .prove(&self.pk, stdin) - .compressed() - .skip_simulation(true) - .request() - .await?; - - Ok(request_id) - } - - async fn poll(&self, handle: &Self::ProofHandle) -> anyhow::Result>> { - let (maybe_proof, status) = self.prover.process_proof_status(*handle, None).await?; - - if matches!(status, FulfillmentStatus::Unfulfillable) { - anyhow::bail!("Proof request {} is unfulfillable", handle); - } - - match maybe_proof { - Some(proof) => { - self.emit_fulfillment_metric(*handle).await; - - Ok(Some(bincode::serialize(&proof)?)) - } - None => Ok(None), - } - } - - fn code_commitment( - &self, - ) -> anyhow::Result<<::Verifier as ZkVerifier>::CodeCommitment> { - Ok(crate::SP1MethodId(self.pk.verifying_key().hash_u32())) - } -} diff --git a/crates/full-node/sov-stf-runner/src/processes/metrics.rs b/crates/full-node/sov-stf-runner/src/processes/metrics.rs index ac6b11308e..7e5d52e8b2 100644 --- a/crates/full-node/sov-stf-runner/src/processes/metrics.rs +++ b/crates/full-node/sov-stf-runner/src/processes/metrics.rs @@ -79,26 +79,3 @@ impl Metric for ZkAggregatedProofMetrics { ) } } - -/// Metrics for the network prover. -/// Emitted after each proof submission to the proving network. -#[derive(Debug)] -pub(crate) struct ZkNetworkProverMetrics { - /// Time in milliseconds for submitting a proof request to the network. - pub submit_duration_ms: u128, -} - -impl Metric for ZkNetworkProverMetrics { - fn measurement_name(&self) -> &'static str { - "sov_rollup_zk_network_prover" - } - - fn serialize_for_telegraf(&self, buffer: &mut Vec) -> std::io::Result<()> { - write!( - buffer, - "{} submit_duration_ms={}i", - self.measurement_name(), - self.submit_duration_ms, - ) - } -} diff --git a/crates/full-node/sov-stf-runner/src/processes/prover_service/mod.rs b/crates/full-node/sov-stf-runner/src/processes/prover_service/mod.rs index 9c4a2c278a..07d2392e97 100644 --- a/crates/full-node/sov-stf-runner/src/processes/prover_service/mod.rs +++ b/crates/full-node/sov-stf-runner/src/processes/prover_service/mod.rs @@ -1,11 +1,9 @@ -mod network; mod parallel; use std::fmt::Debug; use async_trait::async_trait; use borsh::BorshSerialize; -pub use network::NetworkProverService; pub use parallel::ParallelProverService; use serde::de::DeserializeOwned; use serde::Serialize; diff --git a/crates/full-node/sov-stf-runner/src/processes/prover_service/network/mod.rs b/crates/full-node/sov-stf-runner/src/processes/prover_service/network/mod.rs deleted file mode 100644 index 1ce4dc2b74..0000000000 --- a/crates/full-node/sov-stf-runner/src/processes/prover_service/network/mod.rs +++ /dev/null @@ -1,106 +0,0 @@ -mod prover; - -use std::sync::Arc; - -use async_trait::async_trait; -use borsh::BorshSerialize; -use prover::NetworkProver; -use serde::de::DeserializeOwned; -use serde::Serialize; -use sov_rollup_interface::da::DaSpec; -use sov_rollup_interface::node::da::DaService; -use sov_rollup_interface::zk::{Zkvm, ZkvmGuest}; - -use super::{ProverService, ProverServiceError, Verifier}; -use crate::processes::{ProofAggregationStatus, ProofProcessingStatus, StateTransitionInfo}; - -/// Prover service that submits proofs to a remote proving network. -/// -/// Instead of generating proofs locally (like [`super::ParallelProverService`]), -/// this service uses the [`ZkvmNetwork`] trait to submit proof requests to a -/// remote proving service and polls for completion. -pub struct NetworkProverService -where - Address: Serialize + DeserializeOwned, - StateRoot: Serialize + DeserializeOwned + Clone + AsRef<[u8]>, - Witness: Serialize + DeserializeOwned, - Da: DaService, - InnerVm: Zkvm, - OuterVm: Zkvm, -{ - prover: NetworkProver, - verifier: Arc>, -} - -impl - NetworkProverService -where - Address: - BorshSerialize + AsRef<[u8]> + Serialize + DeserializeOwned + Clone + Send + Sync + 'static, - StateRoot: Serialize + DeserializeOwned + Clone + AsRef<[u8]> + Send + Sync + 'static, - Witness: Serialize + DeserializeOwned + Send + Sync + 'static, - Da: DaService, - InnerVm: Zkvm + 'static, - OuterVm: Zkvm, -{ - /// Creates a new network prover service. - pub fn new( - inner_vm: InnerVm::Network, - outer_vm: OuterVm::Network, - da_verifier: Da::Verifier, - prover_address: Address, - outer_proof_timeout: std::time::Duration, - ) -> Self { - let verifier = Arc::new(Verifier { da_verifier }); - - Self { - prover: NetworkProver::new(prover_address, inner_vm, outer_vm, outer_proof_timeout), - verifier, - } - } -} - -#[async_trait] -impl ProverService - for NetworkProverService -where - Address: - BorshSerialize + AsRef<[u8]> + Serialize + DeserializeOwned + Clone + Send + Sync + 'static, - StateRoot: - BorshSerialize + Serialize + DeserializeOwned + Clone + AsRef<[u8]> + Send + Sync + 'static, - Witness: Serialize + DeserializeOwned + Send + Sync + 'static, - Da: DaService, - InnerVm: Zkvm + 'static, - OuterVm: Zkvm + 'static, -{ - type StateRoot = StateRoot; - type Witness = Witness; - type DaService = Da; - type Verifier = ::Verifier; - - async fn prove( - &self, - state_transition_info: StateTransitionInfo< - Self::StateRoot, - Self::Witness, - ::Spec, - >, - ) -> Result< - ProofProcessingStatus::Spec>, - ProverServiceError, - > { - self.prover - .start_proving(state_transition_info, &self.verifier) - .await - } - - async fn create_aggregated_proof( - &self, - block_headers: &[<::Spec as DaSpec>::BlockHeader], - genesis_state_root: &Self::StateRoot, - ) -> anyhow::Result { - self.prover - .create_aggregated_proof(block_headers, genesis_state_root) - .await - } -} diff --git a/crates/full-node/sov-stf-runner/src/processes/prover_service/network/prover.rs b/crates/full-node/sov-stf-runner/src/processes/prover_service/network/prover.rs deleted file mode 100644 index 2d197f0597..0000000000 --- a/crates/full-node/sov-stf-runner/src/processes/prover_service/network/prover.rs +++ /dev/null @@ -1,318 +0,0 @@ -use borsh::BorshSerialize; -use serde::de::DeserializeOwned; -use serde::Serialize; -use sov_rollup_interface::common::SlotNumber; -use sov_rollup_interface::da::{BlockHeaderTrait, DaSpec, DaVerifier}; -use sov_rollup_interface::node::da::DaService; -use sov_rollup_interface::zk::aggregated_proof::{ - AggregatedProofPublicData, BlockProof, SerializedAggregatedProof, -}; -use sov_rollup_interface::zk::{ - SerializedZkProof, StateTransitionPublicData, StateTransitionWitness, - StateTransitionWitnessWithAddress, Zkvm, ZkvmNetwork, -}; -use std::collections::HashMap; -use std::marker::PhantomData; - -use super::Verifier; -use crate::processes::{ - ProofAggregationStatus, ProofProcessingStatus, ProverServiceError, StateTransitionInfo, -}; - -struct SubmittedProofMetadata { - slot_number: SlotNumber, - st: StateTransitionPublicData, -} - -enum NetworkProverStatus { - Submitted { - handle: Handle, - metadata: SubmittedProofMetadata, - }, - Proved(BlockProof), - Err(anyhow::Error), -} - -type ProofStatusMap = HashMap< - ::SlotHash, - NetworkProverStatus< - Address, - StateRoot, - Da, - <::Network as ZkvmNetwork>::ProofHandle, - >, ->; - -pub(crate) struct NetworkProver< - Address, - StateRoot, - Witness, - Da: DaService, - InnerVm: Zkvm, - OuterVm: Zkvm, -> { - prover_address: Address, - inner_vm: InnerVm::Network, - outer_vm: OuterVm::Network, - tracker: tokio::sync::RwLock>, - outer_proof_timeout: std::time::Duration, - phantom: PhantomData, -} - -impl - NetworkProver -where - Da: DaService, - Address: - BorshSerialize + Serialize + DeserializeOwned + AsRef<[u8]> + Clone + Send + Sync + 'static, - StateRoot: Serialize + DeserializeOwned + Clone + AsRef<[u8]> + Send + Sync + 'static, - Witness: Serialize + DeserializeOwned + Send + Sync + 'static, - InnerVm: Zkvm + 'static, - OuterVm: Zkvm + 'static, -{ - pub(crate) fn new( - prover_address: Address, - inner_vm: InnerVm::Network, - outer_vm: OuterVm::Network, - outer_proof_timeout: std::time::Duration, - ) -> Self { - Self { - prover_address, - inner_vm, - outer_vm, - tracker: tokio::sync::RwLock::new(HashMap::new()), - outer_proof_timeout, - phantom: PhantomData, - } - } - - pub(crate) async fn start_proving( - &self, - state_transition_info: StateTransitionInfo, - verifier: &Verifier, - ) -> Result, ProverServiceError> { - let block_header_hash = state_transition_info.da_block_header().hash(); - - { - let tracker = self.tracker.read().await; - if let Some(status) = tracker.get(&block_header_hash) { - return match status { - NetworkProverStatus::Submitted { .. } => { - Err(ProverServiceError::Other(anyhow::anyhow!( - "Proof generation for {} still in progress", - block_header_hash, - ))) - } - NetworkProverStatus::Proved(_) => { - Err(ProverServiceError::Other(anyhow::anyhow!( - "Witness for block_header_hash {}, submitted multiple times.", - block_header_hash, - ))) - } - NetworkProverStatus::Err(e) => { - Err(ProverServiceError::Other(anyhow::format_err!("{}", e))) - } - }; - } - } - - let slot_number = state_transition_info.slot_number; - let data = StateTransitionWitnessWithAddress { - stf_witness: state_transition_info.data, - prover_address: self.prover_address.clone(), - }; - - // Verify DA BEFORE submitting to the network to avoid leaking a proof handle - verifier - .da_verifier - .verify_relevant_tx_list( - &data.stf_witness.da_block_header, - &data.stf_witness.relevant_blobs, - data.stf_witness.relevant_proofs.clone(), - ) - .map_err(|e| { - ProverServiceError::Other(anyhow::anyhow!("DA verification failed: {:?}", e)) - })?; - - let submit_start = std::time::Instant::now(); - let handle = self - .inner_vm - .add_hint_and_submit(&data) - .await - .map_err(ProverServiceError::Other)?; - sov_metrics::track_metrics(|tracker| { - tracker.submit(crate::processes::metrics::ZkNetworkProverMetrics { - submit_duration_ms: submit_start.elapsed().as_millis(), - }); - }); - - let StateTransitionWitnessWithAddress { - stf_witness: - StateTransitionWitness { - initial_state_root, - final_state_root, - .. - }, - prover_address, - } = data; - - let metadata = SubmittedProofMetadata { - slot_number, - st: StateTransitionPublicData { - initial_state_root, - final_state_root, - slot_hash: block_header_hash.clone(), - prover_address, - }, - }; - - tracing::trace!( - "Submitting proof to network for slot hash {}", - block_header_hash - ); - - { - let mut tracker = self.tracker.write().await; - tracker.insert( - block_header_hash, - NetworkProverStatus::Submitted { handle, metadata }, - ); - } - - Ok(ProofProcessingStatus::ProvingInProgress) - } - - pub(crate) async fn create_aggregated_proof( - &self, - block_headers: &[::BlockHeader], - genesis_state_root: &StateRoot, - ) -> anyhow::Result { - assert!(!block_headers.is_empty()); - - let block_header_hashes: Vec<_> = block_headers.iter().map(|h| h.hash()).collect(); - - let mut proof_statuses = self.tracker.write().await; - // Phase 1: Poll all Submitted entries and transition them to Proved. - // We only remove entries confirmed to be Submitted, so Proved/Err entries are untouched. - for slot_hash in &block_header_hashes { - // We want to only remove if we know the entry exists - if !matches!( - proof_statuses.get(slot_hash), - Some(NetworkProverStatus::Submitted { .. }) - ) { - continue; - } - - let Some(NetworkProverStatus::Submitted { handle, metadata }) = - proof_statuses.remove(slot_hash) - else { - unreachable!() - }; - - match self.inner_vm.poll(&handle).await { - Ok(Some(proof_bytes)) => { - let block_proof = BlockProof { - proof: SerializedZkProof { - raw_proof: proof_bytes, - }, - slot_number: metadata.slot_number, - st: metadata.st, - }; - proof_statuses - .insert(slot_hash.clone(), NetworkProverStatus::Proved(block_proof)); - } - Ok(None) => { - tracing::trace!( - "Proof for slot hash {} is still pending on the network", - slot_hash - ); - proof_statuses.insert( - slot_hash.clone(), - NetworkProverStatus::Submitted { handle, metadata }, - ); - return Ok(ProofAggregationStatus::ProofGenerationInProgress); - } - Err(e) => { - tracing::error!("Network proof for slot hash {} failed: {:?}", slot_hash, e); - proof_statuses.insert( - slot_hash.clone(), - NetworkProverStatus::Err(anyhow::anyhow!("Network proving failed: {}", e)), - ); - return Err(anyhow::anyhow!( - "Network proving failed for {}: {}", - slot_hash, - e - )); - } - } - } - - let proof_statuses = proof_statuses.downgrade(); - // Phase 2: Collect all proved block proofs. - let mut block_proofs_data = Vec::new(); - for slot_hash in &block_header_hashes { - match proof_statuses.get(slot_hash) { - Some(NetworkProverStatus::Proved(block_proof)) => { - assert_eq!(slot_hash, &block_proof.st.slot_hash); - block_proofs_data.push(block_proof); - } - Some(NetworkProverStatus::Err(e)) => { - return Err(anyhow::anyhow!(e.to_string())); - } - None => { - return Err(anyhow::anyhow!( - "Missing required proof of {:?}. Use the `prove` method to generate a proof of that block and try again.", - slot_hash - )); - } - Some(NetworkProverStatus::Submitted { .. }) => { - unreachable!("All Submitted entries should have been resolved in phase 1") - } - } - } - - let public_data = AggregatedProofPublicData::from_block_proofs( - &block_proofs_data, - genesis_state_root.clone(), - ); - - tracing::trace!(%public_data, "generating aggregate proof"); - - // Drop the read lock before submitting to the outer network. - drop(proof_statuses); - - let outer_handle = self.outer_vm.add_hint_and_submit(&public_data).await?; - - let serialized_aggregated_proof = tokio::time::timeout(self.outer_proof_timeout, async { - loop { - match self.outer_vm.poll(&outer_handle).await { - Ok(Some(proof_bytes)) => { - break Ok(SerializedAggregatedProof { - raw_aggregated_proof: proof_bytes, - }); - } - Ok(None) => { - tokio::time::sleep(std::time::Duration::from_secs(5)).await; - } - Err(e) => { - break Err(anyhow::anyhow!("Outer network proving failed: {}", e)); - } - } - } - }) - .await - .map_err(|_| { - anyhow::anyhow!( - "Outer network proving timed out after {:?}", - self.outer_proof_timeout - ) - })??; - - let mut tracker = self.tracker.write().await; - for slot_hash in &block_header_hashes { - tracker.remove(slot_hash); - } - - Ok(ProofAggregationStatus::Success(serialized_aggregated_proof)) - } -} diff --git a/crates/full-node/sov-stf-runner/tests/integration/prover_service/mod.rs b/crates/full-node/sov-stf-runner/tests/integration/prover_service/mod.rs index 6af6efaab2..a4c97ff489 100644 --- a/crates/full-node/sov-stf-runner/tests/integration/prover_service/mod.rs +++ b/crates/full-node/sov-stf-runner/tests/integration/prover_service/mod.rs @@ -1,4 +1,3 @@ -mod network; mod parallel; use sov_mock_da::{MockBlockHeader, MockDaSpec, MockHash}; diff --git a/crates/full-node/sov-stf-runner/tests/integration/prover_service/network.rs b/crates/full-node/sov-stf-runner/tests/integration/prover_service/network.rs deleted file mode 100644 index cf0b517e51..0000000000 --- a/crates/full-node/sov-stf-runner/tests/integration/prover_service/network.rs +++ /dev/null @@ -1,439 +0,0 @@ -use std::sync::Arc; -use std::time::Duration; - -use sov_mock_da::{MockDaService, MockDaSpec, MockDaVerifier, MockHash}; -use sov_mock_zkvm::{MockCodeCommitment, MockZkVerifier, MockZkvm, MockZkvmNetwork}; -use sov_modules_api::ZkVerifier; -use sov_rollup_interface::zk::aggregated_proof::AggregatedProofPublicData; -use sov_stf_runner::processes::{ - NetworkProverService, ProofAggregationStatus, ProofProcessingStatus, ProverService, -}; - -use super::{make_header, make_transition_info, Address, StateRoot}; -use crate::helpers::genesis_state_root; - -struct TestNetworkProver { - prover_service: - NetworkProverService, MockDaService, MockZkvm, MockZkvm>, - inner_vm: MockZkvmNetwork, - outer_vm: MockZkvmNetwork, -} - -fn make_network_prover( - inner_auto_complete: bool, - outer_auto_complete: bool, - outer_proof_timeout: Duration, -) -> TestNetworkProver { - let inner_vm = MockZkvmNetwork::new(inner_auto_complete); - let outer_vm = MockZkvmNetwork::new(outer_auto_complete); - - let da_verifier = MockDaVerifier::default(); - TestNetworkProver { - prover_service: NetworkProverService::new( - inner_vm.clone(), - outer_vm.clone(), - da_verifier, - vec![], - outer_proof_timeout, - ), - inner_vm, - outer_vm, - } -} - -#[tokio::test(flavor = "multi_thread")] -async fn test_network_prove_and_aggregate() { - // Outer auto-completes so the poll loop in create_aggregated_proof returns immediately. - let TestNetworkProver { - prover_service, - inner_vm, - .. - } = make_network_prover(false, true, Duration::from_secs(60)); - - let header = make_header(MockHash::from([1; 32]), 0); - let genesis = genesis_state_root(); - - // Submit one block — should return ProvingInProgress. - let status = prover_service - .prove(make_transition_info(header.clone())) - .await - .unwrap(); - assert!(matches!( - status, - ProofProcessingStatus::, Vec, MockDaSpec>::ProvingInProgress, - )); - - // Inner proof not ready yet → ProofGenerationInProgress. - let status = prover_service - .create_aggregated_proof(std::slice::from_ref(&header), &genesis.0) - .await - .unwrap(); - assert_eq!(status, ProofAggregationStatus::ProofGenerationInProgress); - - // Complete inner proof (handle 0 is the first submitted proof). - inner_vm.complete_proof(0); - - // Now aggregation should succeed. - let status = prover_service - .create_aggregated_proof(&[header], &genesis.0) - .await - .unwrap(); - - match status { - ProofAggregationStatus::Success(proof) => { - let serialized_proof = proof.to_serialized_zk_proof(); - let public_data = ::verify_with_proof::< - AggregatedProofPublicData, - >(&serialized_proof, &MockCodeCommitment::default()) - .unwrap(); - assert_eq!(public_data.initial_slot_number.get(), 1); - assert_eq!(public_data.final_slot_number.get(), 1); - } - ProofAggregationStatus::ProofGenerationInProgress => { - panic!("Expected Success after completing inner proof") - } - } -} - -#[tokio::test(flavor = "multi_thread")] -async fn test_network_prove_returns_in_progress() { - let TestNetworkProver { - prover_service, - inner_vm: _, - .. - } = make_network_prover(false, true, Duration::from_secs(60)); - - let header = make_header(MockHash::from([2; 32]), 1); - let genesis = genesis_state_root(); - - prover_service - .prove(make_transition_info(header.clone())) - .await - .unwrap(); - - // Don't complete the inner proof — aggregation should stay in progress. - let status = prover_service - .create_aggregated_proof(&[header], &genesis.0) - .await - .unwrap(); - assert_eq!(status, ProofAggregationStatus::ProofGenerationInProgress); -} - -#[tokio::test(flavor = "multi_thread")] -async fn test_network_aggregated_proof_multiple_blocks() { - let TestNetworkProver { - prover_service, - inner_vm, - .. - } = make_network_prover(false, true, Duration::from_secs(60)); - - let block_count = 5; - let genesis = genesis_state_root(); - let headers: Vec<_> = (0..block_count) - .map(|height| make_header(MockHash::from([height as u8 + 10; 32]), height as u64)) - .collect(); - - // Submit all blocks. - for header in headers.iter().cloned() { - prover_service - .prove(make_transition_info(header)) - .await - .unwrap(); - } - - // Complete all inner proofs (handles 0..5). - for handle in 0..block_count { - inner_vm.complete_proof(handle as u64); - } - - let status = prover_service - .create_aggregated_proof(&headers, &genesis.0) - .await - .unwrap(); - - match status { - ProofAggregationStatus::Success(proof) => { - let serialized_proof = proof.to_serialized_zk_proof(); - let public_data = ::verify_with_proof::< - AggregatedProofPublicData, - >(&serialized_proof, &MockCodeCommitment::default()) - .unwrap(); - assert_eq!(public_data.initial_slot_number.get(), 1); - assert_eq!(public_data.final_slot_number.get(), 5); - } - ProofAggregationStatus::ProofGenerationInProgress => { - panic!("Expected Success after completing all inner proofs") - } - } -} - -#[tokio::test(flavor = "multi_thread")] -async fn test_network_duplicate_proof_rejected() { - let TestNetworkProver { - prover_service, - inner_vm: _, - .. - } = make_network_prover(false, true, Duration::from_secs(60)); - - let header = make_header(MockHash::from([4; 32]), 1); - - // First prove succeeds. - let status = prover_service - .prove(make_transition_info(header.clone())) - .await - .unwrap(); - assert!(matches!( - status, - ProofProcessingStatus::, Vec, MockDaSpec>::ProvingInProgress, - )); - - // Second prove with same header hash should fail. - let err = prover_service - .prove(make_transition_info(header.clone())) - .await - .expect_err("Duplicate proof submission should be rejected"); - assert_eq!( - err.to_string(), - format!("Proof generation for {} still in progress", header.hash) - ); -} - -#[tokio::test(flavor = "multi_thread")] -async fn test_network_prove_rejected_after_proved() { - let TestNetworkProver { - prover_service, - inner_vm, - .. - } = make_network_prover(false, true, Duration::from_secs(60)); - - let genesis = genesis_state_root(); - let header_a = make_header(MockHash::from([5; 32]), 1); - let header_b = make_header(MockHash::from([6; 32]), 2); - - // Submit two blocks. - prover_service - .prove(make_transition_info(header_a.clone())) - .await - .unwrap(); - prover_service - .prove(make_transition_info(header_b.clone())) - .await - .unwrap(); - - // Complete only block A's inner proof (handle 0). - inner_vm.complete_proof(0); - - // Aggregate [A, B]: A transitions to Proved, B is still pending → InProgress. - let status = prover_service - .create_aggregated_proof(&[header_a.clone(), header_b], &genesis.0) - .await - .unwrap(); - assert_eq!(status, ProofAggregationStatus::ProofGenerationInProgress); - - // Proving A again should fail because it is already Proved. - let err = prover_service - .prove(make_transition_info(header_a.clone())) - .await - .expect_err("Re-proving a Proved block should be rejected"); - assert_eq!( - err.to_string(), - format!( - "Witness for block_header_hash {}, submitted multiple times.", - header_a.hash - ) - ); -} - -#[tokio::test(flavor = "multi_thread")] -async fn test_network_prove_rejected_after_error() { - let TestNetworkProver { - prover_service, - inner_vm, - .. - } = make_network_prover(false, true, Duration::from_secs(60)); - - let genesis = genesis_state_root(); - let header_a = make_header(MockHash::from([7; 32]), 1); - - // Submit block A. - prover_service - .prove(make_transition_info(header_a.clone())) - .await - .unwrap(); - - // Remove the proof so poll returns an error. - inner_vm.fail_proof(0); - - // Aggregation triggers the Err branch in Phase 1. - let err = prover_service - .create_aggregated_proof(std::slice::from_ref(&header_a), &genesis.0) - .await - .expect_err("Aggregation should fail when proof is missing"); - assert!( - err.to_string().contains("unknown proof handle: 0"), - "Expected 'unknown proof handle' error, got: {}", - err - ); - - // Proving A again should propagate the stored error. - let err = prover_service - .prove(make_transition_info(header_a)) - .await - .expect_err("Re-proving after error should propagate the stored error"); - assert!( - err.to_string().contains("unknown proof handle: 0"), - "Expected stored error to contain 'unknown proof handle', got: {}", - err - ); -} - -/// Regression test: when `create_aggregated_proof` is called with multiple blocks -/// and only some are ready, it returns early after transitioning the ready ones to -/// `Proved`. A second call must still find those `Proved` entries intact. Previously, -/// a `remove` + `if let Submitted` pattern silently dropped non-`Submitted` entries. -#[tokio::test(flavor = "multi_thread")] -async fn test_network_aggregation_preserves_proved_entries_across_calls() { - let TestNetworkProver { - prover_service, - inner_vm, - .. - } = make_network_prover(false, true, Duration::from_secs(60)); - - let genesis = genesis_state_root(); - let header_a = make_header(MockHash::from([8; 32]), 0); - let header_b = make_header(MockHash::from([9; 32]), 1); - - // Submit two blocks. - prover_service - .prove(make_transition_info(header_a.clone())) - .await - .unwrap(); - prover_service - .prove(make_transition_info(header_b.clone())) - .await - .unwrap(); - - // Complete only A (handle 0). - inner_vm.complete_proof(0); - - // First aggregation: A transitions to Proved, B is still pending → InProgress. - let status = prover_service - .create_aggregated_proof(&[header_a.clone(), header_b.clone()], &genesis.0) - .await - .unwrap(); - assert_eq!(status, ProofAggregationStatus::ProofGenerationInProgress); - - // Complete B (handle 1). - inner_vm.complete_proof(1); - - // Second aggregation: A should still be Proved (not dropped), B transitions to Proved. - let status = prover_service - .create_aggregated_proof(&[header_a, header_b], &genesis.0) - .await - .unwrap(); - - match status { - ProofAggregationStatus::Success(proof) => { - let serialized_proof = proof.to_serialized_zk_proof(); - let public_data = ::verify_with_proof::< - AggregatedProofPublicData, - >(&serialized_proof, &MockCodeCommitment::default()) - .unwrap(); - assert_eq!(public_data.initial_slot_number.get(), 1); - assert_eq!(public_data.final_slot_number.get(), 2); - } - ProofAggregationStatus::ProofGenerationInProgress => { - panic!("Expected Success after completing both inner proofs") - } - } -} - -/// Regression test: the error message from an outer proof timeout must contain -/// "Outer network proving timed out". This substring is matched in -/// `create_aggregate_proof_with_retries` to treat outer proof failures as fatal -/// (non-retryable). If the message changes, the fatal check will silently stop -/// matching, and retries will re-submit to the outer network — abandoning the -/// original proof handle and wasting proving resources. -#[tokio::test(flavor = "multi_thread")] -async fn test_network_outer_proof_timeout_error_message() { - // Inner auto-completes; outer never completes (manual); short timeout. - let TestNetworkProver { - prover_service, - inner_vm: _, - outer_vm: _, - } = make_network_prover(true, false, Duration::from_millis(100)); - - let header = make_header(MockHash::from([20; 32]), 1); - let genesis = genesis_state_root(); - - prover_service - .prove(make_transition_info(header.clone())) - .await - .unwrap(); - - let err = prover_service - .create_aggregated_proof(&[header], &genesis.0) - .await - .expect_err("Should fail with outer proof timeout"); - - let msg = err.to_string(); - assert!( - msg.contains("Outer network proving timed out"), - "Expected error to contain 'Outer network proving timed out', got: {msg}", - ); -} - -/// Regression test: the error message from an outer proof poll failure must -/// contain "Outer network proving failed". This substring is matched in -/// `create_aggregate_proof_with_retries` to treat outer proof failures as fatal -/// (non-retryable). If the message changes, the fatal check will silently stop -/// matching, and retries will re-submit to the outer network — abandoning the -/// original proof handle and wasting proving resources. -#[tokio::test(flavor = "multi_thread")] -async fn test_network_outer_proof_poll_failure_error_message() { - // Inner auto-completes; outer is manual so we can fail it. - let TestNetworkProver { - prover_service, - inner_vm: _, - outer_vm, - } = make_network_prover(true, false, Duration::from_secs(60)); - - let header = make_header(MockHash::from([21; 32]), 1); - let genesis = genesis_state_root(); - - let prover_service = Arc::new(prover_service); - - prover_service - .prove(make_transition_info(header.clone())) - .await - .unwrap(); - - // Spawn aggregation in background — it will submit to the outer VM then poll. - let agg_handle = tokio::spawn({ - let prover_service = Arc::clone(&prover_service); - let genesis = genesis.clone(); - let header = header.clone(); - async move { - prover_service - .create_aggregated_proof(&[header], &genesis.0) - .await - } - }); - - // Give the aggregation task time to submit the outer proof (handle 0). - tokio::time::sleep(Duration::from_millis(100)).await; - - // Fail the outer proof so the next poll returns an error. - outer_vm.fail_proof(0); - - let err = agg_handle - .await - .expect("Task should not panic") - .expect_err("Should fail with outer proof poll error"); - - let msg = err.to_string(); - assert!( - msg.contains("Outer network proving failed"), - "Expected error to contain 'Outer network proving failed', got: {msg}", - ); -} diff --git a/crates/rollup-interface/src/state_machine/zk/mod.rs b/crates/rollup-interface/src/state_machine/zk/mod.rs index 219e9d44ca..7f39588853 100644 --- a/crates/rollup-interface/src/state_machine/zk/mod.rs +++ b/crates/rollup-interface/src/state_machine/zk/mod.rs @@ -63,14 +63,6 @@ pub trait Zkvm: Default + Clone + Send + Sync + 'static { /// Only available under the `"native"` feature. #[cfg(feature = "native")] type OuterHost: aggregated_proof::OuterZkvmHost; - - /// Network proving implementation for this Zkvm. - /// Only available under the `"native"` feature. - /// - /// This is an optional component - if the Zkvm does not support network proving, this can be set to `NoopZkvmNetwork`, - /// which is a dummy implementation that cannot be used or constructed. - #[cfg(feature = "native")] - type Network: ZkvmNetwork>; } /// The code commitment for the Zkvm @@ -165,80 +157,6 @@ pub trait ZkVerifier: Default + Clone + Send + Sync + 'static { ) -> Result; } -/// A network prover that can submit proofs asynchronously and poll for results. -/// -/// Unlike [`ZkvmHost`] which runs proofs synchronously via [`ZkvmHost::add_hint_and_run`], -/// a `ZkvmNetwork` submits proof requests to a remote proving service and returns -/// a handle that can be polled for completion. This enables concurrent proof generation -/// across multiple blocks. -#[cfg(feature = "native")] -pub trait ZkvmNetwork: Send + Sync + 'static { - /// The associated guest type. - type Guest: ZkvmGuest; - - /// An opaque handle returned by [`ZkvmNetwork::submit`] that identifies a pending proof. - type ProofHandle: Send + Sync + Clone + core::fmt::Debug + 'static; - - /// Add a hint and submit the proof request in one atomic operation. - /// - /// Network proving always generates a real proof. - /// Returns a [`Self::ProofHandle`] that can be passed to [`ZkvmNetwork::poll`] to check for the result. - fn add_hint_and_submit( - &self, - item: &T, - ) -> impl core::future::Future> + Send; - - /// Check whether a previously submitted proof is ready. - /// - /// Returns `Ok(Some(proof_bytes))` when the proof is complete, - /// `Ok(None)` if it is still pending, or an error if proving failed. - fn poll( - &self, - handle: &Self::ProofHandle, - ) -> impl core::future::Future>>> + Send; - - /// Returns a commitment to the program being proven. - /// - /// This is the verifying key that identifies the guest program and can be - /// stored at genesis for proof verification. - fn code_commitment( - &self, - ) -> anyhow::Result<<::Verifier as ZkVerifier>::CodeCommitment>; -} - -/// A no-op [`ZkvmNetwork`] for ZKVMs that don't support network proving. -/// -/// This type cannot be constructed because it contains an [`Infallible`](core::convert::Infallible) -/// field. All trait methods use `match self._void {}` to statically prove they are unreachable. -#[cfg(feature = "native")] -pub struct NoopZkvmNetwork { - _guest: core::marker::PhantomData, - _void: core::convert::Infallible, -} - -#[cfg(feature = "native")] -impl ZkvmNetwork for NoopZkvmNetwork { - type Guest = G; - type ProofHandle = (); - - async fn add_hint_and_submit( - &self, - _item: &T, - ) -> anyhow::Result { - match self._void {} - } - - async fn poll(&self, _handle: &Self::ProofHandle) -> anyhow::Result>> { - match self._void {} - } - - fn code_commitment( - &self, - ) -> anyhow::Result<<::Verifier as ZkVerifier>::CodeCommitment> { - match self._void {} - } -} - /// A trait which is accessible from within a zkVM program. pub trait ZkvmGuest: Send + Sync { /// The verifier type associated with this vm. diff --git a/examples/demo-rollup/tests/prover/mod.rs b/examples/demo-rollup/tests/prover/mod.rs index cd2ce6a77d..34afca4061 100644 --- a/examples/demo-rollup/tests/prover/mod.rs +++ b/examples/demo-rollup/tests/prover/mod.rs @@ -40,7 +40,6 @@ pub(super) type DefaultSpec = sov_modules_api::configurable_spec::ConfigurableSp >; mod datagen; -mod network; mod parallel; mod sp1_cpu_prover; @@ -51,9 +50,6 @@ pub(super) type StfWitness = StateTransitionWitness (ProofStateRoot, Vec) { let temp_dir = TempDir::new().expect("Unable to create temporary directory"); diff --git a/examples/demo-rollup/tests/prover/network.rs b/examples/demo-rollup/tests/prover/network.rs deleted file mode 100644 index f744e0e546..0000000000 --- a/examples/demo-rollup/tests/prover/network.rs +++ /dev/null @@ -1,114 +0,0 @@ -use std::time::Duration; - -use sov_mock_da::{MockDaService, MockDaSpec}; -use sov_mock_zkvm::{MockZkvm, MockZkvmNetwork}; -use sov_modules_api::Spec; -use sov_rollup_interface::common::SlotNumber; -use sov_sp1_adapter::network::SP1Network; -use sov_sp1_adapter::SP1; -use sov_stf_runner::processes::{ - NetworkProverService, ProofAggregationStatus, ProofProcessingStatus, ProverService, - StateTransitionInfo, -}; - -use super::{DefaultSpec, ProofStateRoot, ProofWitness}; - -type TestNetworkProverService = NetworkProverService< - ::Address, - ProofStateRoot, - ProofWitness, - MockDaService, - SP1, - MockZkvm, ->; - -/// Tests proof generation using the SP1 network prover service. -/// -/// This submits real proof requests to the Succinct proving network for per-block -/// (inner) proofs, and uses MockZkvmNetwork (auto-complete) for aggregation (outer). -/// -/// Prerequisites: -/// - `NETWORK_PRIVATE_KEY` env var set (Succinct network auth) -/// - SP1 guest ELF built (`cargo build` in the prover guest directory) -/// - Network access to Succinct's proving infrastructure -#[tokio::test(flavor = "multi_thread")] -#[ignore = "Requires SP1_PRIVATE_KEY and network access to the Succinct proving network"] -async fn test_network_proof_generation() { - tracing_subscriber::fmt::init(); - - let elf: &[u8] = *sp1::SP1_GUEST_MOCK_ELF; - assert!( - !elf.is_empty(), - "SP1 guest ELF is empty — build the guest first" - ); - - let inner_vm = SP1Network::new(elf) - .await - .expect("Failed to create SP1 network prover"); - // auto-complete outer proofs - real outer not supported yet - let outer_vm = MockZkvmNetwork::new(true); - - let da_verifier = sov_mock_da::MockDaVerifier::default(); - let prover_address = ::Address::try_from([0u8; 28].as_ref()).unwrap(); - - let prover_service = TestNetworkProverService::new( - inner_vm, - outer_vm, - da_verifier, - prover_address, - Duration::from_secs(600), - ); - - let (genesis_state_root, witnesses) = super::generate_witnesses().await; - - // Submit all blocks to the network prover. - let mut block_headers = Vec::new(); - for (i, witness) in witnesses.into_iter().enumerate() { - block_headers.push(witness.da_block_header.clone()); - - let slot_number = SlotNumber::new(i as u64 + 1); - let state_transition_info = StateTransitionInfo::new(witness, slot_number); - - let status = prover_service - .prove(state_transition_info) - .await - .expect("prove() should succeed"); - assert!( - matches!( - status, - ProofProcessingStatus::::ProvingInProgress - ), - "Expected ProvingInProgress after submitting block {i}" - ); - tracing::info!("Block {} submitted to network prover", i); - } - - tracing::info!( - "All {} blocks submitted, waiting for proofs...", - block_headers.len() - ); - - // Poll until the aggregated proof is ready. - let status = loop { - match prover_service - .create_aggregated_proof(&block_headers, &genesis_state_root) - .await - { - Ok(ProofAggregationStatus::Success(proof)) => break proof, - Ok(ProofAggregationStatus::ProofGenerationInProgress) => { - tracing::info!("Inner proofs still in progress, polling again in 30s..."); - tokio::time::sleep(Duration::from_secs(30)).await; - } - Err(e) => panic!("Aggregation failed: {e}"), - } - }; - - tracing::info!( - "Aggregated proof generated successfully ({} bytes)", - status.raw_aggregated_proof.len() - ); - assert!( - !status.raw_aggregated_proof.is_empty(), - "Aggregated proof should not be empty" - ); -}