diff --git a/crates/adapters/sp1/Cargo.toml b/crates/adapters/sp1/Cargo.toml index fe5d31bb41..deefe6245c 100644 --- a/crates/adapters/sp1/Cargo.toml +++ b/crates/adapters/sp1/Cargo.toml @@ -60,7 +60,7 @@ native = [ "rand", "sp1-sdk/network", "sov-rollup-interface/native", - "sov-metrics?/native", + "sov-metrics/native", "sov-sp1-adapter/native", ] bench = [ diff --git a/crates/adapters/sp1/src/lib.rs b/crates/adapters/sp1/src/lib.rs index 5ebc97e910..bfef0ffaa7 100644 --- a/crates/adapters/sp1/src/lib.rs +++ b/crates/adapters/sp1/src/lib.rs @@ -23,7 +23,7 @@ pub mod host; #[cfg(feature = "native")] pub mod network; -#[cfg(all(feature = "native", feature = "bench"))] +#[cfg(feature = "native")] pub mod metrics; /// Uniquely identifies a SP1 binary. Stored as a serialized version of `SP1VerifyingKey`. diff --git a/crates/adapters/sp1/src/metrics.rs b/crates/adapters/sp1/src/metrics.rs index cf56bf8197..99fd6dbe1e 100644 --- a/crates/adapters/sp1/src/metrics.rs +++ b/crates/adapters/sp1/src/metrics.rs @@ -1,4 +1,9 @@ //! Defines utilities for collecting runtime metrics from inside a SP1 VM +use std::io::Write; + +use sov_metrics::Metric; + +#[cfg(feature = "bench")] use sp1_sdk::HookEnv; /// A custom callback for extracting metrics from the SP1 zkvm. @@ -6,8 +11,58 @@ use sp1_sdk::HookEnv; /// When the "bench" feature is enabled, this callback is registered as a syscall /// in the SP1 VM and invoked whenever a function annotated with the `cycle_tracker` /// macro is invoked. +#[cfg(feature = "bench")] pub fn metrics_hook(_env: HookEnv, buf: &[u8]) -> Vec> { let _ = sov_metrics::cycle_utils::deserialize_metrics_call(buf).unwrap(); vec![] } + +/// 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 index 34a37d4ebc..bba8596dda 100644 --- a/crates/adapters/sp1/src/network.rs +++ b/crates/adapters/sp1/src/network.rs @@ -38,6 +38,27 @@ impl SP1Network { } } +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; @@ -68,7 +89,11 @@ impl ZkvmNetwork for SP1Network { } match maybe_proof { - Some(proof) => Ok(Some(bincode::serialize(&proof)?)), + Some(proof) => { + self.emit_fulfillment_metric(*handle).await; + + Ok(Some(bincode::serialize(&proof)?)) + } None => Ok(None), } }