-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
3,180 additions
and
895 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
use alloy::sol; | ||
|
||
sol!( | ||
#[allow(missing_docs)] | ||
#[sol(rpc)] | ||
FactRegistry, | ||
"src/contracts/artifacts/FactRegistry.json" | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,11 @@ | ||
use crate::settings::SettingsProviderError; | ||
|
||
#[derive(Debug, thiserror::Error)] | ||
pub enum ProverError { | ||
pub enum ProverServiceError { | ||
#[error("Internal prover error: {0}")] | ||
Internal(#[source] Box<dyn std::error::Error + Send + Sync + 'static>), | ||
#[error("Stone prover failed: {0}")] | ||
SettingsProvider(#[from] SettingsProviderError), | ||
#[error("Task is invalid: {0}")] | ||
TaskInvalid(String), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
use alloy::primitives::Address; | ||
use serde::{Deserialize, Serialize}; | ||
use url::Url; | ||
|
||
/// SHARP proving service configuration | ||
#[derive(Debug, Clone, Serialize, Deserialize)] | ||
pub struct SharpConfig { | ||
/// SHARP service url | ||
pub service_url: Url, | ||
/// EVM RPC node url | ||
pub rpc_node_url: Url, | ||
/// GPS verifier contract address (implements FactRegistry) | ||
pub verifier_address: Address, | ||
} | ||
|
||
impl Default for SharpConfig { | ||
fn default() -> Self { | ||
unimplemented!("No defaults for SHARP config") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
use cairo_vm::program_hash::ProgramHashError; | ||
use reqwest::StatusCode; | ||
|
||
use crate::provers::error::ProverServiceError; | ||
|
||
#[derive(Debug, thiserror::Error)] | ||
pub enum SharpError { | ||
#[error("Failed to to add SHARP job: {0}")] | ||
AddJobFailure(#[source] reqwest::Error), | ||
#[error("Failed to to get status of a SHARP job: {0}")] | ||
GetJobStatusFailure(#[source] reqwest::Error), | ||
#[error("SHARP service returned an error {0}")] | ||
SharpService(StatusCode), | ||
#[error("Fact registry call failed: {0}")] | ||
FactRegistry(#[source] alloy::contract::Error), | ||
#[error("Failed to parse task ID: {0}")] | ||
TaskIdParse(uuid::Error), | ||
#[error("Failed to encode PIE")] | ||
PieEncode(#[source] snos::error::SnOsError), | ||
#[error("Failed to compute program hash: {0}")] | ||
ProgramHashCompute(#[source] ProgramHashError), | ||
} | ||
|
||
impl From<SharpError> for ProverServiceError { | ||
fn from(value: SharpError) -> Self { | ||
Self::Internal(Box::new(value)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
use alloy::primitives::{Address, B256}; | ||
use alloy::providers::{ProviderBuilder, RootProvider}; | ||
use alloy::transports::http::{Client, Http}; | ||
use url::Url; | ||
|
||
use crate::contracts::FactRegistry::{self, FactRegistryInstance}; | ||
|
||
use super::error::SharpError; | ||
|
||
pub struct FactChecker { | ||
fact_registry: FactRegistryInstance<TransportT, ProviderT>, | ||
} | ||
|
||
type TransportT = Http<Client>; | ||
type ProviderT = RootProvider<TransportT>; | ||
|
||
impl FactChecker { | ||
pub fn new(rpc_node_url: Url, verifier_address: Address) -> Self { | ||
let provider = ProviderBuilder::new().on_http(rpc_node_url); | ||
let fact_registry = FactRegistry::new(verifier_address, provider); | ||
Self { fact_registry } | ||
} | ||
|
||
pub async fn is_valid(&self, fact: B256) -> Result<bool, SharpError> { | ||
let FactRegistry::isValidReturn { _0 } = | ||
self.fact_registry.isValid(fact.clone()).call().await.map_err(SharpError::FactRegistry)?; | ||
Ok(_0) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,92 @@ | ||
pub mod config; | ||
pub mod error; | ||
pub mod fact_checker; | ||
pub mod sharp_client; | ||
|
||
use std::str::FromStr; | ||
|
||
use alloy::primitives::B256; | ||
use async_trait::async_trait; | ||
use cairo_vm::program_hash::compute_program_hash_chain; | ||
use cairo_vm::vm::runners::cairo_pie::CairoPie; | ||
use snos::sharp::CairoJobStatus; | ||
use uuid::Uuid; | ||
|
||
use super::error::ProverError; | ||
use super::{ProverService, TaskId, TaskStatus}; | ||
use self::config::SharpConfig; | ||
use self::error::SharpError; | ||
use self::fact_checker::FactChecker; | ||
use self::sharp_client::SharpClient; | ||
|
||
use super::error::ProverServiceError; | ||
use super::{ProverService, Task, TaskId, TaskStatus}; | ||
use crate::settings::SettingsProvider; | ||
|
||
pub const SHARP_SETTINGS_NAME: &str = "sharp"; | ||
|
||
/// SHARP (aka GPS) is a shared proving service hosted by Starkware. | ||
pub struct SharpProverService { | ||
// TODO: integrate Sharp client (there are dependency conflicts, should we copy the code instead?) | ||
// https://github.com/keep-starknet-strange/snos/blob/main/src/sharp/mod.rs | ||
// ProverService interface is basically modeled after SHARP so the integration should be seamless. | ||
sharp_client: SharpClient, | ||
fact_checker: FactChecker, | ||
} | ||
|
||
#[async_trait] | ||
impl ProverService for SharpProverService { | ||
async fn submit_task(&self, cairo_pie: CairoPie) -> Result<TaskId, ProverError> { | ||
todo!() | ||
async fn submit_task(&self, task: Task) -> Result<TaskId, ProverServiceError> { | ||
let encoded_pie = match task { | ||
Task::EncodedPie(enc) => enc, | ||
Task::PieObject(pie) => { | ||
todo!("Need to resolve cairo-vm versions comflict"); | ||
// pie::encode_pie_mem(*pie).map_err(SharpError::PieEncode)? | ||
} | ||
}; | ||
let res = self.sharp_client.add_job(&encoded_pie).await?; | ||
if let Some(job_key) = res.cairo_job_key { | ||
Ok(job_key.to_string()) | ||
} else { | ||
Err(ProverServiceError::TaskInvalid(res.error_message.unwrap_or_default()).into()) | ||
} | ||
} | ||
|
||
async fn get_task_status(&self, task_id: &TaskId) -> Result<TaskStatus, ProverError> { | ||
todo!() | ||
async fn get_task_status(&self, task_id: &TaskId) -> Result<TaskStatus, ProverServiceError> { | ||
let job_key = Uuid::from_str(task_id).map_err(SharpError::TaskIdParse)?; | ||
let res = self.sharp_client.get_job_status(&job_key).await?; | ||
match res.status { | ||
CairoJobStatus::FAILED => Ok(TaskStatus::Failed(res.error_log.unwrap_or_default())), | ||
CairoJobStatus::INVALID => { | ||
Ok(TaskStatus::Failed(format!("Task is invalid: {:?}", res.invalid_reason.unwrap_or_default()))) | ||
} | ||
CairoJobStatus::UNKNOWN => Ok(TaskStatus::Failed(format!("Task not found: {}", task_id))), | ||
CairoJobStatus::IN_PROGRESS | CairoJobStatus::NOT_CREATED | CairoJobStatus::PROCESSED => { | ||
Ok(TaskStatus::Processing) | ||
} | ||
CairoJobStatus::ONCHAIN => { | ||
let fact = self.get_fact(task_id); | ||
if self.fact_checker.is_valid(fact).await? { | ||
Ok(TaskStatus::Succeeded) | ||
} else { | ||
Ok(TaskStatus::Failed(format!("Fact {} is not valid or not registed", hex::encode(&fact)))) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl SharpProverService { | ||
pub fn with_settings(settings: &impl SettingsProvider) -> Self { | ||
todo!() | ||
let sharp_cfg: SharpConfig = settings.get_settings(SHARP_SETTINGS_NAME).unwrap(); | ||
let sharp_client = SharpClient::new(sharp_cfg.service_url); | ||
let fact_checker = FactChecker::new(sharp_cfg.rpc_node_url, sharp_cfg.verifier_address); | ||
Self { sharp_client, fact_checker } | ||
} | ||
|
||
pub fn set_fact(&mut self, task_id: &TaskId, pie: &CairoPie) -> Result<(), SharpError> { | ||
let program_hash = | ||
compute_program_hash_chain(&pie.metadata.program, 1).map_err(SharpError::ProgramHashCompute)?; | ||
// TODO: https://github.com/starkware-libs/cairo-lang/blob/efa9648f57568aad8f8a13fbf027d2de7c63c2c0/src/starkware/cairo/bootloaders/generate_fact.py#L32 | ||
Ok(()) | ||
} | ||
|
||
pub fn get_fact(&self, task_id: &TaskId) -> B256 { | ||
B256::ZERO | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
use serde_json::json; | ||
use snos::sharp::{CairoJobResponse, CairoStatusResponse}; | ||
use url::Url; | ||
use uuid::Uuid; | ||
|
||
use super::error::SharpError; | ||
|
||
pub const DEFAULT_SHARP_URL: &str = "https://testnet.provingservice.io"; | ||
|
||
/// SHARP API async wrapper | ||
pub struct SharpClient { | ||
url: Url, | ||
client: reqwest::Client, | ||
} | ||
|
||
impl SharpClient { | ||
pub fn new(url: Url) -> Self { | ||
Self { url, client: reqwest::Client::new() } | ||
} | ||
|
||
pub async fn add_job(&self, encoded_pie: &str) -> Result<CairoJobResponse, SharpError> { | ||
let data = json!({ "action": "add_job", "request": { "cairo_pie": encoded_pie } }); | ||
let res = self.client.post(self.url.clone()).json(&data).send().await.map_err(SharpError::AddJobFailure)?; | ||
|
||
match res.status() { | ||
reqwest::StatusCode::OK => res.json().await.map_err(SharpError::AddJobFailure), | ||
code => Err(SharpError::SharpService(code)), | ||
} | ||
} | ||
|
||
pub async fn get_job_status(&self, job_key: &Uuid) -> Result<CairoStatusResponse, SharpError> { | ||
let data = json!({ "action": "get_status", "request": { "cairo_job_key": job_key } }); | ||
let res = | ||
self.client.post(self.url.clone()).json(&data).send().await.map_err(SharpError::GetJobStatusFailure)?; | ||
|
||
match res.status() { | ||
reqwest::StatusCode::OK => res.json().await.map_err(SharpError::GetJobStatusFailure), | ||
code => Err(SharpError::SharpService(code)), | ||
} | ||
} | ||
} | ||
|
||
impl Default for SharpClient { | ||
fn default() -> Self { | ||
Self::new(DEFAULT_SHARP_URL.parse().unwrap()) | ||
} | ||
} |
Oops, something went wrong.