Skip to content

Commit

Permalink
fix: make use of config.toml, implement config_path as argument (#49)
Browse files Browse the repository at this point in the history
* fix: make use of config.toml, implement config_path as argument

* fix: make all config fields optional to deserialize only part of config.toml

* fix: remove printlns

* fix: use error! and home dir
  • Loading branch information
sebasti810 authored Jul 10, 2024
1 parent bcd2599 commit b5f801d
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 66 deletions.
50 changes: 50 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,5 @@ mockall = "0.12.1"
keystore = { git = "https://github.com/deltadevsde/keystore", rev = "40f21a41afd0654091bb0881665288034ab8533f" }
pyroscope = "0.5.7"
pyroscope_pprofrs = "0.2.7"
toml = "0.8.14"
dirs = "5.0.1"
135 changes: 77 additions & 58 deletions src/cfg.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use clap::{Parser, Subcommand};
use config::{builder::DefaultState, ConfigBuilder, File, FileFormat};
use serde::Deserialize;
use std::sync::Arc;
use config::{builder::DefaultState, ConfigBuilder, File};
use dirs::home_dir;
use serde::{Deserialize, Serialize};
use std::{fs, path::Path, sync::Arc};

use crate::da::{
CelestiaConnection,
LocalDataAvailabilityLayer
};
use crate::da::{CelestiaConnection, LocalDataAvailabilityLayer};

use crate::da::DataAvailabilityLayer;

Expand Down Expand Up @@ -39,7 +37,7 @@ pub struct CommandLineArgs {
epoch_time: Option<u64>,

/// IP address for the webserver to listen on
#[arg(short, long)]
#[arg(long)]
host: Option<String>,

/// Port number for the webserver to listen on
Expand All @@ -49,26 +47,28 @@ pub struct CommandLineArgs {
#[arg(long)]
public_key: Option<String>,

#[arg(long)]
config_path: Option<String>,

#[command(subcommand)]
pub command: Commands,
}

#[derive(Debug, Deserialize, Clone)]
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Config {
#[serde(skip_serializing_if = "Option::is_none")]
pub webserver: Option<WebServerConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub celestia_config: Option<CelestiaConfig>,
#[serde(skip_serializing_if = "Option::is_none")]

pub log_level: String,
pub da_layer: DALayerOption,
pub log_level: Option<String>,
pub da_layer: Option<DALayerOption>,
pub redis_config: Option<RedisConfig>,
pub epoch_time: u64,
pub epoch_time: Option<u64>,
pub public_key: Option<String>,
}

#[derive(Debug, Default, Clone, Eq, PartialEq, Deserialize)]
#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "serde", derive(SerializeDisplay, DeserializeFromStr))]
pub enum DALayerOption {
#[default]
Expand All @@ -77,7 +77,7 @@ pub enum DALayerOption {
None,
}

#[derive(Debug, Deserialize, Clone)]
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct WebServerConfig {
pub host: String,
pub port: u16,
Expand All @@ -92,20 +92,20 @@ impl Default for WebServerConfig {
}
}

#[derive(Debug, Deserialize, Clone)]
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct RedisConfig {
pub connection_string: String
pub connection_string: String,
}

impl Default for RedisConfig {
fn default() -> Self {
RedisConfig{
connection_string: "redis://127.0.0.1/".to_string()
RedisConfig {
connection_string: "redis://127.0.0.1/".to_string(),
}
}
}

#[derive(Debug, Deserialize, Clone)]
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CelestiaConfig {
pub connection_string: String,
pub namespace_id: String,
Expand All @@ -124,72 +124,89 @@ impl Default for Config {
fn default() -> Self {
Config {
webserver: Some(WebServerConfig::default()),
log_level: "DEBUG".to_string(),
da_layer: DALayerOption::default(),
log_level: Some("DEBUG".to_string()),
da_layer: Some(DALayerOption::default()),
celestia_config: Some(CelestiaConfig::default()),
redis_config: Some(RedisConfig::default()),
epoch_time: 60,
epoch_time: Some(60),
public_key: None,
}
}
}

pub fn load_config(args: CommandLineArgs) -> Result<Config, config::ConfigError> {
let config_path = args.config_path.unwrap_or_else(|| {
let home_dir = home_dir().expect("Failed to get home directory");
format!("{}/.deimos/config.toml", home_dir.to_string_lossy())
});

// if the config file doesn't exist, create it with the default values
if !Path::new(&config_path).exists() {
if let Some(parent) = Path::new(&config_path).parent() {
fs::create_dir_all(parent).unwrap();
}

let default_config = Config::default();
let config_toml = toml::to_string(&default_config).unwrap();
fs::write(&config_path, config_toml).unwrap();
}

let settings = ConfigBuilder::<DefaultState>::default()
.add_source(File::from_str(
include_str!("config.toml"),
FileFormat::Toml,
))
.add_source(File::with_name(&config_path))
.build()?;

info!("{}", settings.get_string("log_level").unwrap_or_default());

let default_config = Config::default();
let file_config: Config = settings.try_deserialize().unwrap_or_else(|e| {
error!("deserializing config file: {}", e);
Config::default()
});

// if the config file is missing a field, use the default value
let merged_config = Config {
log_level: file_config.log_level.or(default_config.log_level),
webserver: file_config.webserver.or(default_config.webserver),
redis_config: file_config.redis_config.or(default_config.redis_config),
celestia_config: file_config
.celestia_config
.or(default_config.celestia_config),
da_layer: file_config.da_layer.or(default_config.da_layer),
epoch_time: file_config.epoch_time.or(default_config.epoch_time),
public_key: file_config.public_key.or(default_config.public_key),
};

Ok(Config {
log_level: args.log_level.unwrap_or(default_config.log_level),
log_level: Some(args.log_level.unwrap_or(merged_config.log_level.unwrap())),
webserver: Some(WebServerConfig {
host: args
.host
.unwrap_or(default_config.webserver.as_ref().unwrap().host.clone()),
port: args
.port
.unwrap_or(default_config.webserver.as_ref().unwrap().port),
.unwrap_or(merged_config.webserver.clone().unwrap().host),
port: args.port.unwrap_or(merged_config.webserver.unwrap().port),
}),
da_layer: DALayerOption::default(),
redis_config: Some(RedisConfig {
connection_string: args.redis_client.unwrap_or(
default_config.redis_config.as_ref().unwrap().connection_string.clone()
)
connection_string: args
.redis_client
.unwrap_or(merged_config.redis_config.unwrap().connection_string),
}),
celestia_config: Some(CelestiaConfig {
connection_string: args.celestia_client.unwrap_or(
default_config
.celestia_config
.as_ref()
.unwrap()
.connection_string
.clone(),
),
namespace_id: args.celestia_namespace_id.unwrap_or(
default_config
merged_config
.celestia_config
.as_ref()
.clone()
.unwrap()
.namespace_id
.clone(),
.connection_string,
),
namespace_id: args
.celestia_namespace_id
.unwrap_or(merged_config.celestia_config.unwrap().namespace_id),
}),
epoch_time: args
.epoch_time
.map(|e| e as u64)
.unwrap_or(default_config.epoch_time),
public_key: args.public_key.or(default_config.public_key),
da_layer: merged_config.da_layer,
epoch_time: Some(args.epoch_time.unwrap_or(merged_config.epoch_time.unwrap())),
public_key: args.public_key.or(merged_config.public_key),
})
}

pub async fn initialize_da_layer(config: &Config) -> Arc<dyn DataAvailabilityLayer + 'static> {
match &config.da_layer {
match config.da_layer.as_ref().unwrap() {
DALayerOption::Celestia => {
let celestia_conf = config.clone().celestia_config.unwrap();
match CelestiaConnection::new(
Expand All @@ -205,7 +222,9 @@ pub async fn initialize_da_layer(config: &Config) -> Arc<dyn DataAvailabilityLay
}
}
}
DALayerOption::InMemory => Arc::new(LocalDataAvailabilityLayer::new()) as Arc<dyn DataAvailabilityLayer + 'static>,
DALayerOption::InMemory => {
Arc::new(LocalDataAvailabilityLayer::new()) as Arc<dyn DataAvailabilityLayer + 'static>
}
DALayerOption::None => panic!("No DA Layer"),
}
}
}
1 change: 0 additions & 1 deletion src/config.toml

This file was deleted.

2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ async fn main() -> std::io::Result<()> {
let args = CommandLineArgs::parse();
let config = load_config(args.clone()).unwrap();

std::env::set_var("RUST_LOG", &config.log_level);
std::env::set_var("RUST_LOG", &config.clone().log_level.unwrap());

pretty_env_logger::init();
dotenv().ok();
Expand Down
16 changes: 10 additions & 6 deletions src/node_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,10 @@ impl NodeType for LightClient {
{
trace!("valid signature for height {}", i);
} else {
panic!("invalid signature in retrieved epoch on height {}", i);
panic!(
"invalid signature in retrieved epoch on height {}",
i
);
}
} else {
error!("epoch on height {} was not signed", i);
Expand Down Expand Up @@ -179,7 +182,7 @@ impl Sequencer {
Sequencer {
db,
da,
epoch_duration: cfg.epoch_time,
epoch_duration: cfg.epoch_time.unwrap(),
ws: WebServer::new(cfg.webserver.unwrap()),
key,
epoch_buffer_tx: Arc::new(tx),
Expand Down Expand Up @@ -416,15 +419,16 @@ impl Sequencer {
/// * `false` if the operation was unsuccessful, e.g., due to an invalid signature or other errors.
///
pub fn update_entry(&self, signature: &UpdateEntryJson) -> bool {
debug!("updating entry for uid {} with msg {}", signature.id, signature.signed_message);
debug!(
"updating entry for uid {} with msg {}",
signature.id, signature.signed_message
);
let signed_content = match verify_signature(signature, Some(signature.public_key.clone())) {
Ok(content) => content,
Err(_) => {
error!(
"updating entry for uid {}: invalid signature with pubkey {} on msg {}",
signature.id,
signature.public_key,
signature.signed_message
signature.id, signature.public_key, signature.signed_message
);
return false;
}
Expand Down

0 comments on commit b5f801d

Please sign in to comment.