mod.rs
1 use std::collections::{BTreeMap, BTreeSet, HashMap}; 2 use std::env; 3 use std::net::SocketAddr; 4 use std::time::Duration; 5 6 use anyhow::{bail, format_err}; 7 use fedimint_core::admin_client::ConfigGenParamsConsensus; 8 pub use fedimint_core::config::{ 9 serde_binary_human_readable, ClientConfig, DkgError, DkgPeerMsg, DkgResult, FederationId, 10 GlobalClientConfig, JsonWithKind, ModuleInitRegistry, PeerUrl, ServerModuleConfig, 11 ServerModuleConsensusConfig, ServerModuleInitRegistry, TypedServerModuleConfig, 12 }; 13 use fedimint_core::core::{ModuleInstanceId, ModuleKind, MODULE_INSTANCE_ID_GLOBAL}; 14 use fedimint_core::envs::is_running_in_test_env; 15 use fedimint_core::invite_code::InviteCode; 16 use fedimint_core::module::{ 17 ApiAuth, ApiVersion, CoreConsensusVersion, DynServerModuleInit, MultiApiVersion, PeerHandle, 18 SupportedApiVersionsSummary, SupportedCoreApiVersions, CORE_CONSENSUS_VERSION, 19 }; 20 use fedimint_core::net::peers::{IMuxPeerConnections, IPeerConnections, PeerConnections}; 21 use fedimint_core::task::{timeout, Cancelled, Elapsed, TaskGroup}; 22 use fedimint_core::{secp256k1, timing, PeerId}; 23 use fedimint_logging::{LOG_NET_PEER, LOG_NET_PEER_DKG}; 24 use futures::future::join_all; 25 use rand::rngs::OsRng; 26 use secp256k1::{PublicKey, Secp256k1, SecretKey}; 27 use serde::de::DeserializeOwned; 28 use serde::{Deserialize, Serialize}; 29 use tokio_rustls::rustls; 30 use tracing::{error, info}; 31 32 use crate::config::api::ConfigGenParamsLocal; 33 use crate::config::distributedgen::{DkgRunner, PeerHandleOps}; 34 use crate::envs::FM_MAX_CLIENT_CONNECTIONS_ENV; 35 use crate::fedimint_core::encoding::Encodable; 36 use crate::fedimint_core::NumPeersExt; 37 use crate::multiplexed::PeerConnectionMultiplexer; 38 use crate::net::connect::{dns_sanitize, Connector, TlsConfig}; 39 use crate::net::peers::{DelayCalculator, NetworkConfig}; 40 use crate::net::peers_reliable::ReconnectPeerConnectionsReliable; 41 use crate::TlsTcpConnector; 42 43 pub mod api; 44 pub mod distributedgen; 45 pub mod io; 46 47 /// The default maximum open connections the API can handle 48 const DEFAULT_MAX_CLIENT_CONNECTIONS: u32 = 1000; 49 // if all nodes are correct the session will take 45 to 60 seconds. The 50 // more nodes go offline the longer the session will take to complete. 51 const DEFAULT_BROADCAST_EXPECTED_ROUNDS_PER_SESSION: u16 = 45 * 20; 52 const DEFAULT_BROADCAST_ROUND_DELAY_MS: u16 = 50; 53 const DEFAULT_BROADCAST_MAX_ROUNDS_PER_SESSION: u16 = 5000; 54 55 /// Set of consensus broadcast settings that results in around 10s session time, 56 /// that is useful for testing purposes. Not that all the values here together 57 /// need to satisfy bunch of constrains in alephbft, so tweaking them 58 /// separately will most probably result in panics and other misbehavior. 59 const DEFAULT_TEST_BROADCAST_EXPECTED_ROUNDS_PER_SESSION: u16 = 3 * 20; 60 const DEFAULT_TEST_BROADCAST_ROUND_DELAY_MS: u16 = 50; 61 const DEFAULT_TEST_BROADCAST_MAX_ROUNDS_PER_SESSION: u16 = 2700; 62 63 #[derive(Debug, Clone, Serialize, Deserialize)] 64 /// All the serializable configuration for the fedimint server 65 pub struct ServerConfig { 66 /// Contains all configuration that needs to be the same for every server 67 pub consensus: ServerConfigConsensus, 68 /// Contains all configuration that is locally configurable and not secret 69 pub local: ServerConfigLocal, 70 /// Contains all configuration that will be encrypted such as private key 71 /// material 72 pub private: ServerConfigPrivate, 73 } 74 75 impl ServerConfig { 76 pub fn iter_module_instances( 77 &self, 78 ) -> impl Iterator<Item = (ModuleInstanceId, &ModuleKind)> + '_ { 79 self.consensus.iter_module_instances() 80 } 81 82 pub(crate) fn supported_api_versions_summary( 83 modules: &BTreeMap<ModuleInstanceId, ServerModuleConsensusConfig>, 84 module_inits: &ServerModuleInitRegistry, 85 ) -> SupportedApiVersionsSummary { 86 SupportedApiVersionsSummary { 87 core: Self::supported_api_versions(), 88 modules: modules 89 .iter() 90 .map(|(&id, config)| { 91 ( 92 id, 93 module_inits 94 .get(&config.kind) 95 .expect("missing module kind gen") 96 .supported_api_versions(), 97 ) 98 }) 99 .collect(), 100 } 101 } 102 } 103 104 #[derive(Debug, Clone, Serialize, Deserialize)] 105 pub struct ServerConfigPrivate { 106 /// Secret API auth string 107 pub api_auth: ApiAuth, 108 /// Secret key for TLS communication, required for peer authentication 109 #[serde(with = "serde_tls_key")] 110 pub tls_key: rustls::PrivateKey, 111 /// Secret key for the atomic broadcast to sign messages 112 pub broadcast_secret_key: SecretKey, 113 /// Secret material from modules 114 pub modules: BTreeMap<ModuleInstanceId, JsonWithKind>, 115 } 116 117 #[derive(Debug, Clone, Serialize, Deserialize, Encodable)] 118 pub struct ServerConfigConsensus { 119 /// The version of the binary code running 120 pub code_version: String, 121 /// Agreed on core consensus version 122 pub version: CoreConsensusVersion, 123 /// Public keys for the atomic broadcast to authenticate messages 124 pub broadcast_public_keys: BTreeMap<PeerId, PublicKey>, 125 /// Determines how long a session is expected to run. Has to be less than 126 /// 1000. 127 pub broadcast_expected_rounds_per_session: u16, 128 /// Maximum number of rounds permitted per session. 129 pub broadcast_max_rounds_per_session: u16, 130 /// Network addresses and names for all peer APIs 131 pub api_endpoints: BTreeMap<PeerId, PeerUrl>, 132 /// Certs for TLS communication, required for peer authentication 133 #[serde(with = "serde_tls_cert_map")] 134 pub tls_certs: BTreeMap<PeerId, rustls::Certificate>, 135 /// All configuration that needs to be the same for modules 136 pub modules: BTreeMap<ModuleInstanceId, ServerModuleConsensusConfig>, 137 #[encodable_ignore] 138 // FIXME: Make modules encodable or we will not check module keys 139 /// Human readable representation of [`Self::modules`] 140 pub modules_json: BTreeMap<ModuleInstanceId, JsonWithKind>, 141 /// Additional config the federation wants to transmit to the clients 142 pub meta: BTreeMap<String, String>, 143 } 144 145 #[derive(Debug, Clone, Serialize, Deserialize)] 146 pub struct ServerConfigLocal { 147 /// Network addresses and names for all p2p connections 148 pub p2p_endpoints: BTreeMap<PeerId, PeerUrl>, 149 /// Our peer id (generally should not change) 150 pub identity: PeerId, 151 /// Our bind address for communicating with peers 152 pub fed_bind: SocketAddr, 153 /// Our bind address for our API endpoints 154 pub api_bind: SocketAddr, 155 /// How many API connections we will accept 156 pub max_connections: u32, 157 /// Influences the atomic broadcast latency, should be higher than the 158 /// expected latency between peers so everyone can get proposed consensus 159 /// items confirmed. This is only relevant for byzantine faults. 160 /// 161 /// If you are changing this value you likely also want to change 162 /// [`ServerConfigConsensus::broadcast_expected_rounds_per_session`]. To 163 /// keep the session time constant these two have to behave inversely 164 /// proportional. 165 pub broadcast_round_delay_ms: u16, 166 /// Non-consensus, non-private configuration from modules 167 pub modules: BTreeMap<ModuleInstanceId, JsonWithKind>, 168 } 169 170 #[derive(Debug, Clone)] 171 /// All the parameters necessary for generating the `ServerConfig` during setup 172 /// 173 /// * Guardians can create the parameters using a setup UI or CLI tool 174 /// * Used for distributed or trusted config generation 175 pub struct ConfigGenParams { 176 pub local: ConfigGenParamsLocal, 177 pub consensus: ConfigGenParamsConsensus, 178 } 179 180 impl ServerConfigConsensus { 181 pub fn iter_module_instances( 182 &self, 183 ) -> impl Iterator<Item = (ModuleInstanceId, &ModuleKind)> + '_ { 184 self.modules.iter().map(|(k, v)| (*k, &v.kind)) 185 } 186 187 pub fn to_client_config( 188 &self, 189 module_config_gens: &ModuleInitRegistry<DynServerModuleInit>, 190 ) -> Result<ClientConfig, anyhow::Error> { 191 let client = ClientConfig { 192 global: GlobalClientConfig { 193 api_endpoints: self.api_endpoints.clone(), 194 consensus_version: self.version, 195 meta: self.meta.clone(), 196 }, 197 modules: self 198 .modules 199 .iter() 200 .map(|(k, v)| { 201 let gen = module_config_gens 202 .get(&v.kind) 203 .ok_or_else(|| format_err!("Module gen kind={} not found", v.kind))?; 204 Ok((*k, gen.get_client_config(*k, v)?)) 205 }) 206 .collect::<anyhow::Result<BTreeMap<_, _>>>()?, 207 }; 208 Ok(client) 209 } 210 } 211 212 impl ServerConfig { 213 /// Api versions supported by this server 214 pub fn supported_api_versions() -> SupportedCoreApiVersions { 215 SupportedCoreApiVersions { 216 core_consensus: CORE_CONSENSUS_VERSION, 217 api: MultiApiVersion::try_from_iter([ApiVersion { major: 0, minor: 2 }]) 218 .expect("not version conflicts"), 219 } 220 } 221 /// Creates a new config from the results of a trusted or distributed key 222 /// setup 223 pub fn from( 224 params: ConfigGenParams, 225 identity: PeerId, 226 broadcast_public_keys: BTreeMap<PeerId, PublicKey>, 227 broadcast_secret_key: SecretKey, 228 modules: BTreeMap<ModuleInstanceId, ServerModuleConfig>, 229 version_hash: String, 230 ) -> Self { 231 let private = ServerConfigPrivate { 232 api_auth: params.local.api_auth.clone(), 233 tls_key: params.local.our_private_key.clone(), 234 broadcast_secret_key, 235 modules: Default::default(), 236 }; 237 let local = ServerConfigLocal { 238 p2p_endpoints: params.p2p_urls(), 239 identity, 240 fed_bind: params.local.p2p_bind, 241 api_bind: params.local.api_bind, 242 max_connections: DEFAULT_MAX_CLIENT_CONNECTIONS, 243 broadcast_round_delay_ms: if is_running_in_test_env() { 244 DEFAULT_TEST_BROADCAST_ROUND_DELAY_MS 245 } else { 246 DEFAULT_BROADCAST_ROUND_DELAY_MS 247 }, 248 modules: Default::default(), 249 }; 250 let consensus = ServerConfigConsensus { 251 code_version: version_hash, 252 version: CORE_CONSENSUS_VERSION, 253 broadcast_public_keys, 254 broadcast_expected_rounds_per_session: if is_running_in_test_env() { 255 DEFAULT_TEST_BROADCAST_EXPECTED_ROUNDS_PER_SESSION 256 } else { 257 DEFAULT_BROADCAST_EXPECTED_ROUNDS_PER_SESSION 258 }, 259 broadcast_max_rounds_per_session: if is_running_in_test_env() { 260 DEFAULT_TEST_BROADCAST_MAX_ROUNDS_PER_SESSION 261 } else { 262 DEFAULT_BROADCAST_MAX_ROUNDS_PER_SESSION 263 }, 264 api_endpoints: params.api_urls(), 265 tls_certs: params.tls_certs(), 266 modules: Default::default(), 267 modules_json: Default::default(), 268 meta: params.consensus.meta, 269 }; 270 let mut cfg = Self { 271 consensus, 272 local, 273 private, 274 }; 275 cfg.add_modules(modules); 276 cfg 277 } 278 279 pub fn get_invite_code(&self) -> InviteCode { 280 InviteCode::new( 281 self.consensus.api_endpoints[&self.local.identity] 282 .url 283 .clone(), 284 self.local.identity, 285 FederationId(self.consensus.api_endpoints.consensus_hash()), 286 ) 287 } 288 289 pub fn get_federation_id(&self) -> FederationId { 290 FederationId(self.consensus.api_endpoints.consensus_hash()) 291 } 292 293 pub fn add_modules(&mut self, modules: BTreeMap<ModuleInstanceId, ServerModuleConfig>) { 294 for (name, config) in modules.into_iter() { 295 let ServerModuleConfig { 296 local, 297 private, 298 consensus, 299 consensus_json, 300 } = config; 301 302 self.local.modules.insert(name, local); 303 self.private.modules.insert(name, private); 304 self.consensus.modules.insert(name, consensus); 305 self.consensus.modules_json.insert(name, consensus_json); 306 } 307 } 308 309 /// Constructs a module config by name 310 pub fn get_module_config_typed<T: TypedServerModuleConfig>( 311 &self, 312 id: ModuleInstanceId, 313 ) -> anyhow::Result<T> { 314 let local = Self::get_module_cfg_by_instance_id(&self.local.modules, id)?; 315 let private = Self::get_module_cfg_by_instance_id(&self.private.modules, id)?; 316 let consensus = self 317 .consensus 318 .modules 319 .get(&id) 320 .ok_or_else(|| format_err!("Module {id} not found"))? 321 .clone(); 322 let consensus_json = Self::get_module_cfg_by_instance_id(&self.consensus.modules_json, id)?; 323 let module = ServerModuleConfig::from(local, private, consensus, consensus_json); 324 325 module.to_typed() 326 } 327 pub fn get_module_id_by_kind( 328 &self, 329 kind: impl Into<ModuleKind>, 330 ) -> anyhow::Result<ModuleInstanceId> { 331 let kind = kind.into(); 332 Ok(*self 333 .consensus 334 .modules 335 .iter() 336 .find(|(_, v)| v.kind == kind) 337 .ok_or_else(|| format_err!("Module {kind} not found"))? 338 .0) 339 } 340 341 /// Constructs a module config by id 342 pub fn get_module_config(&self, id: ModuleInstanceId) -> anyhow::Result<ServerModuleConfig> { 343 let local = Self::get_module_cfg_by_instance_id(&self.local.modules, id)?; 344 let private = Self::get_module_cfg_by_instance_id(&self.private.modules, id)?; 345 let consensus = self 346 .consensus 347 .modules 348 .get(&id) 349 .ok_or_else(|| format_err!("Module {id} not found"))? 350 .clone(); 351 let consensus_json = Self::get_module_cfg_by_instance_id(&self.consensus.modules_json, id)?; 352 Ok(ServerModuleConfig::from( 353 local, 354 private, 355 consensus, 356 consensus_json, 357 )) 358 } 359 360 fn get_module_cfg_by_instance_id( 361 json: &BTreeMap<ModuleInstanceId, JsonWithKind>, 362 id: ModuleInstanceId, 363 ) -> anyhow::Result<JsonWithKind> { 364 Ok(json 365 .get(&id) 366 .ok_or_else(|| format_err!("Module {id} not found")) 367 .cloned()? 368 .with_fixed_empty_value()) 369 } 370 371 pub fn validate_config( 372 &self, 373 identity: &PeerId, 374 module_config_gens: &ServerModuleInitRegistry, 375 ) -> anyhow::Result<()> { 376 let peers = self.local.p2p_endpoints.clone(); 377 let consensus = self.consensus.clone(); 378 let private = self.private.clone(); 379 380 let my_public_key = private.broadcast_secret_key.public_key(&Secp256k1::new()); 381 382 if Some(&my_public_key) != consensus.broadcast_public_keys.get(identity) { 383 bail!("Broadcast secret key doesn't match corresponding public key"); 384 } 385 if peers.keys().max().copied().map(|id| id.to_usize()) != Some(peers.len() - 1) { 386 bail!("Peer ids are not indexed from 0"); 387 } 388 if peers.keys().min().copied() != Some(PeerId::from(0)) { 389 bail!("Peer ids are not indexed from 0"); 390 } 391 392 for (module_id, module_kind) in self 393 .consensus 394 .modules 395 .iter() 396 .map(|(id, config)| Ok((*id, config.kind.clone()))) 397 .collect::<anyhow::Result<BTreeSet<_>>>()? 398 .iter() 399 { 400 module_config_gens 401 .get(module_kind) 402 .ok_or_else(|| format_err!("module config gen not found {module_kind}"))? 403 .validate_config(identity, self.get_module_config(*module_id)?)?; 404 } 405 406 Ok(()) 407 } 408 409 pub fn trusted_dealer_gen( 410 params: &HashMap<PeerId, ConfigGenParams>, 411 registry: ServerModuleInitRegistry, 412 version_hash: String, 413 ) -> BTreeMap<PeerId, Self> { 414 let peer0 = ¶ms[&PeerId::from(0)]; 415 416 let mut broadcast_pks = BTreeMap::new(); 417 let mut broadcast_sks = BTreeMap::new(); 418 for peer_id in peer0.peer_ids() { 419 let (broadcast_sk, broadcast_pk) = secp256k1::generate_keypair(&mut OsRng); 420 broadcast_pks.insert(peer_id, broadcast_pk); 421 broadcast_sks.insert(peer_id, broadcast_sk); 422 } 423 424 let modules = peer0.consensus.modules.iter_modules(); 425 let module_configs: BTreeMap<_, _> = modules 426 .map(|(module_id, kind, module_params)| { 427 ( 428 module_id, 429 registry 430 .get(kind) 431 .expect("Module not registered") 432 .trusted_dealer_gen(&peer0.peer_ids(), module_params), 433 ) 434 }) 435 .collect(); 436 437 let server_config: BTreeMap<_, _> = peer0 438 .peer_ids() 439 .iter() 440 .map(|&id| { 441 let config = ServerConfig::from( 442 params[&id].clone(), 443 id, 444 broadcast_pks.clone(), 445 *broadcast_sks.get(&id).expect("We created this entry"), 446 module_configs 447 .iter() 448 .map(|(module_id, cfgs)| (*module_id, cfgs[&id].clone())) 449 .collect(), 450 version_hash.clone(), 451 ); 452 (id, config) 453 }) 454 .collect(); 455 456 server_config 457 } 458 459 /// Runs the distributed key gen algorithm 460 pub async fn distributed_gen( 461 params: &ConfigGenParams, 462 registry: ServerModuleInitRegistry, 463 delay_calculator: DelayCalculator, 464 task_group: &mut TaskGroup, 465 version_hash: String, 466 ) -> DkgResult<Self> { 467 let _timing /* logs on drop */ = timing::TimeReporter::new("distributed-gen").info(); 468 let server_conn = connect( 469 params.p2p_network(), 470 params.tls_config(), 471 delay_calculator, 472 task_group, 473 ) 474 .await; 475 let connections = PeerConnectionMultiplexer::new(server_conn).into_dyn(); 476 477 let peers = ¶ms.peer_ids(); 478 let our_id = ¶ms.local.our_id; 479 480 let broadcast_keys_exchange = PeerHandle::new( 481 &connections, 482 MODULE_INSTANCE_ID_GLOBAL, 483 *our_id, 484 peers.clone(), 485 ); 486 487 let (broadcast_sk, broadcast_pk) = secp256k1::generate_keypair(&mut OsRng); 488 489 let broadcast_public_keys = broadcast_keys_exchange 490 .exchange_pubkeys("broadcast".to_string(), broadcast_pk) 491 .await?; 492 493 // in case we are running by ourselves, avoid DKG 494 if peers.len() == 1 { 495 let server = Self::trusted_dealer_gen( 496 &HashMap::from([(*our_id, params.clone())]), 497 registry, 498 version_hash, 499 ); 500 return Ok(server[our_id].clone()); 501 } 502 info!( 503 target: LOG_NET_PEER_DKG, 504 "Peer {} running distributed key generation...", our_id 505 ); 506 507 // BFT uses a lower threshold of signing keys (f+1) 508 let mut dkg = DkgRunner::new(KeyType::Bft, peers.one_honest(), our_id, peers); 509 dkg.add(KeyType::Auth, peers.threshold()); 510 dkg.add(KeyType::Epoch, peers.threshold()); 511 512 let mut registered_modules = registry.kinds(); 513 let mut module_cfgs: BTreeMap<ModuleInstanceId, ServerModuleConfig> = Default::default(); 514 let modules = params.consensus.modules.iter_modules(); 515 let modules_runner = modules.map(|(module_instance_id, kind, module_params)| { 516 let dkg = PeerHandle::new(&connections, module_instance_id, *our_id, peers.clone()); 517 let registry = registry.clone(); 518 519 async move { 520 let result = match registry.get(kind) { 521 None => Err(DkgError::ModuleNotFound(kind.clone())), 522 Some(gen) => gen.distributed_gen(&dkg, module_params).await, 523 }; 524 (module_instance_id, result) 525 } 526 }); 527 for (module_instance_id, config) in join_all(modules_runner).await { 528 let config = config?; 529 registered_modules.remove(config.consensus_json.kind()); 530 module_cfgs.insert(module_instance_id, config); 531 } 532 if !registered_modules.is_empty() { 533 return Err(DkgError::ParamsNotFound(registered_modules)); 534 } 535 536 info!( 537 target: LOG_NET_PEER_DKG, 538 "Sending confirmations to other peers." 539 ); 540 // Note: Since our outgoing buffers are asynchronous, we don't actually know 541 // if other peers received our message, just because we received theirs. 542 // That's why we need to do a one last best effort sync. 543 let dkg_done = "DKG DONE".to_string(); 544 connections 545 .send( 546 peers, 547 (MODULE_INSTANCE_ID_GLOBAL, dkg_done.clone()), 548 DkgPeerMsg::Done, 549 ) 550 .await?; 551 552 info!( 553 target: LOG_NET_PEER_DKG, 554 "Waiting for confirmations from other peers." 555 ); 556 if let Err(Elapsed) = timeout(Duration::from_secs(30), async { 557 let mut done_peers = BTreeSet::from([*our_id]); 558 559 while done_peers.len() < peers.len() { 560 match connections.receive((MODULE_INSTANCE_ID_GLOBAL, dkg_done.clone())).await { 561 Ok((peer_id, DkgPeerMsg::Done)) => { 562 info!( 563 target: LOG_NET_PEER_DKG, 564 pper_id = %peer_id, "Got completion confirmation"); 565 done_peers.insert(peer_id); 566 }, 567 Ok((peer_id, msg)) => { 568 error!(target: LOG_NET_PEER_DKG, %peer_id, ?msg, "Received incorrect message after dkg was supposed to be finished. Probably dkg multiplexing bug."); 569 }, 570 Err(Cancelled) => {/* ignore shutdown for time being, we'll timeout soon anyway */}, 571 } 572 } 573 }) 574 .await 575 { 576 error!(target: LOG_NET_PEER_DKG, "Timeout waiting for dkg completion confirmation from other peers"); 577 }; 578 579 let server = ServerConfig::from( 580 params.clone(), 581 *our_id, 582 broadcast_public_keys, 583 broadcast_sk, 584 module_cfgs, 585 version_hash, 586 ); 587 588 info!( 589 target: LOG_NET_PEER, 590 "Distributed key generation has completed successfully!" 591 ); 592 593 Ok(server) 594 } 595 } 596 597 /// The types of keys to run distributed key generation for 598 #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] 599 pub enum KeyType { 600 Bft, 601 Epoch, 602 Auth, 603 } 604 605 impl ServerConfig { 606 pub fn network_config(&self) -> NetworkConfig { 607 NetworkConfig { 608 identity: self.local.identity, 609 bind_addr: self.local.fed_bind, 610 peers: self 611 .local 612 .p2p_endpoints 613 .iter() 614 .map(|(&id, endpoint)| (id, endpoint.url.clone())) 615 .collect(), 616 } 617 } 618 619 pub fn tls_config(&self) -> TlsConfig { 620 TlsConfig { 621 our_private_key: self.private.tls_key.clone(), 622 peer_certs: self.consensus.tls_certs.clone(), 623 peer_names: self 624 .local 625 .p2p_endpoints 626 .iter() 627 .map(|(id, endpoint)| (*id, endpoint.name.to_string())) 628 .collect(), 629 } 630 } 631 632 pub fn get_incoming_count(&self) -> u16 { 633 self.local.identity.into() 634 } 635 } 636 637 impl ConfigGenParams { 638 pub fn peer_ids(&self) -> Vec<PeerId> { 639 self.consensus.peers.keys().cloned().collect() 640 } 641 642 pub fn p2p_network(&self) -> NetworkConfig { 643 NetworkConfig { 644 identity: self.local.our_id, 645 bind_addr: self.local.p2p_bind, 646 peers: self 647 .p2p_urls() 648 .into_iter() 649 .map(|(id, peer)| (id, peer.url)) 650 .collect(), 651 } 652 } 653 654 pub fn tls_config(&self) -> TlsConfig { 655 TlsConfig { 656 our_private_key: self.local.our_private_key.clone(), 657 peer_certs: self.tls_certs(), 658 peer_names: self 659 .p2p_urls() 660 .into_iter() 661 .map(|(id, peer)| (id, peer.name)) 662 .collect(), 663 } 664 } 665 666 pub fn tls_certs(&self) -> BTreeMap<PeerId, rustls::Certificate> { 667 self.consensus 668 .peers 669 .iter() 670 .map(|(id, peer)| (*id, peer.cert.clone())) 671 .collect::<BTreeMap<_, _>>() 672 } 673 674 pub fn p2p_urls(&self) -> BTreeMap<PeerId, PeerUrl> { 675 self.consensus 676 .peers 677 .iter() 678 .map(|(id, peer)| { 679 ( 680 *id, 681 PeerUrl { 682 name: peer.name.clone(), 683 url: peer.p2p_url.clone(), 684 }, 685 ) 686 }) 687 .collect::<BTreeMap<_, _>>() 688 } 689 690 pub fn api_urls(&self) -> BTreeMap<PeerId, PeerUrl> { 691 self.consensus 692 .peers 693 .iter() 694 .map(|(id, peer)| { 695 ( 696 *id, 697 PeerUrl { 698 name: peer.name.clone(), 699 url: peer.api_url.clone(), 700 }, 701 ) 702 }) 703 .collect::<BTreeMap<_, _>>() 704 } 705 } 706 707 // TODO: Remove once new config gen UI is written 708 pub fn max_connections() -> u32 { 709 env::var(FM_MAX_CLIENT_CONNECTIONS_ENV) 710 .ok() 711 .and_then(|s| s.parse().ok()) 712 .unwrap_or(DEFAULT_MAX_CLIENT_CONNECTIONS) 713 } 714 715 pub async fn connect<T>( 716 network: NetworkConfig, 717 certs: TlsConfig, 718 delay_calculator: DelayCalculator, 719 task_group: &mut TaskGroup, 720 ) -> PeerConnections<T> 721 where 722 T: std::fmt::Debug + Clone + Serialize + DeserializeOwned + Unpin + Send + Sync + 'static, 723 { 724 let connector = TlsTcpConnector::new(certs, network.identity).into_dyn(); 725 let (connections, _) = 726 ReconnectPeerConnectionsReliable::new(network, delay_calculator, connector, task_group) 727 .await; 728 connections.into_dyn() 729 } 730 731 pub fn gen_cert_and_key( 732 name: &str, 733 ) -> Result<(rustls::Certificate, rustls::PrivateKey), anyhow::Error> { 734 let keypair = rcgen::KeyPair::generate(&rcgen::PKCS_ECDSA_P256_SHA256)?; 735 let keypair_ser = keypair.serialize_der(); 736 let mut params = rcgen::CertificateParams::new(vec![dns_sanitize(name)]); 737 738 params.key_pair = Some(keypair); 739 params.alg = &rcgen::PKCS_ECDSA_P256_SHA256; 740 params.is_ca = rcgen::IsCa::NoCa; 741 params 742 .distinguished_name 743 .push(rcgen::DnType::CommonName, dns_sanitize(name)); 744 745 let cert = rcgen::Certificate::from_params(params)?; 746 747 Ok(( 748 rustls::Certificate(cert.serialize_der()?), 749 rustls::PrivateKey(keypair_ser), 750 )) 751 } 752 753 mod serde_tls_cert_map { 754 use std::borrow::Cow; 755 use std::collections::BTreeMap; 756 757 use fedimint_core::PeerId; 758 use hex::{FromHex, ToHex}; 759 use serde::de::Error; 760 use serde::ser::SerializeMap; 761 use serde::{Deserialize, Deserializer, Serializer}; 762 use tokio_rustls::rustls; 763 764 pub fn serialize<S>( 765 certs: &BTreeMap<PeerId, rustls::Certificate>, 766 serializer: S, 767 ) -> Result<S::Ok, S::Error> 768 where 769 S: Serializer, 770 { 771 let mut serializer = serializer.serialize_map(Some(certs.len()))?; 772 for (key, value) in certs.iter() { 773 serializer.serialize_key(key)?; 774 let hex_str = value.0.encode_hex::<String>(); 775 serializer.serialize_value(&hex_str)?; 776 } 777 serializer.end() 778 } 779 780 pub fn deserialize<'de, D>( 781 deserializer: D, 782 ) -> Result<BTreeMap<PeerId, rustls::Certificate>, D::Error> 783 where 784 D: Deserializer<'de>, 785 { 786 let map: BTreeMap<PeerId, Cow<str>> = Deserialize::deserialize(deserializer)?; 787 let mut certs = BTreeMap::new(); 788 789 for (key, value) in map { 790 let cert = 791 rustls::Certificate(Vec::from_hex(value.as_ref()).map_err(D::Error::custom)?); 792 certs.insert(key, cert); 793 } 794 Ok(certs) 795 } 796 } 797 798 mod serde_tls_key { 799 use std::borrow::Cow; 800 801 use hex::{FromHex, ToHex}; 802 use serde::{Deserialize, Deserializer, Serialize, Serializer}; 803 use tokio_rustls::rustls; 804 805 pub fn serialize<S>(key: &rustls::PrivateKey, serializer: S) -> Result<S::Ok, S::Error> 806 where 807 S: Serializer, 808 { 809 let hex_str = key.0.encode_hex::<String>(); 810 Serialize::serialize(&hex_str, serializer) 811 } 812 813 pub fn deserialize<'de, D>(deserializer: D) -> Result<rustls::PrivateKey, D::Error> 814 where 815 D: Deserializer<'de>, 816 { 817 let hex_str: Cow<str> = Deserialize::deserialize(deserializer)?; 818 let bytes = Vec::from_hex(hex_str.as_ref()).map_err(serde::de::Error::custom)?; 819 Ok(rustls::PrivateKey(bytes)) 820 } 821 }