lib.rs
1 #![allow(where_clauses_object_safety)] // https://github.com/dtolnay/async-trait/issues/228 2 extern crate fedimint_core; 3 4 use std::fs; 5 use std::path::{Path, PathBuf}; 6 7 use config::io::{read_server_config, PLAINTEXT_PASSWORD}; 8 use config::ServerConfig; 9 use fedimint_aead::random_salt; 10 use fedimint_core::config::ServerModuleInitRegistry; 11 use fedimint_core::db::Database; 12 use fedimint_core::epoch::ConsensusItem; 13 use fedimint_core::task::TaskGroup; 14 use fedimint_core::util::write_new; 15 use fedimint_logging::LOG_CONSENSUS; 16 use tracing::info; 17 18 use crate::config::api::{ConfigGenApi, ConfigGenSettings}; 19 use crate::config::io::{write_server_config, SALT_FILE}; 20 use crate::metrics::initialize_gauge_metrics; 21 use crate::net::api::RpcHandlerCtx; 22 use crate::net::connect::TlsTcpConnector; 23 24 pub mod envs; 25 pub mod metrics; 26 27 pub mod atomic_broadcast; 28 29 /// The actual implementation of consensus 30 pub mod consensus; 31 32 /// Networking for mint-to-mint and client-to-mint communiccation 33 pub mod net; 34 35 /// Fedimint toplevel config 36 pub mod config; 37 38 /// Implementation of multiplexed peer connections 39 pub mod multiplexed; 40 41 pub async fn run( 42 data_dir: PathBuf, 43 settings: ConfigGenSettings, 44 db: Database, 45 version_hash: String, 46 module_init_registry: &ServerModuleInitRegistry, 47 task_group: TaskGroup, 48 ) -> anyhow::Result<()> { 49 let cfg = match get_config(&data_dir).await? { 50 Some(cfg) => cfg, 51 None => { 52 run_config_gen( 53 data_dir, 54 settings, 55 db.clone(), 56 version_hash, 57 task_group.make_subgroup(), 58 ) 59 .await? 60 } 61 }; 62 63 let decoders = module_init_registry.decoders_strict( 64 cfg.consensus 65 .modules 66 .iter() 67 .map(|(id, config)| (*id, &config.kind)), 68 )?; 69 70 let db = db.with_decoders(decoders); 71 72 initialize_gauge_metrics(&db).await; 73 74 consensus::run(cfg, db, module_init_registry.clone(), &task_group).await?; 75 76 info!(target: LOG_CONSENSUS, "Shutting down tasks"); 77 78 task_group.shutdown(); 79 80 Ok(()) 81 } 82 83 pub async fn get_config(data_dir: &Path) -> anyhow::Result<Option<ServerConfig>> { 84 // Attempt get the config with local password, otherwise start config gen 85 if let Ok(password) = fs::read_to_string(data_dir.join(PLAINTEXT_PASSWORD)) { 86 return Ok(Some(read_server_config(&password, data_dir.to_owned())?)); 87 } 88 89 Ok(None) 90 } 91 92 pub async fn run_config_gen( 93 data_dir: PathBuf, 94 settings: ConfigGenSettings, 95 db: Database, 96 version_hash: String, 97 mut task_group: TaskGroup, 98 ) -> anyhow::Result<ServerConfig> { 99 info!(target: LOG_CONSENSUS, "Starting config gen"); 100 101 initialize_gauge_metrics(&db).await; 102 103 let (cfg_sender, mut cfg_receiver) = tokio::sync::mpsc::channel(1); 104 105 let config_gen = ConfigGenApi::new( 106 settings.clone(), 107 db.clone(), 108 cfg_sender, 109 &mut task_group, 110 version_hash.clone(), 111 ); 112 113 let mut rpc_module = RpcHandlerCtx::new_module(config_gen); 114 115 net::api::attach_endpoints(&mut rpc_module, config::api::server_endpoints(), None); 116 117 let api_handler = net::api::spawn("config-gen", &settings.api_bind, rpc_module, 10).await; 118 119 let cfg = cfg_receiver.recv().await.expect("should not close"); 120 121 api_handler 122 .stop() 123 .expect("Config api should still be running"); 124 125 api_handler.stopped().await; 126 127 // TODO: Make writing password optional 128 write_new(data_dir.join(PLAINTEXT_PASSWORD), &cfg.private.api_auth.0)?; 129 write_new(data_dir.join(SALT_FILE), random_salt())?; 130 write_server_config( 131 &cfg, 132 data_dir.clone(), 133 &cfg.private.api_auth.0, 134 &settings.registry, 135 )?; 136 137 Ok(cfg) 138 }