Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core,host): initial aggregation API #375

Open
wants to merge 30 commits into
base: proof-aggregation
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
83d538b
feat(core,host): initial aggregation API
petarvujovic98 Sep 17, 2024
df758fa
fix(core,host,sgx): fix compiler and clippy errors
petarvujovic98 Sep 17, 2024
ccb2fb3
Merge branch 'proof-aggregation' into proof-aggregation-api
petarvujovic98 Sep 17, 2024
9b829db
fix(core): remove double member
petarvujovic98 Sep 17, 2024
2ccac77
fix(sp1): fix dependency naming
petarvujovic98 Sep 17, 2024
247ffee
refactor(risc0): clean up aggregation file
petarvujovic98 Sep 17, 2024
2e6f7d8
fix(sp1): enable verification for proof aggregation
petarvujovic98 Sep 17, 2024
29e6fb1
feat(host): migrate to v3 API
petarvujovic98 Sep 17, 2024
a887cc6
feat(sp1): run cargo fmt
petarvujovic98 Sep 17, 2024
c2b0db5
feat(raiko): traversal to find inclusion block if none inclusion numb…
smtmfft Sep 17, 2024
5d29f78
feat(core): make `l1_inclusion_block_number` optional
petarvujovic98 Sep 18, 2024
8a3947b
fixproof req input into prove state manager
smtmfft Sep 19, 2024
7276c7b
feat(core,host,lib,tasks): add aggregation tasks and API
petarvujovic98 Sep 19, 2024
83df208
fix(core): fix typo
petarvujovic98 Sep 19, 2024
f4f818d
fix(raiko): refine error return (#378)
smtmfft Sep 20, 2024
00e2374
chore(main): release 1.2.0 (#370)
taiko-kitty Sep 20, 2024
728cb3a
Merge remote-tracking branch 'origin/main' into proof-aggregation-api
smtmfft Sep 20, 2024
16e4abc
fix v3 error return
smtmfft Sep 20, 2024
fa6fe88
feat(sp1): implement aggregate function
petarvujovic98 Sep 20, 2024
1aaec18
fix sgx aggregation for back compatibility
smtmfft Sep 23, 2024
789a599
fix(lib): fix typo
petarvujovic98 Sep 23, 2024
0358a26
fix risc0 aggregation
smtmfft Sep 24, 2024
a033011
Merge branch 'proof-aggregation-api' of https://github.com/taikoxyz/r…
smtmfft Sep 24, 2024
9da8834
fix(host,sp1): handle statuses
petarvujovic98 Sep 26, 2024
bdcb5f3
enable sp1 aggregation
smtmfft Sep 28, 2024
334d93f
feat(host): error out on empty proof array request
petarvujovic98 Sep 30, 2024
e1d79ff
fix(host): return proper status report
petarvujovic98 Sep 30, 2024
e34567f
feat(host,tasks): adding details to error statuses
petarvujovic98 Sep 30, 2024
d14774d
fix sp1 aggregation
smtmfft Oct 2, 2024
62c29a5
update prove-block script
smtmfft Oct 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)>,
petarvujovic98 marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also added this in the design document, but doesn't it make more sense for this to just take a list of proofs?

https://www.notion.so/Proof-aggregation-API-dbd4fcec46d049b78132072555386a40?d=6052f3ea6244452e98add34ec292cd1a&pvs=4#05a93b35e0e941c7b94ef8bed5be6112

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cp the notion reply and let's discuss it here.

Yes, this is what I called streaming style, raiko generating proofs at the same pace as before, but report aggregated one if it is asked for aggregation proof. better for runtime, less burst resource requirement, but bit complex-er status management.
We talked that with client before, they thought the list is easier for initial test, less effort in dev, so we decided to fast impl this to let aggregation go devnet quickly. But I think that streaming style will eventually replace it.

I think the streaming style is what you want, but perhaps I mis-understand your optimistic mode, correct me if so.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Brechtpd It does make more sense to keep it as a separate route to only aggregate existing proofs, but as @smtmfft and I talked about, for the initial version it is easier for the client to test it with a similar request style which proves all the requested blocks.
I will create a aggregate-only endpoint to handle the optimal scenario, but for now just allowing a quicker path to integration unless we want to go with the more optimal approach right away.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there are other considerations than of course okay with me with the current approach, just trying to avoid any additional work if going from the current block indices to the proofs one would be significantly different and so some code being written now would be deprecated quite quickly.

/// 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>,
smtmfft marked this conversation as resolved.
Show resolved Hide resolved
#[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,
}
}
}
2 changes: 1 addition & 1 deletion core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,8 +455,8 @@ mod tests {
.unwrap();

let proof_request = ProofRequest {
l1_inclusion_block_number: 0,
block_number,
l1_inclusion_block_number: 0,
network,
graffiti: B256::ZERO,
prover: Address::ZERO,
Expand Down
9 changes: 6 additions & 3 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 All @@ -37,11 +38,13 @@ pub fn create_router(concurrency_limit: usize, jwt_secret: Option<&str>) -> Rout

let v1_api = v1::create_router(concurrency_limit);
let v2_api = v2::create_router();
let v3_api = v3::create_router();

let router = Router::new()
.nest("/v1", v1_api)
.nest("/v2", v2_api.clone())
.merge(v2_api)
.nest("/v2", v2_api)
.nest("/v3", v3_api.clone())
.merge(v3_api)
.layer(middleware)
.layer(middleware::from_fn(check_max_body_size))
.layer(trace)
Expand All @@ -58,7 +61,7 @@ pub fn create_router(concurrency_limit: usize, jwt_secret: Option<&str>) -> Rout
}

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

async fn check_max_body_size(req: Request, next: Next) -> Response {
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 = "info@taiko.xyz",
),
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 },
petarvujovic98 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

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))
}
Loading
Loading