pub(crate) mod execute;
pub(crate) mod prove;
pub(crate) mod recurser;
pub(crate) mod setup;
pub(crate) mod upload;
pub(crate) mod wrap;
use crate::{Result, SdkError};
use std::time::Duration;
use zisk_common::io::StreamRead;
use zisk_common::{ProgramVK, Proof, ProofKind, PublicValues};
use zisk_coordinator_api::dto::DomainInputKind;
use zisk_coordinator_client::CoordinatorClient;
use zisk_prover_backend::GuestProgram;
use crate::aggregate_proofs::{AggregateProofsRequest, AggregationInput};
use crate::lifecycle::{SetupTarget, UploadTarget};
use crate::recurser::Recurser;
use crate::{
execute::{ExecuteRequest, ExecuteResult},
hints::HintsSource,
input_source::InputSource,
job_handle::{JobHandle, SubscriberList},
prove::ProveRequest,
remote::setup::SetupByIdRequest,
setup::{SetupRequest, SetupResult},
upload::{UploadRequest, UploadResult},
wrap::WrapRequest,
Client, ExecutorKind,
};
const DEFAULT_CONNECT_TIMEOUT: Duration = Duration::from_secs(10);
const DEFAULT_REQUEST_TIMEOUT: Duration = Duration::from_secs(300);
pub struct RemoteClientBuilder<Out = RemoteClient> {
url: String,
connect_timeout: Duration,
request_timeout: Duration,
_out: std::marker::PhantomData<fn() -> Out>,
}
impl<Out> RemoteClientBuilder<Out> {
pub(crate) fn new(url: impl Into<String>) -> Self {
Self {
url: url.into(),
connect_timeout: DEFAULT_CONNECT_TIMEOUT,
request_timeout: DEFAULT_REQUEST_TIMEOUT,
_out: std::marker::PhantomData,
}
}
#[must_use]
pub fn connect_timeout(mut self, d: Duration) -> Self {
self.connect_timeout = d;
self
}
#[must_use]
pub fn request_timeout(mut self, d: Duration) -> Self {
self.request_timeout = d;
self
}
}
impl<Out: From<RemoteClient>> RemoteClientBuilder<Out> {
fn connect(self) -> Result<RemoteClient> {
crate::client::ensure_single_instance();
let gw = CoordinatorClient::connect(self.url, self.connect_timeout, self.request_timeout)
.map_err(SdkError::backend)?;
Ok(RemoteClient { gw })
}
pub fn build(self) -> Result<Out> {
Ok(self.connect()?.into())
}
pub fn build_ext(self) -> Result<RemoteClientExt> {
Ok(RemoteClientExt { inner: self.connect()? })
}
}
#[derive(Clone)]
pub struct RemoteClient {
pub(crate) gw: CoordinatorClient,
}
impl Client for RemoteClient {
fn run_upload(&self, program: &GuestProgram) -> Result<UploadResult> {
self.do_upload(program)
}
fn run_setup(
&self,
program: &GuestProgram,
with_hints: bool,
emulator_only: bool,
timeout: Option<Duration>,
subs: SubscriberList,
) -> Result<JobHandle<SetupResult>> {
self.do_setup(program, with_hints, emulator_only, timeout, subs)
}
fn run_prove(
&self,
program: &GuestProgram,
stdin: InputSource,
hints: Option<HintsSource>,
executor: ExecutorKind,
proof_kind: ProofKind,
timeout: Option<Duration>,
subs: SubscriberList,
) -> Result<JobHandle<crate::prove::ProveResult>> {
self.do_prove(program, stdin, hints, executor, proof_kind, timeout, subs)
}
fn run_execute(
&self,
program: &GuestProgram,
stdin: InputSource,
hints: Option<HintsSource>,
executor: ExecutorKind,
timeout: Option<Duration>,
subs: SubscriberList,
) -> Result<JobHandle<ExecuteResult>> {
self.do_execute(program, stdin, hints, executor, timeout, subs)
}
fn run_wrap(
&self,
proof: &Proof,
proof_kind: ProofKind,
_override_publics: Option<PublicValues>,
_override_program_vk: Option<ProgramVK>,
timeout: Option<Duration>,
subs: SubscriberList,
) -> Result<JobHandle<crate::prove::ProveResult>> {
self.do_wrap(proof, proof_kind, timeout, subs)
}
fn run_upload_aggregation_program(&self, agg: &Recurser) -> Result<UploadResult> {
self.do_upload_aggregation_program(agg)
}
fn run_setup_aggregation_program(
&self,
agg: &Recurser,
timeout: Option<Duration>,
subs: SubscriberList,
) -> Result<JobHandle<SetupResult>> {
self.do_setup_aggregation_program(agg, timeout, subs)
}
fn run_aggregate_proofs(
&self,
agg: &Recurser,
proof_a: &Proof,
proof_b: &Proof,
free_a: &[u64],
free_b: &[u64],
root_c_recurser_agg: Option<[u64; 4]>,
timeout: Option<Duration>,
subs: SubscriberList,
) -> Result<JobHandle<crate::prove::ProveResult>> {
self.do_aggregate_proofs(
agg,
proof_a,
proof_b,
free_a,
free_b,
root_c_recurser_agg,
timeout,
subs,
)
}
}
impl RemoteClient {
#[must_use]
pub fn prove<'a>(
&'a self,
program: &'a GuestProgram,
stdin: impl Into<InputSource>,
) -> ProveRequest<'a, Self> {
ProveRequest::new(self, program, stdin, ExecutorKind::default())
}
#[must_use]
pub fn execute<'a>(
&'a self,
program: &'a GuestProgram,
stdin: impl Into<InputSource>,
) -> ExecuteRequest<'a, Self> {
ExecuteRequest::new(self, program, stdin, ExecutorKind::default())
}
#[must_use]
pub fn setup<'a, T: Into<SetupTarget<'a>>>(&'a self, target: T) -> SetupRequest<'a, Self> {
SetupRequest::new(self, target.into())
}
#[must_use]
pub fn setup_by_id(&self, hash_id: impl Into<String>) -> SetupByIdRequest<'_> {
SetupByIdRequest::new(self, hash_id.into())
}
#[must_use]
pub fn upload<'a, T: Into<UploadTarget<'a>>>(&'a self, target: T) -> UploadRequest<'a, Self> {
UploadRequest::new(self, target.into())
}
#[must_use]
pub fn wrap_proof<'a>(
&'a self,
proof: &'a Proof,
proof_kind: ProofKind,
) -> WrapRequest<'a, Self> {
WrapRequest::new(self, proof, proof_kind)
}
#[must_use]
pub fn aggregate_proofs<'a>(
&'a self,
agg: &'a Recurser,
input_a: impl Into<AggregationInput<'a>>,
input_b: impl Into<AggregationInput<'a>>,
) -> AggregateProofsRequest<'a, Self> {
AggregateProofsRequest::new(self, agg, input_a.into(), input_b.into())
}
}
#[derive(Clone)]
pub struct RemoteClientExt {
inner: RemoteClient,
}
impl std::ops::Deref for RemoteClientExt {
type Target = RemoteClient;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl RemoteClientExt {
#[must_use]
pub fn prove<'a>(
&'a self,
program: &'a GuestProgram,
stdin: impl Into<InputSource>,
) -> crate::prove::ProveRequestExt<'a> {
crate::prove::ProveRequestExt::new(&self.inner, program, stdin)
}
#[must_use]
pub fn execute<'a>(
&'a self,
program: &'a GuestProgram,
stdin: impl Into<InputSource>,
) -> crate::execute::ExecuteRequestExt<'a> {
crate::execute::ExecuteRequestExt::new(&self.inner, program, stdin)
}
}
pub(crate) fn stdin_to_input_kind(
stdin: InputSource,
) -> Result<(DomainInputKind, Option<crate::input_stream::ZiskStream>)> {
match stdin {
InputSource::Stream(stream) => {
Ok((DomainInputKind::StreamUri(stream.uri().to_string()), Some(stream)))
}
InputSource::Stdin(s) => Ok((
DomainInputKind::try_inline(s.into_inner().read_data()).map_err(SdkError::backend)?,
None,
)),
}
}
pub(crate) fn hints_to_input_kind(
hints: Option<HintsSource>,
) -> Result<(Option<DomainInputKind>, Option<crate::input_stream::ZiskStream>)> {
let hints = match hints {
Some(h) => h,
None => return Ok((None, None)),
};
match hints {
HintsSource::Stream(stream) => {
Ok((Some(DomainInputKind::StreamUri(stream.uri().to_string())), Some(*stream)))
}
HintsSource::Hints(h) => {
let mut source = h.into_inner();
source.open().map_err(SdkError::backend)?;
let mut data = Vec::new();
while let Some(chunk) = source.next().map_err(SdkError::backend)? {
data.extend(chunk);
}
source.close().map_err(SdkError::backend)?;
Ok((Some(DomainInputKind::try_inline(data).map_err(SdkError::backend)?), None))
}
}
}