Skip to content

Commit

Permalink
feat: add SxTClient
Browse files Browse the repository at this point in the history
  • Loading branch information
iajoiner committed Oct 28, 2024
1 parent c5ae3a6 commit bb8644d
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 111 deletions.
42 changes: 18 additions & 24 deletions scripts/count-ethereum-core/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use futures::StreamExt;
use indexmap::IndexMap;
use proof_of_sql::base::database::OwnedColumn;
use std::{env, fs::File, io::BufReader};
use sxt_proof_of_sql_sdk::{query_and_verify, SdkArgs};
use std::{env, fs::File, io::BufReader, sync::Arc};
use sxt_proof_of_sql_sdk::SxTClient;

#[allow(dead_code)]
const ETHEREUM_CORE_COUNTS_FILE: &str = "ethereum-core-counts.json";
Expand Down Expand Up @@ -32,17 +32,14 @@ const ETHEREUM_CORE_TABLES: [&str; 21] = [
];

async fn count_table(
table_ref: String,
base_args: SdkArgs,
client: &SxTClient,
table_ref: &str,
) -> Result<i64, Box<dyn core::error::Error>> {
let query = format!("SELECT * FROM {table_ref}");
let args = SdkArgs {
table_ref,
query,
..base_args
};

let table = query_and_verify(&args).await?;
let uppercased_table_ref = table_ref.to_uppercase();
let query = format!("SELECT * FROM {uppercased_table_ref}");
let table = client
.query_and_verify(&query, &uppercased_table_ref)
.await?;
assert_eq!(table.num_columns(), 1);
assert_eq!(table.num_rows(), 1);

Expand Down Expand Up @@ -74,23 +71,20 @@ async fn main() {
env_logger::init();
dotenv::dotenv().unwrap();

let base_args = SdkArgs {
prover_root_url: env::var("PROVER_ROOT_URL").unwrap_or("api.spaceandtime.dev".to_string()),
auth_root_url: env::var("AUTH_ROOT_URL").unwrap_or("api.spaceandtime.dev".to_string()),
substrate_node_url: env::var("SUBSTRATE_NODE_URL")
.unwrap_or("foo.bar.spaceandtime.dev".to_string()),
verifier_setup: env::var("VERIFIER_SETUP").unwrap_or("verifier_setup.bin".to_string()),
sxt_api_key: env::var("SXT_API_KEY").expect("SXT_API_KEY is required"),
query: "SELECT COUNT(*) FROM PLACEHOLDER".to_string(),
table_ref: "PLACEHOLDER".to_string(),
};
let client = Arc::new(SxTClient::new(
env::var("PROVER_ROOT_URL").unwrap_or("api.spaceandtime.dev".to_string()),
env::var("AUTH_ROOT_URL").unwrap_or("api.spaceandtime.dev".to_string()),
env::var("SUBSTRATE_NODE_URL").unwrap_or("foo.bar.spaceandtime.dev".to_string()),
env::var("SXT_API_KEY").expect("SXT_API_KEY is required"),
env::var("VERIFIER_SETUP").unwrap_or("verifier_setup.bin".to_string()),
));

let current_counts: IndexMap<String, i64> = futures::stream::iter(ETHEREUM_CORE_TABLES)
.filter_map(|table_ref| {
let base_args = base_args.clone();
let client = client.clone();
async move {
log::info!("querying count of {table_ref}");
let count = count_table(table_ref.to_string().to_uppercase(), base_args)
let count = count_table(client.as_ref(), table_ref)
.await
.inspect_err(|e| log::error!("failed to query count for {table_ref}: {e}"))
.ok()?;
Expand Down
13 changes: 13 additions & 0 deletions sdk/src/args.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::SxTClient;
use clap::Parser;

/// Struct to define and parse command-line arguments for Proof of SQL Client.
Expand Down Expand Up @@ -79,3 +80,15 @@ pub struct SdkArgs {
)]
pub verifier_setup: String,
}

impl From<&SdkArgs> for SxTClient {
fn from(args: &SdkArgs) -> Self {
Self::new(
args.prover_root_url.clone(),
args.auth_root_url.clone(),
args.substrate_node_url.clone(),
args.sxt_api_key.clone(),
args.verifier_setup.clone(),
)
}
}
129 changes: 129 additions & 0 deletions sdk/src/client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
use crate::{get_access_token, query_commitments};
use proof_of_sql::{
base::database::{OwnedTable, TableRef},
proof_primitive::dory::{
DoryScalar, DynamicDoryCommitment, DynamicDoryEvaluationProof, VerifierSetup,
},
sql::{parse::QueryExpr, proof::VerifiableQueryResult},
};
use prover::{ProverContextRange, ProverQuery, ProverResponse};
use reqwest::Client;
use std::{collections::HashMap, path::Path};

mod prover {
tonic::include_proto!("sxt.core");
}

/// Space and Time (SxT) client
#[derive(Debug, Clone)]
pub struct SxTClient {
/// Root URL for the Prover service
///
/// This URL is used for interacting with the prover service.
pub prover_root_url: String,

/// Root URL for the Auth service
///
/// Used for authentication requests. Generally the same as the Prover Root URL.
pub auth_root_url: String,

/// URL for the Substrate node service
///
/// Specifies the Substrate node endpoint used for accessing commitment data.
pub substrate_node_url: String,

/// API Key for Space and Time (SxT) services
///
/// The API key required for authorization with Space and Time services.
pub sxt_api_key: String,

/// Path to the verifier setup binary file
///
/// Specifies the path to the `verifier_setup.bin` file required for verification.
pub verifier_setup: String,
}

impl SxTClient {
/// Create a new SxT client
pub fn new(
prover_root_url: String,
auth_root_url: String,
substrate_node_url: String,
sxt_api_key: String,
verifier_setup: String,
) -> Self {
Self {
prover_root_url,
auth_root_url,
substrate_node_url,
sxt_api_key,
verifier_setup,
}
}

/// Query and verify a SQL query
///
/// Run a SQL query and verify the result using Dynamic Dory.
pub async fn query_and_verify(
&self,
query: &str,
table: &str,
) -> Result<OwnedTable<DoryScalar>, Box<dyn core::error::Error>> {
// Parse table_ref into TableRef struct
let table_ref = TableRef::new(table.parse()?);
let schema = table_ref.schema_id();
// Load verifier setup
let verifier_setup_path = Path::new(&self.verifier_setup);
let verifier_setup = VerifierSetup::load_from_file(verifier_setup_path)?;
// Accessor setup
let accessor =
query_commitments(&[table_ref.resource_id()], &self.substrate_node_url).await?;
// Parse the SQL query
let query_expr: QueryExpr<DynamicDoryCommitment> =
QueryExpr::try_new(query.parse()?, schema, &accessor)?;
let proof_plan = query_expr.proof_expr();
let serialized_proof_plan = flexbuffers::to_vec(proof_plan)?;
// Send the query to the prover
let mut query_context = HashMap::new();
let commitment_range = accessor[&table_ref].range();
query_context.insert(
table_ref.to_string().to_uppercase(),
ProverContextRange {
start: commitment_range.start as u64,
ends: vec![commitment_range.end as u64],
},
);
let prover_query = ProverQuery {
proof_plan: serialized_proof_plan,
query_context,
commitment_scheme: 1,
};
let client = Client::new();
let access_token = get_access_token(&self.sxt_api_key, &self.auth_root_url).await?;
let response = client
.post(format!("https://{}/v1/prove", &self.prover_root_url))
.bearer_auth(&access_token)
.json(&prover_query)
.send()
.await?
.error_for_status()?;
let serialized_prover_response = response.text().await?;
let prover_response = serde_json::from_str::<ProverResponse>(&serialized_prover_response)
.map_err(|_e| {
format!(
"Failed to parse prover response: {}",
&serialized_prover_response
)
})?;
let stringified_verifiable_result = prover_response.verifiable_result.clone();
let verifiable_result: VerifiableQueryResult<DynamicDoryEvaluationProof> =
flexbuffers::from_slice(&stringified_verifiable_result)?;
// Verify the proof
let proof = verifiable_result.proof.unwrap();
let serialized_result = verifiable_result.provable_result.unwrap();
let owned_table_result = proof
.verify(proof_plan, &accessor, &serialized_result, &&verifier_setup)?
.table;
Ok(owned_table_result)
}
}
89 changes: 4 additions & 85 deletions sdk/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,90 +1,9 @@
mod args;
pub use args::SdkArgs;
mod auth;
pub use auth::get_access_token;
mod client;
pub use client::SxTClient;
mod substrate;
pub use substrate::query_commitments;
mod sxt_chain_runtime;

use proof_of_sql::{
base::database::{OwnedTable, TableRef},
proof_primitive::dory::{
DoryScalar, DynamicDoryCommitment, DynamicDoryEvaluationProof, VerifierSetup,
},
sql::{parse::QueryExpr, proof::VerifiableQueryResult},
};
use prover::{ProverContextRange, ProverQuery, ProverResponse};
use reqwest::Client;
use std::{collections::HashMap, path::Path};

mod prover {
tonic::include_proto!("sxt.core");
}

/// Query and verify a SQL query
///
/// Run a SQL query and verify the result using Dynamic Dory.
pub async fn query_and_verify(
args: &SdkArgs,
) -> Result<OwnedTable<DoryScalar>, Box<dyn core::error::Error>> {
// Parse table_ref into TableRef struct
let table_ref = TableRef::new(args.table_ref.parse()?);
let schema = table_ref.schema_id();
// Load verifier setup
let verifier_setup_path = Path::new(&args.verifier_setup);
let verifier_setup = VerifierSetup::load_from_file(verifier_setup_path)?;
// Accessor setup
let accessor =
substrate::query_commitments(&[table_ref.resource_id()], &args.substrate_node_url).await?;
// Parse the SQL query
let query: QueryExpr<DynamicDoryCommitment> =
QueryExpr::try_new(args.query.parse()?, schema, &accessor)?;
let proof_plan = query.proof_expr();
let serialized_proof_plan = flexbuffers::to_vec(proof_plan)?;
// Send the query to the prover
let mut query_context = HashMap::new();
let commitment_range = accessor[&table_ref].range();

query_context.insert(
table_ref.to_string().to_uppercase(),
ProverContextRange {
start: commitment_range.start as u64,
ends: vec![commitment_range.end as u64],
},
);
let prover_query = ProverQuery {
proof_plan: serialized_proof_plan,
query_context,
commitment_scheme: 1,
};
let client = Client::new();
let access_token = auth::get_access_token(&args.sxt_api_key, &args.auth_root_url).await?;
let response = client
.post(format!("https://{}/v1/prove", &args.prover_root_url))
.bearer_auth(&access_token)
.json(&prover_query)
.send()
.await?
.error_for_status()?;
let serialized_prover_response = response.text().await?;
let prover_response = serde_json::from_str::<ProverResponse>(&serialized_prover_response)
.map_err(|_e| {
format!(
"Failed to parse prover response: {}",
&serialized_prover_response
)
})?;
let stringified_verifiable_result = prover_response.verifiable_result.clone();
let verifiable_result: VerifiableQueryResult<DynamicDoryEvaluationProof> =
flexbuffers::from_slice(&stringified_verifiable_result)?;
// Verify the proof
let proof = verifiable_result.proof.unwrap();
let serialized_result = verifiable_result.provable_result.unwrap();
let owned_table_result = proof
.verify(
query.proof_expr(),
&accessor,
&serialized_result,
&&verifier_setup,
)?
.table;
Ok(owned_table_result)
}
7 changes: 5 additions & 2 deletions sdk/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use clap::Parser;
use dotenv::dotenv;
use sxt_proof_of_sql_sdk::{query_and_verify, SdkArgs};
use sxt_proof_of_sql_sdk::{SdkArgs, SxTClient};

#[tokio::main]
async fn main() -> Result<(), Box<dyn core::error::Error>> {
Expand All @@ -9,9 +9,12 @@ async fn main() -> Result<(), Box<dyn core::error::Error>> {

// Parse command-line arguments
let args = SdkArgs::parse();
let client: SxTClient = (&args).into();

// Execute the query and verify the result
let result = query_and_verify(&args).await?;
let result = client
.query_and_verify(&args.query, &args.table_ref)
.await?;

// Print the result of the query
println!("Query result: {:?}", result);
Expand Down

0 comments on commit bb8644d

Please sign in to comment.