mirror of
https://github.com/eth-act/ere.git
synced 2026-02-19 11:54:42 -05:00
feat: upgrade sp1 to v6.0.0
This commit is contained in:
1393
Cargo.lock
generated
1393
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -137,8 +137,12 @@ risc0-zkvm = { version = "3.0.4", default-features = false }
|
||||
risc0-zkvm-platform = { version = "2.2.1", default-features = false }
|
||||
|
||||
# SP1 dependencies
|
||||
sp1-sdk = "5.2.4"
|
||||
sp1-zkvm = { version = "5.2.4", default-features = false }
|
||||
sp1-cuda = "6.0.0"
|
||||
sp1-hypercube = "6.0.0"
|
||||
sp1-recursion-executor = "6.0.0"
|
||||
sp1-sdk = "6.0.0"
|
||||
sp1-p3-field = { version = "0.3.1-succinct", package = "p3-field" }
|
||||
sp1-zkvm = { version = "6.0.0", default-features = false }
|
||||
|
||||
# Ziren dependencies
|
||||
zkm-sdk = { git = "https://github.com/ProjectZKM/Ziren.git", tag = "v1.2.3" }
|
||||
|
||||
@@ -11,10 +11,15 @@ bincode = { workspace = true, features = ["alloc", "serde"] }
|
||||
serde.workspace = true
|
||||
tempfile.workspace = true
|
||||
thiserror.workspace = true
|
||||
tokio = { workspace = true, features = ["rt-multi-thread"], optional = true }
|
||||
tracing.workspace = true
|
||||
|
||||
# SP1 dependencies
|
||||
sp1-sdk = { workspace = true, optional = true }
|
||||
sp1-cuda = { workspace = true, optional = true }
|
||||
sp1-hypercube = { workspace = true, optional = true }
|
||||
sp1-p3-field = { workspace = true, optional = true }
|
||||
sp1-recursion-executor = { workspace = true, optional = true }
|
||||
sp1-sdk = { workspace = true, features = ["network"], optional = true }
|
||||
|
||||
# Local dependencies
|
||||
ere-compile-utils = { workspace = true, optional = true }
|
||||
@@ -29,7 +34,7 @@ ere-build-utils.workspace = true
|
||||
[features]
|
||||
default = ["compiler", "zkvm"]
|
||||
compiler = ["dep:ere-compile-utils"]
|
||||
zkvm = ["dep:sp1-sdk"]
|
||||
zkvm = ["dep:tokio", "dep:sp1-cuda", "dep:sp1-hypercube", "dep:sp1-p3-field", "dep:sp1-recursion-executor", "dep:sp1-sdk"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -15,10 +15,10 @@ ere-platform-trait.workspace = true
|
||||
[features]
|
||||
default = ["lib", "libm"]
|
||||
blake3 = ["sp1-zkvm/blake3"]
|
||||
embedded = ["sp1-zkvm/embedded"]
|
||||
lib = ["sp1-zkvm/lib"]
|
||||
libm = ["sp1-zkvm/libm"]
|
||||
verify = ["sp1-zkvm/verify"]
|
||||
untrusted_programs = ["sp1-zkvm/untrusted_programs"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@@ -4,15 +4,13 @@ use ere_zkvm_interface::compiler::Compiler;
|
||||
use std::{env, path::Path};
|
||||
|
||||
const TARGET_TRIPLE: &str = "riscv32ima-unknown-none-elf";
|
||||
/// According to https://github.com/succinctlabs/sp1/blob/v6.0.0/crates/build/src/command/utils.rs#L49.
|
||||
const RUSTFLAGS: &[&str] = &[
|
||||
"-C",
|
||||
"passes=lower-atomic", // Only for rustc > 1.81
|
||||
"-C",
|
||||
// Start of the code section
|
||||
"link-arg=-Ttext=0x00201000",
|
||||
"-C",
|
||||
// The lowest memory location that will be used when your program is loaded
|
||||
"link-arg=--image-base=0x00200800",
|
||||
"-C",
|
||||
"link-arg=--image-base=0x78000000",
|
||||
"-C",
|
||||
"panic=abort",
|
||||
"--cfg",
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
use crate::{program::SP1Program, zkvm::sdk::Prover};
|
||||
use crate::{program::SP1Program, zkvm::sdk::SP1Sdk};
|
||||
use anyhow::bail;
|
||||
use ere_zkvm_interface::zkvm::{
|
||||
CommonError, Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind,
|
||||
ProverResource, PublicValues, zkVM, zkVMProgramDigest,
|
||||
};
|
||||
use sp1_sdk::{SP1ProofMode, SP1ProofWithPublicValues, SP1ProvingKey, SP1Stdin, SP1VerifyingKey};
|
||||
use std::{
|
||||
mem::take,
|
||||
panic,
|
||||
sync::{RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
time::Instant,
|
||||
};
|
||||
use sp1_sdk::{SP1ProofMode, SP1ProofWithPublicValues, SP1Stdin, SP1VerifyingKey};
|
||||
use std::{future::Future, sync::OnceLock, time::Instant};
|
||||
use tracing::info;
|
||||
|
||||
mod error;
|
||||
@@ -21,42 +16,13 @@ pub use error::Error;
|
||||
include!(concat!(env!("OUT_DIR"), "/name_and_sdk_version.rs"));
|
||||
|
||||
pub struct EreSP1 {
|
||||
program: SP1Program,
|
||||
/// Prover resource configuration for creating clients
|
||||
resource: ProverResource,
|
||||
/// Proving key
|
||||
pk: SP1ProvingKey,
|
||||
/// Verification key
|
||||
vk: SP1VerifyingKey,
|
||||
// The current version of SP1 (v5.2.4) has a problem where if GPU proving
|
||||
// the program crashes in the Moongate container, it leaves an internal
|
||||
// mutex poisoned, which prevents further proving attempts.
|
||||
// This is a workaround to avoid the poisoned mutex issue by creating a new
|
||||
// prover if the proving panics.
|
||||
// Eventually, this should be fixed in the SP1 SDK.
|
||||
// For more context see: https://github.com/eth-act/zkevm-benchmark-workload/issues/54
|
||||
prover: RwLock<Prover>,
|
||||
sdk: SP1Sdk,
|
||||
}
|
||||
|
||||
impl EreSP1 {
|
||||
pub fn new(program: SP1Program, resource: ProverResource) -> Result<Self, Error> {
|
||||
let prover = Prover::new(&resource)?;
|
||||
let (pk, vk) = prover.setup(&program.elf)?;
|
||||
Ok(Self {
|
||||
program,
|
||||
resource,
|
||||
pk,
|
||||
vk,
|
||||
prover: RwLock::new(prover),
|
||||
})
|
||||
}
|
||||
|
||||
fn prover(&'_ self) -> Result<RwLockReadGuard<'_, Prover>, Error> {
|
||||
self.prover.read().map_err(|_| Error::RwLockPosioned)
|
||||
}
|
||||
|
||||
fn prover_mut(&'_ self) -> Result<RwLockWriteGuard<'_, Prover>, Error> {
|
||||
self.prover.write().map_err(|_| Error::RwLockPosioned)
|
||||
let sdk = block_on(SP1Sdk::new(program.elf, &resource))?;
|
||||
Ok(Self { sdk })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,10 +30,8 @@ impl zkVM for EreSP1 {
|
||||
fn execute(&self, input: &Input) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> {
|
||||
let stdin = input_to_stdin(input)?;
|
||||
|
||||
let prover = self.prover()?;
|
||||
|
||||
let start = Instant::now();
|
||||
let (public_values, exec_report) = prover.execute(self.program.elf(), &stdin)?;
|
||||
let (public_values, exec_report) = block_on(self.sdk.execute(stdin))?;
|
||||
let execution_duration = start.elapsed();
|
||||
|
||||
Ok((
|
||||
@@ -85,7 +49,7 @@ impl zkVM for EreSP1 {
|
||||
input: &Input,
|
||||
proof_kind: ProofKind,
|
||||
) -> anyhow::Result<(PublicValues, Proof, ProgramProvingReport)> {
|
||||
info!("Generating proof…");
|
||||
info!("Generating proof...");
|
||||
|
||||
let stdin = input_to_stdin(input)?;
|
||||
|
||||
@@ -94,27 +58,8 @@ impl zkVM for EreSP1 {
|
||||
ProofKind::Groth16 => SP1ProofMode::Groth16,
|
||||
};
|
||||
|
||||
let mut prover = self.prover_mut()?;
|
||||
|
||||
// Restart GPU prover if the prover is dropped before.
|
||||
if matches!(self.resource, ProverResource::Gpu) && matches!(&*prover, Prover::Cpu(_)) {
|
||||
*prover = Prover::new(&self.resource).and_then(|prover| {
|
||||
prover.setup(&self.program.elf)?;
|
||||
Ok(prover)
|
||||
})?;
|
||||
}
|
||||
|
||||
let start = Instant::now();
|
||||
let proof =
|
||||
panic::catch_unwind(|| prover.prove(&self.pk, &stdin, mode)).map_err(|err| {
|
||||
if matches!(self.resource, ProverResource::Gpu) {
|
||||
// Drop the panicked GPU prover and replace it with CPU one,
|
||||
// next prove call will try to restart it.
|
||||
take(&mut *prover);
|
||||
}
|
||||
|
||||
Error::Panic(panic_msg(err))
|
||||
})??;
|
||||
let proof = block_on(self.sdk.prove(stdin, mode))?;
|
||||
let proving_time = start.elapsed();
|
||||
|
||||
let public_values = proof.public_values.to_vec();
|
||||
@@ -132,7 +77,7 @@ impl zkVM for EreSP1 {
|
||||
}
|
||||
|
||||
fn verify(&self, proof: &Proof) -> anyhow::Result<PublicValues> {
|
||||
info!("Verifying proof…");
|
||||
info!("Verifying proof...");
|
||||
|
||||
let proof_kind = proof.kind();
|
||||
|
||||
@@ -149,7 +94,7 @@ impl zkVM for EreSP1 {
|
||||
bail!(Error::InvalidProofKind(proof_kind, inner_proof_kind));
|
||||
}
|
||||
|
||||
self.prover()?.verify(&proof, &self.vk)?;
|
||||
self.sdk.verify(&proof)?;
|
||||
|
||||
let public_values_bytes = proof.public_values.as_slice().to_vec();
|
||||
|
||||
@@ -169,7 +114,7 @@ impl zkVMProgramDigest for EreSP1 {
|
||||
type ProgramDigest = SP1VerifyingKey;
|
||||
|
||||
fn program_digest(&self) -> anyhow::Result<Self::ProgramDigest> {
|
||||
Ok(self.vk.clone())
|
||||
Ok(self.sdk.verifying_key().clone())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,10 +129,16 @@ fn input_to_stdin(input: &Input) -> Result<SP1Stdin, Error> {
|
||||
Ok(stdin)
|
||||
}
|
||||
|
||||
fn panic_msg(err: Box<dyn std::any::Any + Send + 'static>) -> String {
|
||||
None.or_else(|| err.downcast_ref::<String>().cloned())
|
||||
.or_else(|| err.downcast_ref::<&'static str>().map(ToString::to_string))
|
||||
.unwrap_or_else(|| "unknown panic msg".to_string())
|
||||
fn block_on<T>(future: impl Future<Output = T>) -> T {
|
||||
match tokio::runtime::Handle::try_current() {
|
||||
Ok(handle) => tokio::task::block_in_place(|| handle.block_on(future)),
|
||||
Err(_) => {
|
||||
static FALLBACK_RT: OnceLock<tokio::runtime::Runtime> = OnceLock::new();
|
||||
FALLBACK_RT
|
||||
.get_or_init(|| tokio::runtime::Runtime::new().expect("Failed to create runtime"))
|
||||
.block_on(future)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -7,14 +7,8 @@ pub enum Error {
|
||||
#[error(transparent)]
|
||||
CommonError(#[from] CommonError),
|
||||
|
||||
#[error("Prover RwLock posioned, panic not catched properly")]
|
||||
RwLockPosioned,
|
||||
|
||||
#[error("Failed to setup ELF: {0}")]
|
||||
SetupElfFailed(String),
|
||||
|
||||
#[error("Failed to initialize cuda prover: {0}")]
|
||||
InitCudaProverFailed(String),
|
||||
Setup(#[source] anyhow::Error),
|
||||
|
||||
#[error("Deserialize proofs in Input failed: {0:?}")]
|
||||
DeserializeInputProofs(bincode::error::DecodeError),
|
||||
@@ -26,12 +20,15 @@ pub enum Error {
|
||||
#[error("SP1 execution failed: {0}")]
|
||||
Execute(#[source] anyhow::Error),
|
||||
|
||||
#[error("SP1 execution completed with non-success exit code: {0}")]
|
||||
ExecutionFailed(u32),
|
||||
|
||||
// Prove
|
||||
#[error("SP1 SDK proving failed: {0}")]
|
||||
Prove(#[source] anyhow::Error),
|
||||
|
||||
#[error("SP1 proving panicked: {0}")]
|
||||
Panic(String),
|
||||
#[error("Failed to extract exit code from proof")]
|
||||
ExitCodeExtractionFailed,
|
||||
|
||||
// Verify
|
||||
#[error("Invalid proof kind, expected: {0:?}, got: {1:?}")]
|
||||
@@ -40,3 +37,13 @@ pub enum Error {
|
||||
#[error("SP1 SDK verification failed: {0}")]
|
||||
Verify(#[source] SP1VerificationError),
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn setup(err: impl Into<anyhow::Error>) -> Self {
|
||||
Self::Setup(err.into())
|
||||
}
|
||||
|
||||
pub fn prove(err: impl Into<anyhow::Error>) -> Self {
|
||||
Self::Prove(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +1,57 @@
|
||||
use crate::zkvm::{Error, panic_msg};
|
||||
use crate::zkvm::Error;
|
||||
use ere_zkvm_interface::{
|
||||
CommonError, RemoteProverConfig,
|
||||
zkvm::{ProverResource, ProverResourceKind},
|
||||
};
|
||||
use sp1_cuda::CudaProvingKey;
|
||||
use sp1_hypercube::air::PublicValues;
|
||||
use sp1_p3_field::PrimeField32;
|
||||
use sp1_recursion_executor::RecursionPublicValues;
|
||||
use sp1_sdk::{
|
||||
CpuProver, NetworkProver, Prover as _, ProverClient, SP1ProofMode, SP1ProofWithPublicValues,
|
||||
SP1ProvingKey, SP1Stdin, SP1VerifyingKey,
|
||||
CpuProver, CudaProver, Elf, ExecutionReport, NetworkProver, ProveRequest, Prover as SP1Prover,
|
||||
ProverClient, ProvingKey as SP1ProvingKeyTrait, SP1Proof, SP1ProofMode,
|
||||
SP1ProofWithPublicValues, SP1ProvingKey as CpuProvingKey, SP1PublicValues, SP1Stdin,
|
||||
SP1VerifyingKey, StatusCode,
|
||||
};
|
||||
use std::{
|
||||
env,
|
||||
ops::Deref,
|
||||
panic::{self, AssertUnwindSafe},
|
||||
process::Command,
|
||||
};
|
||||
use tracing::error;
|
||||
use std::{borrow::Borrow, env, sync::Arc};
|
||||
|
||||
// https://github.com/succinctlabs/sp1/blob/v5.2.4/crates/cuda/src/lib.rs#L207C34-L207C78.
|
||||
const SP1_CUDA_IMAGE: &str = "public.ecr.aws/succinct-labs/sp1-gpu:8fd1ef7";
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum Prover {
|
||||
Cpu(CpuProver),
|
||||
Gpu(CudaProver),
|
||||
Network(NetworkProver),
|
||||
pub enum SP1Sdk {
|
||||
Cpu {
|
||||
prover: CpuProver,
|
||||
pk: CpuProvingKey,
|
||||
},
|
||||
Gpu {
|
||||
prover: CudaProver,
|
||||
pk: CudaProvingKey,
|
||||
},
|
||||
Network {
|
||||
prover: Box<NetworkProver>,
|
||||
pk: CpuProvingKey,
|
||||
},
|
||||
}
|
||||
|
||||
impl Default for Prover {
|
||||
fn default() -> Self {
|
||||
Self::new(&ProverResource::Cpu).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Prover {
|
||||
pub fn new(resource: &ProverResource) -> Result<Self, Error> {
|
||||
impl SP1Sdk {
|
||||
pub async fn new(elf: Vec<u8>, resource: &ProverResource) -> Result<Self, Error> {
|
||||
let elf = Elf::Dynamic(Arc::from(elf));
|
||||
Ok(match resource {
|
||||
ProverResource::Cpu => Self::Cpu(ProverClient::builder().cpu().build()),
|
||||
ProverResource::Gpu => Self::Gpu(CudaProver::new()?),
|
||||
ProverResource::Network(config) => Self::Network(build_network_prover(config)?),
|
||||
ProverResource::Cpu => {
|
||||
let prover = ProverClient::builder().cpu().build().await;
|
||||
let pk = prover.setup(elf).await.map_err(Error::setup)?;
|
||||
Self::Cpu { prover, pk }
|
||||
}
|
||||
ProverResource::Gpu => {
|
||||
let prover = ProverClient::builder().cuda().build().await;
|
||||
let pk = prover.setup(elf).await.map_err(Error::setup)?;
|
||||
Self::Gpu { prover, pk }
|
||||
}
|
||||
ProverResource::Network(config) => {
|
||||
let prover = build_network_prover(config).await?;
|
||||
let pk = prover.setup(elf).await.map_err(Error::setup)?;
|
||||
Self::Network {
|
||||
prover: Box::new(prover),
|
||||
pk,
|
||||
}
|
||||
}
|
||||
_ => Err(CommonError::unsupported_prover_resource_kind(
|
||||
resource.kind(),
|
||||
[
|
||||
@@ -48,135 +63,73 @@ impl Prover {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn setup(&self, elf: &[u8]) -> Result<(SP1ProvingKey, SP1VerifyingKey), Error> {
|
||||
panic::catch_unwind(AssertUnwindSafe(|| match self {
|
||||
Self::Cpu(cpu_prover) => cpu_prover.setup(elf),
|
||||
Self::Gpu(cuda_prover) => cuda_prover.setup(elf),
|
||||
Self::Network(network_prover) => network_prover.setup(elf),
|
||||
}))
|
||||
.map_err(|err| Error::SetupElfFailed(panic_msg(err)))
|
||||
}
|
||||
|
||||
pub fn execute(
|
||||
&self,
|
||||
elf: &[u8],
|
||||
input: &SP1Stdin,
|
||||
) -> Result<(sp1_sdk::SP1PublicValues, sp1_sdk::ExecutionReport), Error> {
|
||||
pub fn verifying_key(&self) -> &SP1VerifyingKey {
|
||||
match self {
|
||||
Self::Cpu(cpu_prover) => cpu_prover.execute(elf, input).run(),
|
||||
Self::Gpu(cuda_prover) => cuda_prover.execute(elf, input).run(),
|
||||
Self::Network(network_prover) => network_prover.execute(elf, input).run(),
|
||||
Self::Cpu { pk, .. } => pk.verifying_key(),
|
||||
Self::Gpu { pk, .. } => pk.verifying_key(),
|
||||
Self::Network { pk, .. } => pk.verifying_key(),
|
||||
}
|
||||
.map_err(Error::Execute)
|
||||
}
|
||||
|
||||
pub fn prove(
|
||||
pub async fn execute(
|
||||
&self,
|
||||
pk: &SP1ProvingKey,
|
||||
input: &SP1Stdin,
|
||||
input: SP1Stdin,
|
||||
) -> Result<(SP1PublicValues, ExecutionReport), Error> {
|
||||
let (public_values, exec_report) = match self {
|
||||
Self::Cpu { prover, pk } => prover.execute(pk.elf().clone(), input).await,
|
||||
Self::Gpu { prover, pk } => prover.execute(pk.elf().clone(), input).await,
|
||||
Self::Network { prover, pk } => prover.execute(pk.elf().clone(), input).await,
|
||||
}
|
||||
.map_err(|e| Error::Execute(e.into()))?;
|
||||
|
||||
let exit_code = exec_report.exit_code as u32;
|
||||
if exit_code != StatusCode::SUCCESS.as_u32() {
|
||||
return Err(Error::ExecutionFailed(exit_code));
|
||||
}
|
||||
|
||||
Ok((public_values, exec_report))
|
||||
}
|
||||
|
||||
pub async fn prove(
|
||||
&self,
|
||||
input: SP1Stdin,
|
||||
mode: SP1ProofMode,
|
||||
) -> Result<SP1ProofWithPublicValues, Error> {
|
||||
match self {
|
||||
Self::Cpu(cpu_prover) => cpu_prover.prove(pk, input).mode(mode).run(),
|
||||
Self::Gpu(cuda_prover) => cuda_prover.prove(pk, input).mode(mode).run(),
|
||||
Self::Network(network_prover) => network_prover.prove(pk, input).mode(mode).run(),
|
||||
let proof = match self {
|
||||
Self::Cpu { prover, pk } => {
|
||||
let req = prover.prove(pk, input).mode(mode);
|
||||
req.await.map_err(Error::prove)
|
||||
}
|
||||
Self::Gpu { prover, pk } => {
|
||||
let req = prover.prove(pk, input).mode(mode);
|
||||
req.await.map_err(Error::prove)
|
||||
}
|
||||
Self::Network { prover, pk } => {
|
||||
let req = prover.prove(pk, input).mode(mode);
|
||||
req.await.map_err(Error::prove)
|
||||
}
|
||||
}?;
|
||||
|
||||
let exit_code = extract_exit_code(&proof)?;
|
||||
if exit_code != StatusCode::SUCCESS.as_u32() {
|
||||
return Err(Error::ExecutionFailed(exit_code));
|
||||
}
|
||||
.map_err(Error::Prove)
|
||||
|
||||
Ok(proof)
|
||||
}
|
||||
|
||||
pub fn verify(
|
||||
&self,
|
||||
proof: &SP1ProofWithPublicValues,
|
||||
vk: &SP1VerifyingKey,
|
||||
) -> Result<(), Error> {
|
||||
pub fn verify(&self, proof: &SP1ProofWithPublicValues) -> Result<(), Error> {
|
||||
let vk = self.verifying_key();
|
||||
match self {
|
||||
Self::Cpu(cpu_prover) => cpu_prover.verify(proof, vk),
|
||||
Self::Gpu(cuda_prover) => cuda_prover.verify(proof, vk),
|
||||
Self::Network(network_prover) => network_prover.verify(proof, vk),
|
||||
Self::Cpu { prover, .. } => prover.verify(proof, vk, Some(StatusCode::SUCCESS)),
|
||||
Self::Gpu { prover, .. } => prover.verify(proof, vk, Some(StatusCode::SUCCESS)),
|
||||
Self::Network { prover, .. } => prover.verify(proof, vk, Some(StatusCode::SUCCESS)),
|
||||
}
|
||||
.map_err(Error::Verify)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CudaProver {
|
||||
container_name: String,
|
||||
prover: sp1_sdk::CudaProver,
|
||||
}
|
||||
|
||||
impl Deref for CudaProver {
|
||||
type Target = sp1_sdk::CudaProver;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.prover
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for CudaProver {
|
||||
fn drop(&mut self) {
|
||||
let mut cmd = Command::new("docker");
|
||||
cmd.args(["container", "rm", "--force", self.container_name.as_ref()]);
|
||||
if let Err(err) = cmd
|
||||
.output()
|
||||
.map_err(|err| CommonError::command(&cmd, err))
|
||||
.and_then(|output| {
|
||||
(!output.status.success()).then_some(()).ok_or_else(|| {
|
||||
CommonError::command_exit_non_zero(&cmd, output.status, Some(&output))
|
||||
})
|
||||
})
|
||||
{
|
||||
error!(
|
||||
"Failed to remove docker container {}: {err}",
|
||||
self.container_name
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CudaProver {
|
||||
fn new() -> Result<Self, Error> {
|
||||
// Ported from https://github.com/succinctlabs/sp1/blob/v5.2.4/crates/cuda/src/lib.rs#L199.
|
||||
|
||||
let container_name = "sp1-gpu".to_string();
|
||||
let image_name = env::var("SP1_GPU_IMAGE").unwrap_or_else(|_| SP1_CUDA_IMAGE.to_string());
|
||||
let rust_log = env::var("RUST_LOG").unwrap_or_else(|_| "none".to_string());
|
||||
let gpus = env::var("ERE_GPU_DEVICES").unwrap_or_else(|_| "all".to_string());
|
||||
|
||||
let mut cmd = Command::new("docker");
|
||||
cmd.args([
|
||||
"run",
|
||||
"--rm",
|
||||
"--env",
|
||||
&format!("RUST_LOG={rust_log}"),
|
||||
"--publish",
|
||||
"3000:3000",
|
||||
"--gpus",
|
||||
&gpus,
|
||||
"--name",
|
||||
&container_name,
|
||||
&image_name,
|
||||
]);
|
||||
|
||||
let host = if let Ok(network) = env::var("ERE_DOCKER_NETWORK") {
|
||||
cmd.args(["--network", network.as_str()]);
|
||||
container_name.as_str()
|
||||
} else {
|
||||
"127.0.0.1"
|
||||
};
|
||||
let endpoint = format!("http://{host}:3000/twirp/");
|
||||
cmd.spawn().map_err(|err| CommonError::command(&cmd, err))?;
|
||||
|
||||
let prover =
|
||||
panic::catch_unwind(|| ProverClient::builder().cuda().server(&endpoint).build())
|
||||
.map_err(|err| Error::InitCudaProverFailed(panic_msg(err)))?;
|
||||
|
||||
Ok(Self {
|
||||
container_name,
|
||||
prover,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn build_network_prover(config: &RemoteProverConfig) -> Result<NetworkProver, Error> {
|
||||
async fn build_network_prover(config: &RemoteProverConfig) -> Result<NetworkProver, Error> {
|
||||
let mut builder = ProverClient::builder().network();
|
||||
// Check if we have a private key in the config or environment
|
||||
if let Some(api_key) = &config.api_key {
|
||||
@@ -193,5 +146,32 @@ fn build_network_prover(config: &RemoteProverConfig) -> Result<NetworkProver, Er
|
||||
builder = builder.rpc_url(&rpc_url);
|
||||
}
|
||||
// Otherwise SP1 SDK will use its default RPC URL
|
||||
Ok(builder.build())
|
||||
Ok(builder.build().await)
|
||||
}
|
||||
|
||||
/// Extracts the exit code from an public values of proof.
|
||||
///
|
||||
/// The `exit_code` field is extracted from the public values struct of proof,
|
||||
/// mirroring the approach used in `verify_proof` of `sp1_sdk`.
|
||||
fn extract_exit_code(proof: &SP1ProofWithPublicValues) -> Result<u32, Error> {
|
||||
match &proof.proof {
|
||||
SP1Proof::Core(shard_proofs) => shard_proofs.last().map(|proof| {
|
||||
let pv: &PublicValues<[_; 4], [_; 3], [_; 4], _> =
|
||||
proof.public_values.as_slice().borrow();
|
||||
pv.exit_code.as_canonical_u32()
|
||||
}),
|
||||
SP1Proof::Compressed(proof) => {
|
||||
let pv: &RecursionPublicValues<_> = proof.proof.public_values.as_slice().borrow();
|
||||
Some(pv.exit_code.as_canonical_u32())
|
||||
}
|
||||
SP1Proof::Plonk(proof) => proof
|
||||
.public_inputs
|
||||
.get(2)
|
||||
.and_then(|value| value.parse::<u32>().ok()),
|
||||
SP1Proof::Groth16(proof) => proof
|
||||
.public_inputs
|
||||
.get(2)
|
||||
.and_then(|value| value.parse::<u32>().ok()),
|
||||
}
|
||||
.ok_or(Error::ExitCodeExtractionFailed)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user