From d2ff687dc07202beec77a7436cf7d2bf339e2b1e Mon Sep 17 00:00:00 2001 From: undercover-cactus Date: Tue, 30 Sep 2025 19:39:11 +0200 Subject: [PATCH] feat: added the possibility to provide a config file for SH (#191) Co-authored-by: Ahmad Kaouk <56095276+ahmadkaouk@users.noreply.github.com> --- operator/Cargo.lock | 1 + operator/Cargo.toml | 1 + operator/node/Cargo.toml | 1 + operator/node/src/cli.rs | 14 +++++++++++ operator/node/src/command.rs | 35 +++++++++++++++++++++++++++ operator/node/src/config.rs | 46 ++++++++++++++++++++++++++++++++++++ operator/node/src/main.rs | 1 + 7 files changed, 99 insertions(+) create mode 100644 operator/node/src/config.rs diff --git a/operator/Cargo.lock b/operator/Cargo.lock index c698d7a2..1447cbcb 100644 --- a/operator/Cargo.lock +++ b/operator/Cargo.lock @@ -3065,6 +3065,7 @@ dependencies = [ "sp-transaction-pool", "substrate-build-script-utils", "substrate-frame-rpc-system", + "toml 0.8.23", "url", ] diff --git a/operator/Cargo.toml b/operator/Cargo.toml index 91499510..83412fba 100644 --- a/operator/Cargo.toml +++ b/operator/Cargo.toml @@ -90,6 +90,7 @@ tracing-subscriber = { version = "=0.3.19", features = [ "env-filter", ] } # Dependency pinned because 0.3.20 messes up text formatting in substrate logs url = "2.2.2" +toml = "0.8.19" # Polkadot SDK cumulus-primitives-core = { git = "https://github.com/paritytech/polkadot-sdk", tag = "polkadot-stable2412-6", default-features = false } diff --git a/operator/node/Cargo.toml b/operator/node/Cargo.toml index 5e1d0541..1e24757c 100644 --- a/operator/node/Cargo.toml +++ b/operator/node/Cargo.toml @@ -130,6 +130,7 @@ shp-types = { workspace = true } sp-keystore = { workspace = true } serde = { workspace = true, default-features = true } cumulus-client-service = { workspace = true } +toml = { workspace = true } [build-dependencies] substrate-build-script-utils = { workspace = true, default-features = true } diff --git a/operator/node/src/cli.rs b/operator/node/src/cli.rs index c39fa440..5cca9cde 100644 --- a/operator/node/src/cli.rs +++ b/operator/node/src/cli.rs @@ -49,6 +49,20 @@ pub struct Cli { /// Fisherman configurations #[command(flatten)] pub fisherman_config: FishermanConfigurations, + + /// Provider configurations file path (allow to specify the provider configuration in a file instead of the cli) + #[arg(long, conflicts_with_all = [ + "provider", "provider_type", "max_storage_capacity", "jump_capacity", + "storage_layer", "storage_path", "extrinsic_retry_timeout", "sync_mode_min_blocks_behind", + "check_for_pending_proofs_period", "max_blocks_behind_to_catch_up_root_changes", + "msp_charging_period", "msp_charge_fees_task", "msp_charge_fees_min_debt", + "msp_move_bucket_task", "msp_move_bucket_max_try_count", "msp_move_bucket_max_tip", + "bsp_upload_file_task", "bsp_upload_file_max_try_count", "bsp_upload_file_max_tip", + "bsp_move_bucket_task", "bsp_move_bucket_grace_period", + "bsp_charge_fees_task", "bsp_charge_fees_min_debt", + "bsp_submit_proof_task", "bsp_submit_proof_max_attempts", "fisherman", "fisherman_database_url", + ])] + pub provider_config_file: Option, } #[derive(Debug, clap::Subcommand)] diff --git a/operator/node/src/command.rs b/operator/node/src/command.rs index 0c49bb01..15552872 100644 --- a/operator/node/src/command.rs +++ b/operator/node/src/command.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use crate::config; use crate::service::frontier_database_dir; use crate::{ benchmarking::{inherent_benchmark_data, RemarkBuilder, TransferKeepAliveBuilder}, @@ -318,6 +319,40 @@ pub fn run() -> sc_cli::Result<()> { let mut fisherman_options: Option = None; let runner = cli.create_runner(&cli.run)?; + // If we have a provider config file + if let Some(provider_config_file) = cli.provider_config_file { + let config = config::read_config(&provider_config_file); + if let Some(c) = config { + // Check for mutual exclusivity in config file + let has_provider = matches!( + c.provider.provider_type, + ProviderType::Bsp | ProviderType::Msp + ); + let has_fisherman = !c.fisherman.database_url.is_empty(); + + if has_provider && has_fisherman { + return Err("Cannot configure both provider and fisherman in the same config file. Please choose one role.".into()); + } + + if has_provider { + let provider = c.provider; + provider_options = Some(provider); + } else if has_fisherman { + let fisherman = c.fisherman; + fisherman_options = Some(fisherman); + } + + indexer_options = Some(c.indexer); + }; + }; + + if cli.provider_config.provider && cli.fisherman_config.fisherman { + return Err( + "Cannot run as a fisherman and a provider at the same time. Please choose one role." + .into(), + ); + } + if cli.provider_config.provider { provider_options = Some(cli.provider_config.provider_options()); }; diff --git a/operator/node/src/config.rs b/operator/node/src/config.rs new file mode 100644 index 00000000..9e8b4b2d --- /dev/null +++ b/operator/node/src/config.rs @@ -0,0 +1,46 @@ +use log::error; +use serde::Deserialize; +use std::fs::File; +use std::io::prelude::*; +use std::path::Path; +use toml; + +use shc_client::builder::{FishermanOptions, IndexerOptions}; + +use crate::command::ProviderOptions; + +#[derive(Clone, Debug, Deserialize)] +pub struct Config { + pub provider: ProviderOptions, + pub indexer: IndexerOptions, + pub fisherman: FishermanOptions, +} + +pub fn read_config(path: &str) -> Option { + let path = Path::new(path); + + let mut file = match File::open(path) { + Ok(file) => file, + Err(err) => { + error!("Failed to open config file: {}", err); + return None; + } + }; + let mut contents = String::new(); + if let Err(err) = file.read_to_string(&mut contents) { + error!("Fail to read config file : {}", err); + + return None; + }; + + let config = match toml::from_str(&contents) { + Err(err) => { + error!("Fail to parse config file : {}", err); + + return None; + } + Ok(c) => c, + }; + + return Some(config); +} diff --git a/operator/node/src/main.rs b/operator/node/src/main.rs index 9d955d02..8d516db0 100644 --- a/operator/node/src/main.rs +++ b/operator/node/src/main.rs @@ -6,6 +6,7 @@ mod chain_spec; mod cli; mod client; mod command; +mod config; mod consensus; mod eth; mod rpc;