fedimint_core/net/
iroh.rs1use std::net::SocketAddr;
2
3use fedimint_core::util::SafeUrl;
4use fedimint_logging::LOG_NET_IROH;
5use iroh::defaults::DEFAULT_STUN_PORT;
6use iroh::discovery::pkarr::{PkarrPublisher, PkarrResolver};
7use iroh::{Endpoint, RelayMode, RelayNode, RelayUrl, SecretKey};
8use iroh_relay::RelayQuicConfig;
9use tracing::info;
10use url::Url;
11
12use crate::envs::{FM_IROH_ENABLE_DHT_ENV, is_env_var_set};
13use crate::iroh_prod::{FM_IROH_DNS_FEDIMINT_PROD, FM_IROH_RELAYS_FEDIMINT_PROD};
14
15pub async fn build_iroh_endpoint(
16 secret_key: SecretKey,
17 bind_addr: SocketAddr,
18 iroh_dns: Option<SafeUrl>,
19 iroh_relays: Vec<SafeUrl>,
20 alpn: &[u8],
21) -> Result<Endpoint, anyhow::Error> {
22 let iroh_dns_servers: Vec<_> = iroh_dns.clone().map_or_else(
23 || {
24 FM_IROH_DNS_FEDIMINT_PROD
25 .into_iter()
26 .map(|dns| dns.parse().expect("Can't fail"))
27 .collect()
28 },
29 |iroh_dns| vec![iroh_dns.to_unsafe()],
30 );
31
32 let relay_mode = if iroh_relays.is_empty() {
33 RelayMode::Custom(
34 FM_IROH_RELAYS_FEDIMINT_PROD
35 .into_iter()
36 .map(|url| RelayNode {
37 url: RelayUrl::from(Url::parse(url).expect("Hardcoded, can't fail")),
38 stun_only: false,
39 stun_port: DEFAULT_STUN_PORT,
40 quic: Some(RelayQuicConfig::default()),
41 })
42 .collect(),
43 )
44 } else {
45 RelayMode::Custom(
46 iroh_relays
47 .into_iter()
48 .map(|url| RelayNode {
49 url: RelayUrl::from(url.to_unsafe()),
50 stun_only: false,
51 stun_port: DEFAULT_STUN_PORT,
52 quic: Some(RelayQuicConfig::default()),
53 })
54 .collect(),
55 )
56 };
57
58 let mut builder = Endpoint::builder();
59
60 for iroh_dns in iroh_dns_servers {
61 builder = builder
62 .add_discovery({
63 let iroh_dns = iroh_dns.clone();
64 move |sk: &SecretKey| Some(PkarrPublisher::new(sk.clone(), iroh_dns))
65 })
66 .add_discovery(|_| Some(PkarrResolver::new(iroh_dns)));
67 }
68
69 if is_env_var_set(FM_IROH_ENABLE_DHT_ENV) {
71 #[cfg(not(target_family = "wasm"))]
72 {
73 builder = builder.discovery_dht();
74 }
75 } else {
76 info!(
77 target: LOG_NET_IROH,
78 "Iroh DHT is disabled"
79 );
80 }
81
82 let builder = builder
83 .discovery_n0()
84 .relay_mode(relay_mode)
85 .secret_key(secret_key)
86 .alpns(vec![alpn.to_vec()]);
87
88 let builder = match bind_addr {
89 SocketAddr::V4(addr_v4) => builder.bind_addr_v4(addr_v4),
90 SocketAddr::V6(addr_v6) => builder.bind_addr_v6(addr_v6),
91 };
92
93 let endpoint = builder.bind().await.expect("Could not bind to port");
94
95 info!(
96 target: LOG_NET_IROH,
97 %bind_addr,
98 node_id = %endpoint.node_id(),
99 node_id_pkarr = %z32::encode(endpoint.node_id().as_bytes()),
100 "Iroh p2p server endpoint"
101 );
102
103 Ok(endpoint)
104}