Repository: fedimint/fedimint
Pull request #7304: Cleanup Server
Author: login: joschisan
Created: 2025-04-23T08:04:33Z | Merged: 2025-04-23T12:19:58Z

<!--

# Code Review Policy

* CI must pass (enforced)
* 1 review is mandatory (enforced), 2 or more ideal
* If you believe your change is simple, and non-controversial enough, and you want
  to avoid merge conflicts, or blocking work before it gets enough reviews, label it with
  `needs further review` label and Merge it.

See https://github.com/fedimint/fedimint/blob/master/CONTRIBUTING.md#code-review-policy for
full description.

-->



Diff:
diff --git a/fedimint-server/src/config/mod.rs b/fedimint-server/src/config/mod.rs
index 7cdf9991635..a12ebf25291 100644
--- a/fedimint-server/src/config/mod.rs
+++ b/fedimint-server/src/config/mod.rs
@@ -177,14 +177,6 @@ pub fn legacy_consensus_config_hash(cfg: &ServerConfigConsensus) -> sha256::Hash
     .consensus_hash_sha256()
 }
 
-/// The type of networking `fedimintd` should use
-#[derive(Clone, Debug, Serialize, Deserialize, Default)]
-pub enum NetworkingStack {
-    #[default]
-    Tcp,
-    Iroh,
-}
-
 // FIXME: (@leonardo) Should this have another field for the expected transport
 // ? (e.g. clearnet/tor/...)
 #[derive(Debug, Clone, Serialize, Deserialize)]
