Skip to content

Commit

Permalink
feat(saya): add config file arg for saya bin (starkware-libs#1513)
Browse files Browse the repository at this point in the history
* feat(saya): add config file arg for saya bin

* fix: minor fixes and valid celestia namespace

* fix: adjust config test with new celestia namespace

---------

Co-authored-by: Jonatan Chaverri <jonatan.chaverri@kyndryl.com>
Co-authored-by: glihm <dev@glihm.net>
  • Loading branch information
3 people authored Feb 11, 2024
1 parent ad97e8f commit 1e6ed14
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 28 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ tokio = { version = "1.32.0", features = [ "full" ] }
toml = "0.7.4"
tracing = "0.1.34"
tracing-subscriber = { version = "0.3.16", features = [ "env-filter", "json" ] }
url = "2.4.0"
url = { version = "2.4.0", features = [ "serde" ] }

# server
hyper = "0.14.27"
Expand Down
119 changes: 94 additions & 25 deletions bin/saya/src/args/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
//! Saya binary options.
use std::fs::File;
use std::io::BufReader;
use std::path::PathBuf;

use clap::Parser;
use saya_core::data_availability::celestia::CelestiaConfig;
use saya_core::data_availability::DataAvailabilityConfig;
Expand All @@ -19,13 +23,21 @@ pub struct SayaArgs {
#[arg(long)]
#[arg(value_name = "KATANA URL")]
#[arg(help = "The Katana RPC URL to fetch data from.")]
#[arg(default_value = "http://localhost:5050")]
pub rpc_url: Url,

/// Enable JSON logging.
#[arg(long)]
#[arg(help = "Output logs in JSON format.")]
pub json_log: bool,

/// Specify a JSON configuration file to use.
#[arg(long)]
#[arg(value_name = "CONFIG FILE")]
#[arg(help = "The path to a JSON configuration file. This takes precedence over other CLI \
arguments.")]
pub config_file: Option<PathBuf>,

/// Specify a block to start fetching data from.
#[arg(short, long, default_value = "0")]
pub start_block: u64,
Expand Down Expand Up @@ -54,34 +66,91 @@ impl SayaArgs {
}

impl TryFrom<SayaArgs> for SayaConfig {
type Error = &'static str;
type Error = Box<dyn std::error::Error>;

fn try_from(args: SayaArgs) -> Result<Self, Self::Error> {
let da_config = match args.data_availability.da_chain {
Some(chain) => Some(match chain {
DataAvailabilityChain::Celestia => {
let conf = args.data_availability.celestia;

DataAvailabilityConfig::Celestia(CelestiaConfig {
node_url: match conf.celestia_node_url {
Some(v) => v,
None => return Err("Celestia config: Node url is required"),
},
namespace: match conf.celestia_namespace {
Some(v) => v,
None => return Err("Celestia config: Namespace is required"),
},
node_auth_token: conf.celestia_node_auth_token,
})
}
}),
None => None,
if let Some(config_file) = args.config_file {
let file = File::open(config_file).map_err(|_| "Failed to open config file")?;
let reader = BufReader::new(file);
serde_json::from_reader(reader).map_err(|e| e.into())
} else {
let da_config = match args.data_availability.da_chain {
Some(chain) => Some(match chain {
DataAvailabilityChain::Celestia => {
let conf = args.data_availability.celestia;

DataAvailabilityConfig::Celestia(CelestiaConfig {
node_url: match conf.celestia_node_url {
Some(v) => v,
None => {
return Err(Box::new(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"Celestia config: Node url is required",
)));
}
},
namespace: match conf.celestia_namespace {
Some(v) => v,
None => {
return Err(Box::new(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"Celestia config: Namespace is required",
)));
}
},
node_auth_token: conf.celestia_node_auth_token,
})
}
}),
None => None,
};

Ok(SayaConfig {
katana_rpc: args.rpc_url,
start_block: args.start_block,
data_availability: da_config,
})
}
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::args::data_availability::CelestiaOptions;

#[test]
fn test_saya_config_deserialization() {
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
let config_file_path = std::path::Path::new(&manifest_dir)
.join("src")
.join("args")
.join("test_saya_config_file.json");

let args = SayaArgs {
config_file: Some(config_file_path.clone()),
rpc_url: Url::parse("http://localhost:5050").unwrap(),
json_log: false,
start_block: 0,
data_availability: DataAvailabilityOptions {
da_chain: None,
celestia: CelestiaOptions {
celestia_node_url: None,
celestia_node_auth_token: None,
celestia_namespace: None,
},
},
};
let config: SayaConfig = args.try_into().unwrap();

Ok(SayaConfig {
katana_rpc: args.rpc_url,
start_block: args.start_block,
data_availability: da_config,
})
assert_eq!(config.katana_rpc.as_str(), "http://localhost:5050/");
assert_eq!(config.start_block, 0);
if let Some(DataAvailabilityConfig::Celestia(celestia_config)) = config.data_availability {
assert_eq!(celestia_config.node_url.as_str(), "http://localhost:26657/");
assert_eq!(celestia_config.node_auth_token, Some("your_auth_token".to_string()));
assert_eq!(celestia_config.namespace, "katana");
} else {
panic!("Expected Celestia config");
}
}
}
11 changes: 11 additions & 0 deletions bin/saya/src/args/test_saya_config_file.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"katana_rpc": "http://localhost:5050",
"start_block": 0,
"data_availability": {
"Celestia": {
"node_url": "http://localhost:26657",
"node_auth_token": "your_auth_token",
"namespace": "katana"
}
}
}
5 changes: 4 additions & 1 deletion crates/saya/core/src/data_availability/celestia/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ use celestia_rpc::{BlobClient, Client};
use celestia_types::blob::SubmitOptions;
use celestia_types::nmt::Namespace;
use celestia_types::Blob;
use serde::{Deserialize, Serialize};
use starknet::core::types::FieldElement;
use url::Url;

use crate::data_availability::error::{DataAvailabilityResult, Error};
use crate::data_availability::{DataAvailabilityClient, DataAvailabilityMode};
use crate::url_deserializer;

#[derive(Debug, Clone)]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct CelestiaConfig {
#[serde(deserialize_with = "url_deserializer")]
pub node_url: Url,
pub node_auth_token: Option<String>,
pub namespace: String,
Expand Down
3 changes: 2 additions & 1 deletion crates/saya/core/src/data_availability/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use std::fmt::Display;

use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use starknet::core::types::FieldElement;

pub mod celestia;
Expand All @@ -15,7 +16,7 @@ pub mod state_diff;
use error::DataAvailabilityResult;

/// All possible chains configuration for data availability.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub enum DataAvailabilityConfig {
Celestia(celestia::CelestiaConfig),
}
Expand Down
11 changes: 11 additions & 0 deletions crates/saya/core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Saya core library.
use std::sync::Arc;

use serde::{Deserialize, Serialize};
use starknet::core::types::{BlockId, MaybePendingStateUpdate, StateUpdate};
use starknet::providers::jsonrpc::HttpTransport;
use starknet::providers::{JsonRpcClient, Provider};
Expand All @@ -16,12 +17,22 @@ pub mod prover;
pub mod verifier;

/// Saya's main configuration.
#[derive(Debug, Deserialize, Serialize)]
pub struct SayaConfig {
#[serde(deserialize_with = "url_deserializer")]
pub katana_rpc: Url,
pub start_block: u64,
pub data_availability: Option<DataAvailabilityConfig>,
}

fn url_deserializer<'de, D>(deserializer: D) -> Result<Url, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Url::parse(&s).map_err(serde::de::Error::custom)
}

/// Saya.
pub struct Saya {
/// The main Saya configuration.
Expand Down

0 comments on commit 1e6ed14

Please sign in to comment.