Skip to content

Commit

Permalink
add SharpSdk scaffolding (#100)
Browse files Browse the repository at this point in the history
  • Loading branch information
tcoratger authored Nov 15, 2024
1 parent b514a6f commit c547876
Show file tree
Hide file tree
Showing 10 changed files with 588 additions and 103 deletions.
341 changes: 238 additions & 103 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,5 @@ proptest = "1.0"
arbitrary = "1.3"
rand = "0.8.5"
thiserror = "1.0"
url = "2.5"
reqwest = { version = "0.12", features = ["multipart"] }
2 changes: 2 additions & 0 deletions crates/exex/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ once_cell = { workspace = true }
tokio = { workspace = true }
futures = { workspace = true }
thiserror = { workspace = true }
url = { workspace = true }
reqwest = { workspace = true }

[dev-dependencies]
reth-exex-test-utils = { workspace = true }
Expand Down
189 changes: 189 additions & 0 deletions crates/exex/src/atlantic/endpoints.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
use super::error::SharpSdkError;
use url::Url;

/// Proof and trace generation endpoints.
#[derive(Debug, Clone)]
pub enum ProofTraceEndpoints {
/// Submit a Atlantic proof generation query.
ProofGeneration,
/// Submit a Atlantic trace generation query.
TraceGeneration,
/// Submit a Atlantic trace generation and proof generation query.
TraceGenerationProofGeneration,
}

impl ProofTraceEndpoints {
pub fn url(&self, base_url: &Url) -> Result<Url, SharpSdkError> {
match self {
Self::ProofGeneration => base_url.join("proof-generation"),
Self::TraceGeneration => base_url.join("trace-generation"),
Self::TraceGenerationProofGeneration => {
base_url.join("trace-generation-proof-generation")
}
}
.map_err(SharpSdkError::from)
}
}

/// The L2 endpoints.
#[derive(Debug, Clone)]
pub enum L2Endpoints {
/// Submit a Atlantic L2 query.
AtlanticQuery,
/// Submit a Atlantic proof generation and verification query.
ProofGenerationVerification,
/// Submit a Atlantic proof verification query.
ProofVerification,
}

impl L2Endpoints {
pub fn url(&self, base_url: &Url) -> Result<Url, SharpSdkError> {
match self {
Self::AtlanticQuery => base_url.join("l2/atlantic-query"),
Self::ProofGenerationVerification => {
base_url.join("l2/atlantic-query/proof-generation-verification")
}
Self::ProofVerification => base_url.join("l2/atlantic-query/proof-verification"),
}
.map_err(SharpSdkError::from)
}
}

/// The Sharp queries endpoints.
#[derive(Debug, Clone)]
pub enum SharpQueryEndpoints {
/// Get the list of Atlantic queries that have been submitted.
Queries,
/// Get an Atlantic query.
Query,
/// Get the Atlantic query jobs for a given Atlantic query.
QueryJobs,
}

impl SharpQueryEndpoints {
pub fn url(&self, base_url: &Url) -> Result<Url, SharpSdkError> {
match self {
Self::Queries => base_url.join("atlantic-queries"),
Self::Query => base_url.join("atlantic-query"),
Self::QueryJobs => base_url.join("atlantic-query-jobs"),
}
.map_err(SharpSdkError::from)
}
}

/// The health check endpoint.
#[derive(Debug, Clone)]
pub enum HealthCheckEndpoints {
/// Check if the server is alive.
IsAlive,
}

impl HealthCheckEndpoints {
pub fn url(&self, base_url: &Url) -> Result<Url, SharpSdkError> {
match self {
Self::IsAlive => base_url.join("is-alive"),
}
.map_err(SharpSdkError::from)
}
}

/// The program registry endpoint.
#[derive(Debug, Clone)]
pub enum ProgramRegistryEndpoints {
/// Submit a program to the program registry.
SubmitProgram,
}

impl ProgramRegistryEndpoints {
pub fn url(&self, base_url: &Url) -> Result<Url, SharpSdkError> {
match self {
Self::SubmitProgram => base_url.join("submit-program"),
}
.map_err(SharpSdkError::from)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_proof_trace_endpoint_urls() {
let base_url = Url::parse("https://example.com/").unwrap();

// Test ProofTraceEndpoints URLs
assert_eq!(
ProofTraceEndpoints::ProofGeneration.url(&base_url).unwrap(),
Url::parse("https://example.com/proof-generation").unwrap()
);
assert_eq!(
ProofTraceEndpoints::TraceGeneration.url(&base_url).unwrap(),
Url::parse("https://example.com/trace-generation").unwrap()
);
assert_eq!(
ProofTraceEndpoints::TraceGenerationProofGeneration.url(&base_url).unwrap(),
Url::parse("https://example.com/trace-generation-proof-generation").unwrap()
);
}

#[test]
fn test_l2_endpoint_urls() {
let base_url = Url::parse("https://example.com/").unwrap();

// Test L2Endpoints URLs
assert_eq!(
L2Endpoints::AtlanticQuery.url(&base_url).unwrap(),
Url::parse("https://example.com/l2/atlantic-query").unwrap()
);
assert_eq!(
L2Endpoints::ProofGenerationVerification.url(&base_url).unwrap(),
Url::parse("https://example.com/l2/atlantic-query/proof-generation-verification")
.unwrap()
);
assert_eq!(
L2Endpoints::ProofVerification.url(&base_url).unwrap(),
Url::parse("https://example.com/l2/atlantic-query/proof-verification").unwrap()
);
}

#[test]
fn test_sharp_query_endpoint_urls() {
let base_url = Url::parse("https://example.com/").unwrap();

// Test SharpQueryEndpoints URLs
assert_eq!(
SharpQueryEndpoints::Queries.url(&base_url).unwrap(),
Url::parse("https://example.com/atlantic-queries").unwrap()
);
assert_eq!(
SharpQueryEndpoints::Query.url(&base_url).unwrap(),
Url::parse("https://example.com/atlantic-query").unwrap()
);
assert_eq!(
SharpQueryEndpoints::QueryJobs.url(&base_url).unwrap(),
Url::parse("https://example.com/atlantic-query-jobs").unwrap()
);
}

#[test]
fn test_health_check_endpoint_url() {
let base_url = Url::parse("https://example.com/").unwrap();

// Test HealthCheckEndpoints URL
assert_eq!(
HealthCheckEndpoints::IsAlive.url(&base_url).unwrap(),
Url::parse("https://example.com/is-alive").unwrap()
);
}

#[test]
fn test_program_registry_endpoint_url() {
let base_url = Url::parse("https://example.com/").unwrap();

// Test ProgramRegistryEndpoints URL
assert_eq!(
ProgramRegistryEndpoints::SubmitProgram.url(&base_url).unwrap(),
Url::parse("https://example.com/submit-program").unwrap()
);
}
}
15 changes: 15 additions & 0 deletions crates/exex/src/atlantic/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use thiserror::Error;

#[derive(Debug, Error)]
pub enum SharpSdkError {
#[error(transparent)]
ReqwestError(#[from] reqwest::Error),
#[error(transparent)]
SerdeError(#[from] serde_json::Error),
#[error(transparent)]
FileError(#[from] std::io::Error),
#[error(transparent)]
UrlParseError(#[from] url::ParseError),
#[error("Missing program hash or program file")]
MissingProgramHashOrFile,
}
14 changes: 14 additions & 0 deletions crates/exex/src/atlantic/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//! # Sharp SDK Modules
//!
//! This library provides a SDK for interacting with the Sharp API,
//! offering endpoints, error handling, data models, and proof generation functionalities.
//!
//! ## Inspiration
//! This SDK is highly inspired by [herodotus_sharp_playground](https://github.com/chudkowsky/herodotus_sharp_playground),
//! which influenced its design and functionality.
pub mod endpoints;
pub mod error;
pub mod model;
pub mod prover;
pub mod sharp;
40 changes: 40 additions & 0 deletions crates/exex/src/atlantic/model.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct Context {
pub proof_path: Option<String>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct Job {
pub id: String,
pub status: String,
pub context: Option<Context>,
}

#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct SharpQueryDetails {
id: String,
submitted_by_client: String,
status: String,
step: Option<String>,
program_hash: Option<String>,
layout: Option<String>,
program_fact_hash: Option<String>,
price: String,
credits_used: usize,
is_fact_mocked: bool,
prover: Option<String>,
chain: String,
steps: Vec<String>,
created_at: String,
completed_at: Option<String>,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct QueryResponse {
pub sharp_query_id: String,
}
31 changes: 31 additions & 0 deletions crates/exex/src/atlantic/prover.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use std::fmt;

#[derive(Debug)]
pub enum ProverVersion {
Starkware,
Herodotus,
}

impl fmt::Display for ProverVersion {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let version_str = match self {
Self::Starkware => "starkware_sharp",
Self::Herodotus => "herodotus_stone",
};
write!(f, "{version_str}")
}
}

#[cfg(test)]
mod tests {
use super::ProverVersion;

#[test]
fn test_prover_version_to_string() {
let version_starkware = ProverVersion::Starkware;
assert_eq!(version_starkware.to_string(), "starkware_sharp");

let version_herodotus = ProverVersion::Herodotus;
assert_eq!(version_herodotus.to_string(), "herodotus_stone");
}
}
56 changes: 56 additions & 0 deletions crates/exex/src/atlantic/sharp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use super::{error::SharpSdkError, model::QueryResponse, prover::ProverVersion};
use crate::atlantic::endpoints::ProofTraceEndpoints;
use reqwest::Client;
use url::Url;

/// The Sharp SDK for interacting with the Sharp API.
#[derive(Debug, Clone)]
pub struct SharpSdk {
/// The API key to use for authentication.
pub api_key: String,
/// The base URL for the Sharp API.
pub base_url: Url,
}

impl SharpSdk {
/// Create a new Sharp SDK instance
pub const fn new(api_key: String, base_url: Url) -> Self {
Self { api_key, base_url }
}

pub async fn proof_generation(
&self,
pie_file: Vec<u8>,
layout: &str,
prover: ProverVersion,
) -> Result<QueryResponse, SharpSdkError> {
// Create the form data
let form = reqwest::multipart::Form::new()
.part(
"pieFile",
reqwest::multipart::Part::bytes(pie_file)
.file_name("pie.zip")
.mime_str("application/zip")?,
)
.text("layout", layout.to_string())
.text("prover", prover.to_string());

// Create a new HTTP client
let client = Client::new();

// Construct the full URL.
let url = ProofTraceEndpoints::ProofGeneration.url(&self.base_url)?;

// Send the request
let response = client
.post(url)
.query(&[("apiKey", &self.api_key)])
.multipart(form)
.send()
.await?
.json::<QueryResponse>()
.await?;

Ok(response)
}
}
1 change: 1 addition & 0 deletions crates/exex/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod atlantic;
pub mod db;
pub mod execution;
pub mod exex;
Expand Down

0 comments on commit c547876

Please sign in to comment.