@@ -217,10 +209,8 @@ pub struct ConfigGenSettings {
     pub p2p_url: Option<SafeUrl>,
     /// URL for our API connection
     pub api_url: Option<SafeUrl>,
-    /// Networking stack to use
-    /// TODO: we might make it a part of the API  request when ready
-    /// (move to `SetLocalParamsRequest`).
-    pub networking: NetworkingStack,
+    /// Enable iroh for networking
+    pub enable_iroh: bool,
     /// Set the params (if leader) or just the local params (if follower)
     pub modules: ServerModuleConfigGenParamsRegistry,
     /// Registry for config gen
diff --git a/fedimint-server/src/config/setup.rs b/fedimint-server/src/config/setup.rs
index 33ae3972600..de799776395 100644
--- a/fedimint-server/src/config/setup.rs
+++ b/fedimint-server/src/config/setup.rs
@@ -32,7 +32,7 @@ use tokio_rustls::rustls;
 use tracing::warn;
 
 use super::PeerEndpoints;
-use crate::config::{ConfigGenParams, ConfigGenSettings, NetworkingStack, PeerSetupCode};
+use crate::config::{ConfigGenParams, ConfigGenSettings, PeerSetupCode};
 use crate::net::api::HasApiContext;
 use crate::net::p2p_connector::gen_cert_and_key;
 
@@ -166,66 +166,60 @@ impl ISetupApi for SetupApi {
             "Local parameters have already been set"
         );
 
-        let lp = match self.settings.networking {
-            NetworkingStack::Tcp => {
-                let (tls_cert, tls_key) = gen_cert_and_key(&name)
-                    .expect("Failed to generate TLS for given guardian name");
-
-                LocalParams {
-                    auth,
-                    tls_key: Some(tls_key),
-                    iroh_api_sk: None,
-                    iroh_p2p_sk: None,
-                    endpoints: PeerEndpoints::Tcp {
-                        api_url: self
-                            .settings
-                            .api_url
-                            .clone()
-                            .ok_or_else(|| anyhow::format_err!("Api URL must be configured"))?,
-                        p2p_url: self
-                            .settings
-                            .p2p_url
-                            .clone()
-                            .ok_or_else(|| anyhow::format_err!("P2P URL must be configured"))?,
-
-                        cert: tls_cert.0,
-                    },
-                    name,
-                    federation_name,
-                }
+        let lp = if self.settings.enable_iroh {
+            warn!(target: LOG_SERVER, "Iroh support is experimental");
+
+            let iroh_api_sk = if let Ok(var) = std::env::var(FM_IROH_API_SECRET_KEY_OVERRIDE_ENV) {
+                SecretKey::from_str(&var)
+                    .with_context(|| format!("Parsing {FM_IROH_API_SECRET_KEY_OVERRIDE_ENV}"))?
+            } else {
+                SecretKey::generate(&mut OsRng)
+            };
+
+            let iroh_p2p_sk = if let Ok(var) = std::env::var(FM_IROH_P2P_SECRET_KEY_OVERRIDE_ENV) {
+                SecretKey::from_str(&var)
+                    .with_context(|| format!("Parsing {FM_IROH_P2P_SECRET_KEY_OVERRIDE_ENV}"))?
+            } else {
+                SecretKey::generate(&mut OsRng)
+            };
+
+            LocalParams {
+                auth,
+                tls_key: None,
+                iroh_api_sk: Some(iroh_api_sk.clone()),
+                iroh_p2p_sk: Some(iroh_p2p_sk.clone()),
+                endpoints: PeerEndpoints::Iroh {
+                    api_pk: iroh_api_sk.public(),
+                    p2p_pk: iroh_p2p_sk.public(),
+                },
+                name,
+                federation_name,
             }
-            NetworkingStack::Iroh => {
-                warn!(target: LOG_SERVER, "Iroh support is experimental");
-                let iroh_api_sk = if let Ok(var) =
-                    std::env::var(FM_IROH_API_SECRET_KEY_OVERRIDE_ENV)
-                {
-                    SecretKey::from_str(&var)
-                        .with_context(|| format!("Parsing {FM_IROH_API_SECRET_KEY_OVERRIDE_ENV}"))?
-                } else {
-                    SecretKey::generate(&mut OsRng)
-                };
-
-                let iroh_p2p_sk = if let Ok(var) =
-                    std::env::var(FM_IROH_P2P_SECRET_KEY_OVERRIDE_ENV)
-                {
-                    SecretKey::from_str(&var)
-                        .with_context(|| format!("Parsing {FM_IROH_P2P_SECRET_KEY_OVERRIDE_ENV}"))?
-                } else {
-                    SecretKey::generate(&mut OsRng)
-                };
-
-                LocalParams {
-                    auth,
-                    tls_key: None,
-                    iroh_api_sk: Some(iroh_api_sk.clone()),
-                    iroh_p2p_sk: Some(iroh_p2p_sk.clone()),
-                    endpoints: PeerEndpoints::Iroh {
-                        api_pk: iroh_api_sk.public(),
-                        p2p_pk: iroh_p2p_sk.public(),
-                    },
-                    name,
-                    federation_name,
-                }
+        } else {
+            let (tls_cert, tls_key) =
+                gen_cert_and_key(&name).expect("Failed to generate TLS for given guardian name");
+
+            LocalParams {
+                auth,
+                tls_key: Some(tls_key),
+                iroh_api_sk: None,
+                iroh_p2p_sk: None,
+                endpoints: PeerEndpoints::Tcp {
+                    api_url: self
+                        .settings
+                        .api_url
+                        .clone()
+                        .ok_or_else(|| anyhow::format_err!("Api URL must be configured"))?,
+                    p2p_url: self
+                        .settings
+                        .p2p_url
+                        .clone()
+                        .ok_or_else(|| anyhow::format_err!("P2P URL must be configured"))?,
+
+                    cert: tls_cert.0,
+                },
+                name,
+                federation_name,
             }
         };
 
diff --git a/fedimint-server/src/consensus/engine.rs b/fedimint-server/src/consensus/engine.rs
index 82d2e9342e3..8cdf7ec93b6 100644
--- a/fedimint-server/src/consensus/engine.rs
+++ b/fedimint-server/src/consensus/engine.rs
@@ -71,7 +71,7 @@ pub struct ConsensusEngine {
     pub ord_latency_sender: watch::Sender<Option<Duration>>,
     pub task_group: TaskGroup,
     pub data_dir: PathBuf,
-    pub checkpoint_retention: u64,
+    pub db_checkpoint_retention: u64,
 }
 
 impl ConsensusEngine {
@@ -536,8 +536,8 @@ impl ConsensusEngine {
                 // Validate that the directory is a session index
                 if let Ok(file_name) = checkpoint.file_name().into_string() {
                     if let Ok(session) = file_name.parse::<u64>() {
-                        if current_session >= self.checkpoint_retention
-                            && session < current_session - self.checkpoint_retention
+                        if current_session >= self.db_checkpoint_retention
+                            && session < current_session - self.db_checkpoint_retention
                         {
                             fs::remove_dir_all(checkpoint.path())?;
                         }
@@ -557,7 +557,7 @@ impl ConsensusEngine {
     fn checkpoint_database(&self, session_index: u64) {
         // If `checkpoint_retention` has been turned off, don't checkpoint the database
         // at all.
-        if self.checkpoint_retention == 0 {
+        if self.db_checkpoint_retention == 0 {
             return;
         }
 
@@ -592,11 +592,11 @@ impl ConsensusEngine {
         session_index: u64,
         checkpoint_dir: &Path,
     ) -> anyhow::Result<()> {
-        if self.checkpoint_retention > session_index {
+        if self.db_checkpoint_retention > session_index {
             return Ok(());
         }
 
-        let delete_session_index = session_index - self.checkpoint_retention;
+        let delete_session_index = session_index - self.db_checkpoint_retention;
         let checkpoint_to_delete = checkpoint_dir.join(delete_session_index.to_string());
         if checkpoint_to_delete.exists() {
             fs::remove_dir_all(checkpoint_to_delete)?;
diff --git a/fedimint-server/src/consensus/mod.rs b/fedimint-server/src/consensus/mod.rs
index 004b13a562b..39d3707f6d9 100644
--- a/fedimint-server/src/consensus/mod.rs
+++ b/fedimint-server/src/consensus/mod.rs
@@ -6,7 +6,6 @@ pub mod engine;
 pub mod transaction;
 
 use std::collections::BTreeMap;
-use std::env;
 use std::net::SocketAddr;
 use std::path::PathBuf;
 use std::sync::Arc;
@@ -46,7 +45,6 @@ use crate::config::{ServerConfig, ServerConfigLocal};
 use crate::consensus::api::{ConsensusApi, server_endpoints};
 use crate::consensus::engine::ConsensusEngine;
 use crate::db::verify_server_db_integrity_dbtx;
-use crate::envs::{FM_DB_CHECKPOINT_RETENTION_DEFAULT, FM_DB_CHECKPOINT_RETENTION_ENV};
 use crate::net::api::announcement::get_api_urls;
 use crate::net::api::{ApiSecrets, HasApiContext};
 use crate::net::p2p::P2PStatusReceivers;
@@ -70,6 +68,7 @@ pub async fn run(
     dyn_server_bitcoin_rpc: DynServerBitcoinRpc,
     ui_bind: SocketAddr,
     dashboard_ui_router: DashboardUiRouter,
+    db_checkpoint_retention: u64,
 ) -> anyhow::Result<()> {
     cfg.validate_config(&cfg.local.identity, &module_init_registry)?;
 
@@ -233,12 +232,6 @@ pub async fn run(
         );
     }
 
-    let checkpoint_retention: String = env::var(FM_DB_CHECKPOINT_RETENTION_ENV)
-        .unwrap_or(FM_DB_CHECKPOINT_RETENTION_DEFAULT.to_string());
-    let checkpoint_retention = checkpoint_retention.parse().unwrap_or_else(|_| {
-        panic!("FM_DB_CHECKPOINT_RETENTION_ENV var is invalid: {checkpoint_retention}")
-    });
-
     info!(target: LOG_CONSENSUS, "Starting Consensus Engine...");
 
     let api_urls = get_api_urls(&db, &cfg.consensus).await;
@@ -273,7 +266,7 @@ pub async fn run(
         modules: module_registry,
         task_group: task_group.clone(),
         data_dir,
-        checkpoint_retention,
+        db_checkpoint_retention,
     }
     .run()
     .await?;
diff --git a/fedimint-server/src/envs.rs b/fedimint-server/src/envs.rs
deleted file mode 100644
index 9141191f7db..00000000000
--- a/fedimint-server/src/envs.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-/// Environment variable for UI bind address
-pub const FM_UI_BIND_ENV: &str = "FM_UI_BIND";
-
-/// Environment variable for the session count determining when to cleanup old
-/// checkpoints.
-pub const FM_DB_CHECKPOINT_RETENTION_ENV: &str = "FM_DB_CHECKPOINT_RETENTION";
-
-/// Default number of checkpoints from the current session should be retained on
-/// disk.
-pub const FM_DB_CHECKPOINT_RETENTION_DEFAULT: u64 = 1;
-
-/// Use iroh for networking
-pub const FM_FORCE_IROH_ENV: &str = "FM_FORCE_IROH";
diff --git a/fedimint-server/src/lib.rs b/fedimint-server/src/lib.rs
index ff0b0ebae96..2393a0e4bb9 100644
--- a/fedimint-server/src/lib.rs
+++ b/fedimint-server/src/lib.rs
@@ -59,7 +59,6 @@ use crate::net::api::announcement::start_api_announcement_service;
 use crate::net::p2p::{ReconnectP2PConnections, p2p_status_channels};
 use crate::net::p2p_connector::{IP2PConnector, TlsTcpConnector};
 
-pub mod envs;
 pub mod metrics;
 
 /// The actual implementation of consensus
@@ -84,11 +83,12 @@ pub async fn run(
     settings: ConfigGenSettings,
     db: Database,
     code_version_str: String,
-    module_init_registry: &ServerModuleInitRegistry,
+    module_init_registry: ServerModuleInitRegistry,
     task_group: TaskGroup,
     bitcoin_rpc: DynServerBitcoinRpc,
     setup_ui_router: SetupUiRouter,
     dashboard_ui_router: DashboardUiRouter,
+    db_checkpoint_retention: u64,
 ) -> anyhow::Result<()> {
     let (cfg, connections, p2p_status_receivers) = match get_config(&data_dir)? {
         Some(cfg) => {
@@ -170,6 +170,7 @@ pub async fn run(
         bitcoin_rpc,
         settings.ui_bind,
         dashboard_ui_router,
+        db_checkpoint_retention,
     ))
     .await?;
 
diff --git a/fedimint-testing/src/federation.rs b/fedimint-testing/src/federation.rs
index f704297f46d..ba921a91235 100644
--- a/fedimint-testing/src/federation.rs
+++ b/fedimint-testing/src/federation.rs
@@ -305,6 +305,7 @@ impl FederationTestBuilder {
                     bitcoin_rpc_connection,
                     ui_bind,
                     Box::new(|_| axum::Router::new()),
+                    1,
                 ))
                 .await
                 .expect("Could not initialise consensus");
diff --git a/fedimintd/src/envs.rs b/fedimintd/src/envs.rs
index 12e48bb4862..83221bfa366 100644
--- a/fedimintd/src/envs.rs
+++ b/fedimintd/src/envs.rs
@@ -45,3 +45,10 @@ pub const FM_BITCOIND_URL_ENV: &str = "FM_BITCOIND_URL";
 
 // Env variable for the Esplora URL
 pub const FM_ESPLORA_URL_ENV: &str = "FM_ESPLORA_URL";
+
+/// Use iroh for networking
+pub const FM_ENABLE_IROH_ENV: &str = "FM_ENABLE_IROH";
+
+/// Environment variable for the session count determining when to cleanup old
+/// checkpoints.
+pub const FM_DB_CHECKPOINT_RETENTION_ENV: &str = "FM_DB_CHECKPOINT_RETENTION";
diff --git a/fedimintd/src/fedimintd.rs b/fedimintd/src/fedimintd.rs
index f553c26fb31..c0319698f17 100644
--- a/fedimintd/src/fedimintd.rs
+++ b/fedimintd/src/fedimintd.rs
@@ -17,7 +17,7 @@ use fedimint_core::envs::{
 };
 use fedimint_core::module::registry::ModuleRegistry;
 use fedimint_core::task::TaskGroup;
-use fedimint_core::util::{FmtCompactAnyhow as _, SafeUrl, handle_version_hash_command};
+use fedimint_core::util::{SafeUrl, handle_version_hash_command};
 use fedimint_core::{crit, timing};
 use fedimint_ln_common::config::{
     LightningGenParams, LightningGenParamsConsensus, LightningGenParamsLocal,
@@ -27,10 +27,10 @@ use fedimint_logging::{LOG_CORE, LOG_SERVER, TracingSetup};
 use fedimint_meta_server::{MetaGenParams, MetaInit};
 use fedimint_mint_server::MintInit;
 use fedimint_mint_server::common::config::{MintGenParams, MintGenParamsConsensus};
+use fedimint_rocksdb::RocksDb;
+use fedimint_server::config::ConfigGenSettings;
 use fedimint_server::config::io::DB_FILE;
-use fedimint_server::config::{ConfigGenSettings, NetworkingStack};
 use fedimint_server::core::{ServerModuleInit, ServerModuleInitRegistry};
-use fedimint_server::envs::FM_FORCE_IROH_ENV;
 use fedimint_server::net::api::ApiSecrets;
 use fedimint_server_bitcoin_rpc::bitcoind::BitcoindClient;
 use fedimint_server_bitcoin_rpc::esplora::EsploraClient;
@@ -41,15 +41,14 @@ use fedimint_wallet_server::WalletInit;
 use fedimint_wallet_server::common::config::{
     WalletGenParams, WalletGenParamsConsensus, WalletGenParamsLocal,
 };
-use futures::FutureExt;
 use tracing::{debug, error, info};
 
 use crate::default_esplora_server;
 use crate::envs::{
     FM_API_URL_ENV, FM_BIND_API_ENV, FM_BIND_METRCIS_ENV, FM_BIND_P2P_ENV,
     FM_BIND_TOKIO_CONSOLE_ENV, FM_BIND_UI_ENV, FM_BITCOIN_NETWORK_ENV, FM_BITCOIND_URL_ENV,
-    FM_DATA_DIR_ENV, FM_DISABLE_META_MODULE_ENV, FM_ESPLORA_URL_ENV, FM_FORCE_API_SECRETS_ENV,
-    FM_P2P_URL_ENV,
+    FM_DATA_DIR_ENV, FM_DB_CHECKPOINT_RETENTION_ENV, FM_DISABLE_META_MODULE_ENV,
+    FM_ENABLE_IROH_ENV, FM_ESPLORA_URL_ENV, FM_FORCE_API_SECRETS_ENV, FM_P2P_URL_ENV,
 };
 use crate::fedimintd::metrics::APP_START_TS;
 
@@ -121,6 +120,9 @@ struct ServerOpts {
     #[arg(long, env = FM_API_URL_ENV)]
     api_url: Option<SafeUrl>,
 
+    #[arg(long, env = FM_ENABLE_IROH_ENV)]
+    enable_iroh: bool,
+
     /// Enable tokio console logging
     #[arg(long, env = FM_BIND_TOKIO_CONSOLE_ENV)]
     bind_tokio_console: Option<SocketAddr>,
@@ -133,6 +135,10 @@ struct ServerOpts {
     #[arg(long, env = FM_BIND_METRCIS_ENV)]
     bind_metrics: Option<SocketAddr>,
 
+    /// Number of checkpoints from the current session to retain on disk
+    #[arg(long, env = FM_DB_CHECKPOINT_RETENTION_ENV, default_value = "1")]
+    db_checkpoint_retention: u64,
+
     /// Comma separated list of API secrets.
     ///
     /// Setting it will enforce API authentication and make the Federation
@@ -377,43 +383,70 @@ impl Fedimintd {
 
     /// Block thread and run a Fedimintd server
     pub async fn run(self) -> ! {
+        let timing_total_runtime = timing::TimeReporter::new("total-runtime").info();
+
         let root_task_group = TaskGroup::new();
-        root_task_group.install_kill_handler();
 
-        let timing_total_runtime = timing::TimeReporter::new("total-runtime").info();
+        if let Some(bind_metrics) = self.opts.bind_metrics.as_ref() {
+            root_task_group.spawn_cancellable(
+                "metrics-server",
+                fedimint_metrics::run_api_server(*bind_metrics, root_task_group.clone()),
+            );
+        }
 
-        let task_group = root_task_group.clone();
-        root_task_group.spawn_cancellable("main", async move {
-            match run(
-                self.opts,
-                &task_group,
-                self.server_gens,
-                self.server_gen_params,
-                self.code_version_str,
-            )
+        let settings = ConfigGenSettings {
+            p2p_bind: self.opts.bind_p2p,
+            api_bind: self.opts.bind_api,
+            ui_bind: self.opts.bind_ui,
+            p2p_url: self.opts.p2p_url,
+            api_url: self.opts.api_url,
+            enable_iroh: self.opts.enable_iroh,
+            modules: self.server_gen_params.clone(),
+            registry: self.server_gens.clone(),
+        };
+
+        let db = Database::new(
+            RocksDb::open(self.opts.data_dir.join(DB_FILE))
+                .await
+                .unwrap(),
+            ModuleRegistry::default(),
+        );
+
+        let dyn_server_bitcoin_rpc = match (
+            self.opts.bitcoind_url.as_ref(),
+            self.opts.esplora_url.as_ref(),
+        ) {
+            (Some(url), None) => BitcoindClient::new(url).unwrap().into_dyn(),
+            (None, Some(url)) => EsploraClient::new(url).unwrap().into_dyn(),
+            _ => unreachable!("ArgGroup already enforced XOR relation"),
+        };
+
+        root_task_group.install_kill_handler();
+
+        fedimint_server::run(
+            self.opts.data_dir,
+            self.opts.force_api_secrets,
+            settings,
+            db,
+            self.code_version_str,
+            self.server_gens,
+            root_task_group.clone(),
+            dyn_server_bitcoin_rpc,
+            Box::new(fedimint_server_ui::setup::router),
+            Box::new(fedimint_server_ui::dashboard::router),
+            self.opts.db_checkpoint_retention,
+        )
+        .await
+        .inspect_err(|e| crit!(target: LOG_SERVER, ?e, "Main task returned error"))
+        .ok();
+
+        info!(target: LOG_CORE, "Awaiting shutdown of root task group");
+
+        root_task_group
+            .join_all(Some(SHUTDOWN_TIMEOUT))
             .await
-            {
-                Ok(()) => {}
-                Err(error) => {
-                    crit!(target: LOG_SERVER, err = %error.fmt_compact_anyhow(), "Main task returned error, shutting down");
-                    task_group.shutdown();
-                }
-            }
-        });
-
-        let shutdown_future = root_task_group
-            .make_handle()
-            .make_shutdown_rx()
-            .then(|()| async {
-                info!(target: LOG_CORE, "Shutdown called");
-            });
-
-        shutdown_future.await;
-        debug!(target: LOG_CORE, "Terminating main task");
-
-        if let Err(err) = root_task_group.join_all(Some(SHUTDOWN_TIMEOUT)).await {
-            error!(target: LOG_CORE, ?err, "Error while shutting down task group");
-        }
+            .inspect_err(|e| error!(target: LOG_CORE, ?e, "Error while shutting down task group"))
+            .ok();
 
         debug!(target: LOG_CORE, "Shutdown complete");
 
@@ -425,59 +458,3 @@ impl Fedimintd {
         std::process::exit(-1);
     }
 }
-
-async fn run(
-    opts: ServerOpts,
-    task_group: &TaskGroup,
-    module_inits: ServerModuleInitRegistry,
-    module_inits_params: ServerModuleConfigGenParamsRegistry,
-    code_version_str: String,
-) -> anyhow::Result<()> {
-    if let Some(bind_metrics) = opts.bind_metrics.as_ref() {
-        task_group.spawn_cancellable(
-            "metrics-server",
-            fedimint_metrics::run_api_server(*bind_metrics, task_group.clone()),
-        );
-    }
-
-    // TODO: meh, move, refactor
-    let settings = ConfigGenSettings {
-        p2p_bind: opts.bind_p2p,
-        api_bind: opts.bind_api,
-        ui_bind: opts.bind_ui,
-        p2p_url: opts.p2p_url,
-        api_url: opts.api_url,
-        modules: module_inits_params.clone(),
-        registry: module_inits.clone(),
-        networking: if is_env_var_set(FM_FORCE_IROH_ENV) {
-            NetworkingStack::Iroh
-        } else {
-            NetworkingStack::default()
-        },
-    };
-
-    let db = Database::new(
-        fedimint_rocksdb::RocksDb::open(opts.data_dir.join(DB_FILE)).await?,
-        ModuleRegistry::default(),
-    );
-
-    let dyn_server_bitcoin_rpc = match (opts.bitcoind_url.as_ref(), opts.esplora_url.as_ref()) {
-        (Some(url), None) => BitcoindClient::new(url)?.into_dyn(),
-        (None, Some(url)) => EsploraClient::new(url)?.into_dyn(),
-        _ => unreachable!("ArgGroup already enforced XOR relation"),
-    };
-
-    Box::pin(fedimint_server::run(
-        opts.data_dir,
-        opts.force_api_secrets,
-        settings,
-        db,
-        code_version_str,
-        &module_inits,
-        task_group.clone(),
-        dyn_server_bitcoin_rpc,
-        Box::new(fedimint_server_ui::setup::router),
-        Box::new(fedimint_server_ui::dashboard::router),
-    ))
-    .await
-}


Reviews:
user: login: elsirion
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T09:33:27Z
user: login: elsirion
body: Let's figure out the problem with linting separately.
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T09:39:06Z
user: login: dpc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-28T18:24:58Z
user: login: dpc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-28T18:38:57Z
user: login: joschisan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T11:08:17Z
user: login: dpc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T15:53:05Z

Review comments:
diff_hunk: @@ -121,6 +120,9 @@ struct ServerOpts {
     #[arg(long, env = FM_API_URL_ENV)]
     api_url: Option<SafeUrl>,
 
+    #[arg(long, env = FM_ENABLE_IROH_ENV)]
+    enable_iroh: bool,
path: fedimintd/src/fedimintd.rs
user: login: elsirion
body: I wonder if clap accepts `--enable-iroh=false` if we eventually make it the default. Worst case we can just switch to `--disable-iroh` I guess.
created_at: 2025-04-23T09:33:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -379,43 +379,71 @@ impl Fedimintd {
 
     /// Block thread and run a Fedimintd server
     pub async fn run(self) -> ! {
+        let timing_total_runtime = timing::TimeReporter::new("total-runtime").info();
+
         let root_task_group = TaskGroup::new();
-        root_task_group.install_kill_handler();
 
-        let timing_total_runtime = timing::TimeReporter::new("total-runtime").info();
+        if let Some(bind_metrics) = self.opts.bind_metrics.as_ref() {
+            root_task_group.spawn_cancellable(
+                "metrics-server",
+                fedimint_metrics::run_api_server(*bind_metrics, root_task_group.clone()),
+            );
+        }
 
-        let task_group = root_task_group.clone();
-        root_task_group.spawn_cancellable("main", async move {
-            match run(
-                self.opts,
-                &task_group,
-                self.server_gens,
-                self.server_gen_params,
-                self.code_version_str,
-            )
path: fedimintd/src/fedimintd.rs
user: login: elsirion
body: We probably ran some API server in parallel at this level in the past, now running in a separate task seems redundant indeed.
created_at: 2025-04-23T09:36:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -135,6 +135,10 @@ struct ServerOpts {
     #[arg(long, env = FM_BIND_METRCIS_ENV)]
     bind_metrics: Option<SocketAddr>,
 
+    /// Number of checkpoints from the current session to retain on disk
+    #[arg(long, env = FM_DB_CHECKPOINT_RETENTION_ENV, default_value = "1")]
+    db_checkpoint_retention: u64,
path: fedimintd/src/fedimintd.rs
user: login: elsirion
body: :tada: 
created_at: 2025-04-23T09:38:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -437,9 +437,7 @@ impl Fedimintd {
             self.opts.db_checkpoint_retention,
         )
         .await
-        .inspect_err(
-            |e| crit!(target: LOG_SERVER, e = %e.fmt_compact_anyhow(), "Main task returned error"),
-        )
+        .inspect_err(|e| crit!(target: LOG_SERVER, ?e, "Main task returned error"))
path: fedimintd/src/fedimintd.rs
user: login: elsirion
body: This looks like the opposite of a fix tbh.
created_at: 2025-04-23T09:38:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -217,10 +209,8 @@ pub struct ConfigGenSettings {
     pub p2p_url: Option<SafeUrl>,
     /// URL for our API connection
     pub api_url: Option<SafeUrl>,
-    /// Networking stack to use
-    /// TODO: we might make it a part of the API  request when ready
-    /// (move to `SetLocalParamsRequest`).
-    pub networking: NetworkingStack,
+    /// Enable iroh for networking
+    pub enable_iroh: bool,
path: fedimint-server/src/config/mod.rs
user: login: dpc
body: Why turn a proper enum in a bool. Meh.
created_at: 2025-04-28T18:24:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -217,10 +209,8 @@ pub struct ConfigGenSettings {
     pub p2p_url: Option<SafeUrl>,
     /// URL for our API connection
     pub api_url: Option<SafeUrl>,
-    /// Networking stack to use
-    /// TODO: we might make it a part of the API  request when ready
-    /// (move to `SetLocalParamsRequest`).
-    pub networking: NetworkingStack,
+    /// Enable iroh for networking
+    pub enable_iroh: bool,
path: fedimint-server/src/config/mod.rs
user: login: dpc
body: Why would anyone wants a bool instead of enum? It's just way less informative than enum, nothing gets simpler with bool. The only reason I don't always have enums for every boolean choice is that I'm just too lazy. If you impl `FromStr` on it, you can even accept it in clap directly, so you could have `--networking=iroh`, with a default impl on tcp, that we would switch in the future. @joschisan @elsirion 
created_at: 2025-04-28T18:38:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -217,10 +209,8 @@ pub struct ConfigGenSettings {
     pub p2p_url: Option<SafeUrl>,
     /// URL for our API connection
     pub api_url: Option<SafeUrl>,
-    /// Networking stack to use
-    /// TODO: we might make it a part of the API  request when ready
-    /// (move to `SetLocalParamsRequest`).
-    pub networking: NetworkingStack,
+    /// Enable iroh for networking
+    pub enable_iroh: bool,
path: fedimint-server/src/config/mod.rs
user: login: joschisan
body: Well the thought here is that the place where the setting is used in fedimint-server has the same name and type as the flag and the corresponding env variable. So it's a more obvious where it's coming from. 
created_at: 2025-04-29T11:08:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -217,10 +209,8 @@ pub struct ConfigGenSettings {
     pub p2p_url: Option<SafeUrl>,
     /// URL for our API connection
     pub api_url: Option<SafeUrl>,
-    /// Networking stack to use
-    /// TODO: we might make it a part of the API  request when ready
-    /// (move to `SetLocalParamsRequest`).
-    pub networking: NetworkingStack,
+    /// Enable iroh for networking
+    pub enable_iroh: bool,
path: fedimint-server/src/config/mod.rs
user: login: dpc
body: @joschisan If you implemented `FromStr` it would be the same from clap and env var all the way. And it wouldn't be a bool.

Generally for "rationale" just google "boolean trap" e.g. https://katafrakt.me/2024/11/09/booleans-are-a-trap/

Bool smell, why do we even need them in Rust? 
created_at: 2025-04-29T15:53:05Z
author_association: CONTRIBUTOR

PR comments:
user: login: elsirion
created_at: 2025-04-28T17:09:06Z
body: @dpc suspects this to cause problems 
author_association: CONTRIBUTOR
user: login: dpc
created_at: 2025-04-28T18:58:40Z
body: > @dpc suspects this to cause problems

![image](https://github.com/user-attachments/assets/66c4b20e-f9dc-4988-b376-9d4f42edc557)

![image](https://github.com/user-attachments/assets/88be5b7f-218c-497a-84bb-eb6656ad0634)

author_association: CONTRIBUTOR