Skip to content

Commit

Permalink
feat(core,host): initial aggregation API
Browse files Browse the repository at this point in the history
  • Loading branch information
petarvujovic98 committed Sep 17, 2024
1 parent 8e86975 commit 83d538b
Show file tree
Hide file tree
Showing 7 changed files with 498 additions and 12 deletions.
84 changes: 77 additions & 7 deletions core/src/interfaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,14 +442,84 @@ impl TryFrom<ProofRequestOpt> for ProofRequest {
}
}

#[serde_as]
#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Default, Clone, Serialize, Deserialize, Debug, ToSchema)]
#[serde(default)]
/// A request for proof aggregation of multiple proofs.
pub struct AggregationRequest {
/// All the proofs to verify
pub proofs: Vec<Proof>,
/// The block numbers and l1 inclusion block numbers for the blocks to aggregate proofs for.
pub block_numbers: Vec<(u64, u64)>,
/// The network to generate the proof for.
pub network: Option<String>,
/// The L1 network to generate the proof for.
pub l1_network: Option<String>,
// Graffiti.
pub graffiti: Option<String>,
/// The protocol instance data.
pub prover: Option<String>,
/// The proof type.
pub proof_type: ProofType,
/// Additional prover params.
pub prover_args: HashMap<String, Value>,
pub proof_type: Option<String>,
/// Blob proof type.
pub blob_proof_type: Option<String>,
#[serde(flatten)]
/// Any additional prover params in JSON format.
pub prover_args: ProverSpecificOpts,
}

impl AggregationRequest {
/// Merge proof request options into aggregation request options.
pub fn merge(&mut self, opts: &ProofRequestOpt) -> RaikoResult<()> {
let this = serde_json::to_value(&self)?;
let mut opts = serde_json::to_value(opts)?;
merge(&mut opts, &this);
*self = serde_json::from_value(opts)?;
Ok(())
}
}

impl From<AggregationRequest> for Vec<ProofRequestOpt> {
fn from(value: AggregationRequest) -> Self {
value
.block_numbers
.iter()
.map(
|&(block_number, l1_inclusion_block_number)| ProofRequestOpt {
block_number: Some(block_number),
l1_inclusion_block_number: Some(l1_inclusion_block_number),
network: value.network.clone(),
l1_network: value.l1_network.clone(),
graffiti: value.graffiti.clone(),
prover: value.prover.clone(),
proof_type: value.proof_type.clone(),
blob_proof_type: value.blob_proof_type.clone(),
prover_args: value.prover_args.clone(),
},
)
.collect()
}
}

impl From<ProofRequestOpt> for AggregationRequest {
fn from(value: ProofRequestOpt) -> Self {
let block_numbers = if let Some(block_number) = value.block_number {
vec![(
block_number,
value
.l1_inclusion_block_number
.unwrap_or_else(|| block_number - 1),
)]
} else {
vec![]
};

Self {
block_numbers,
network: value.network,
l1_network: value.l1_network,
graffiti: value.graffiti,
prover: value.prover,
proof_type: value.proof_type,
blob_proof_type: value.blob_proof_type,
prover_args: value.prover_args,
}
}
}
1 change: 1 addition & 0 deletions host/src/server/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use crate::ProverState;

pub mod v1;
pub mod v2;
pub mod v3;

pub fn create_router(concurrency_limit: usize, jwt_secret: Option<&str>) -> Router<ProverState> {
let cors = CorsLayer::new()
Expand Down
2 changes: 1 addition & 1 deletion host/src/server/api/v2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
ProverState,
};

mod proof;
pub mod proof;

#[derive(OpenApi)]
#[openapi(
Expand Down
8 changes: 4 additions & 4 deletions host/src/server/api/v2/proof/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ use crate::{
Message, ProverState,
};

mod cancel;
mod list;
mod prune;
mod report;
pub mod cancel;
pub mod list;
pub mod prune;
pub mod report;

#[utoipa::path(post, path = "/proof",
tag = "Proving",
Expand Down
166 changes: 166 additions & 0 deletions host/src/server/api/v3/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
use axum::{response::IntoResponse, Json, Router};
use raiko_lib::prover::Proof;
use raiko_tasks::TaskStatus;
use serde::{Deserialize, Serialize};
use utoipa::{OpenApi, ToSchema};
use utoipa_scalar::{Scalar, Servable};
use utoipa_swagger_ui::SwaggerUi;

use crate::{
server::api::v1::{self, GuestOutputDoc},
ProverState,
};

mod proof;

#[derive(OpenApi)]
#[openapi(
info(
title = "Raiko Proverd Server API",
version = "3.0",
description = "Raiko Proverd Server API",
contact(
name = "API Support",
url = "https://community.taiko.xyz",
email = "[email protected]",
),
license(
name = "MIT",
url = "https://github.com/taikoxyz/raiko/blob/main/LICENSE"
),
),
components(
schemas(
raiko_core::interfaces::ProofRequestOpt,
raiko_core::interfaces::ProverSpecificOpts,
crate::interfaces::HostError,
GuestOutputDoc,
ProofResponse,
TaskStatus,
CancelStatus,
PruneStatus,
Proof,
Status,
)
),
tags(
(name = "Proving", description = "Routes that handle proving requests"),
(name = "Health", description = "Routes that report the server health status"),
(name = "Metrics", description = "Routes that give detailed insight into the server")
)
)]
/// The root API struct which is generated from the `OpenApi` derive macro.
pub struct Docs;

#[derive(Debug, Deserialize, Serialize, ToSchema)]
#[serde(untagged)]
pub enum ProofResponse {
Status {
/// The status of the submitted task.
status: TaskStatus,
},
Proof {
/// The proof.
proof: Proof,
},
}

#[derive(Debug, Deserialize, Serialize, ToSchema)]
#[serde(tag = "status", rename_all = "lowercase")]
pub enum Status {
Ok { data: ProofResponse },
Error { error: String, message: String },
}

impl From<Vec<u8>> for Status {
fn from(proof: Vec<u8>) -> Self {
Self::Ok {
data: ProofResponse::Proof {
proof: serde_json::from_slice(&proof).unwrap_or_default(),
},
}
}
}

impl From<Proof> for Status {
fn from(proof: Proof) -> Self {
Self::Ok {
data: ProofResponse::Proof { proof },
}
}
}

impl From<TaskStatus> for Status {
fn from(status: TaskStatus) -> Self {
Self::Ok {
data: ProofResponse::Status { status },
}
}
}

impl IntoResponse for Status {
fn into_response(self) -> axum::response::Response {
Json(serde_json::to_value(self).unwrap()).into_response()
}
}

#[derive(Debug, Deserialize, Serialize, ToSchema)]
#[serde(tag = "status", rename_all = "lowercase")]
/// Status of cancellation request.
/// Can be `ok` for a successful cancellation or `error` with message and error type for errors.
pub enum CancelStatus {
/// Cancellation was successful.
Ok,
/// Cancellation failed.
Error { error: String, message: String },
}

impl IntoResponse for CancelStatus {
fn into_response(self) -> axum::response::Response {
Json(serde_json::to_value(self).unwrap()).into_response()
}
}

#[derive(Debug, Serialize, ToSchema, Deserialize)]
#[serde(tag = "status", rename_all = "lowercase")]
/// Status of prune request.
/// Can be `ok` for a successful prune or `error` with message and error type for errors.
pub enum PruneStatus {
/// Prune was successful.
Ok,
/// Prune failed.
Error { error: String, message: String },
}

impl IntoResponse for PruneStatus {
fn into_response(self) -> axum::response::Response {
Json(serde_json::to_value(self).unwrap()).into_response()
}
}

#[must_use]
pub fn create_docs() -> utoipa::openapi::OpenApi {
[
v1::health::create_docs(),
v1::metrics::create_docs(),
proof::create_docs(),
]
.into_iter()
.fold(Docs::openapi(), |mut doc, sub_doc| {
doc.merge(sub_doc);
doc
})
}

pub fn create_router() -> Router<ProverState> {
let docs = create_docs();

Router::new()
// Only add the concurrency limit to the proof route. We want to still be able to call
// healthchecks and metrics to have insight into the system.
.nest("/proof", proof::create_router())
.nest("/health", v1::health::create_router())
.nest("/metrics", v1::metrics::create_router())
.merge(SwaggerUi::new("/swagger-ui").url("/api-docs/openapi.json", docs.clone()))
.merge(Scalar::with_url("/scalar", docs))
}
77 changes: 77 additions & 0 deletions host/src/server/api/v3/proof/cancel.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use axum::{debug_handler, extract::State, routing::post, Json, Router};
use raiko_core::{
interfaces::{AggregationRequest, ProofRequest, ProofRequestOpt},
provider::get_task_data,
};
use raiko_tasks::{TaskDescriptor, TaskManager, TaskStatus};
use serde_json::Value;
use utoipa::OpenApi;

use crate::{interfaces::HostResult, server::api::v2::CancelStatus, Message, ProverState};

#[utoipa::path(post, path = "/proof/cancel",
tag = "Proving",
request_body = ProofRequestOpt,
responses (
(status = 200, description = "Successfully cancelled proof task", body = CancelStatus)
)
)]
#[debug_handler(state = ProverState)]
/// Cancel a proof task with requested config.
///
/// Accepts a proof request and cancels a proving task with the specified guest prover.
/// The guest provers currently available are:
/// - native - constructs a block and checks for equality
/// - sgx - uses the sgx environment to construct a block and produce proof of execution
/// - sp1 - uses the sp1 prover
/// - risc0 - uses the risc0 prover
async fn cancel_handler(
State(prover_state): State<ProverState>,
Json(aggregation_request): Json<AggregationRequest>,
) -> HostResult<CancelStatus> {
// Override the existing proof request config from the config file and command line
// options with the request from the client.
aggregation_request.merge(&prover_state.request_config());

let proof_request_opts: Vec<ProofRequestOpt> = aggregation_request.into();

for opt in proof_request_opts {
let proof_request = ProofRequest::try_from(opt)?;

let (chain_id, block_hash) = get_task_data(
&proof_request.network,
proof_request.block_number,
&prover_state.chain_specs,
)
.await?;

let key = TaskDescriptor::from((
chain_id,
block_hash,
proof_request.proof_type,
proof_request.prover.clone().to_string(),
));

prover_state.task_channel.try_send(Message::from(&key))?;

let mut manager = prover_state.task_manager();

manager
.update_task_progress(key, TaskStatus::Cancelled, None)
.await?;
}

Ok(CancelStatus::Ok)
}

#[derive(OpenApi)]
#[openapi(paths(cancel_handler))]
struct Docs;

pub fn create_docs() -> utoipa::openapi::OpenApi {
Docs::openapi()
}

pub fn create_router() -> Router<ProverState> {
Router::new().route("/", post(cancel_handler))
}
Loading

0 comments on commit 83d538b

Please sign in to comment.