fedimint_core/net/
iroh.rs

1use 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, warn};
10
11use crate::envs::{
12    FM_IROH_DHT_ENABLE_ENV, FM_IROH_N0_DISCOVERY_ENABLE_ENV, FM_IROH_PKARR_PUBLISHER_ENABLE_ENV,
13    FM_IROH_PKARR_RESOLVER_ENABLE_ENV, is_env_var_set, is_env_var_set_opt,
14};
15
16pub async fn build_iroh_endpoint(
17    secret_key: SecretKey,
18    bind_addr: SocketAddr,
19    iroh_dns: Option<SafeUrl>,
20    iroh_relays: Vec<SafeUrl>,
21    alpn: &[u8],
22) -> Result<Endpoint, anyhow::Error> {
23    let relay_mode = if iroh_relays.is_empty() {
24        RelayMode::Default
25    } else {
26        RelayMode::Custom(
27            iroh_relays
28                .into_iter()
29                .map(|url| RelayNode {
30                    url: RelayUrl::from(url.to_unsafe()),
31                    stun_only: false,
32                    stun_port: DEFAULT_STUN_PORT,
33                    quic: Some(RelayQuicConfig::default()),
34                })
35                .collect(),
36        )
37    };
38
39    let mut builder = Endpoint::builder();
40
41    if let Some(iroh_dns) = iroh_dns.map(SafeUrl::to_unsafe) {
42        if is_env_var_set_opt(FM_IROH_PKARR_PUBLISHER_ENABLE_ENV).unwrap_or(true) {
43            builder = builder.add_discovery({
44                let iroh_dns = iroh_dns.clone();
45                move |sk: &SecretKey| Some(PkarrPublisher::new(sk.clone(), iroh_dns))
46            });
47        } else {
48            warn!(
49                target: LOG_NET_IROH,
50                "Iroh pkarr publisher is disabled"
51            );
52        }
53
54        if is_env_var_set_opt(FM_IROH_PKARR_RESOLVER_ENABLE_ENV).unwrap_or(true) {
55            builder = builder.add_discovery(|_| Some(PkarrResolver::new(iroh_dns)));
56        } else {
57            warn!(
58                target: LOG_NET_IROH,
59                "Iroh pkarr resolver is disabled"
60            );
61        }
62    }
63
64    // See <https://github.com/fedimint/fedimint/issues/7811>
65    if is_env_var_set(FM_IROH_DHT_ENABLE_ENV) {
66        #[cfg(not(target_family = "wasm"))]
67        {
68            builder = builder.discovery_dht();
69        }
70    } else {
71        info!(
72            target: LOG_NET_IROH,
73            "Iroh DHT is disabled"
74        );
75    }
76
77    if is_env_var_set_opt(FM_IROH_N0_DISCOVERY_ENABLE_ENV).unwrap_or(true) {
78        builder = builder.discovery_n0();
79    } else {
80        warn!(
81            target: LOG_NET_IROH,
82            "Iroh n0 discovery is disabled"
83        );
84    }
85
86    let builder = builder
87        .relay_mode(relay_mode)
88        .secret_key(secret_key)
89        .alpns(vec![alpn.to_vec()]);
90
91    let builder = match bind_addr {
92        SocketAddr::V4(addr_v4) => builder.bind_addr_v4(addr_v4),
93        SocketAddr::V6(addr_v6) => builder.bind_addr_v6(addr_v6),
94    };
95
96    let endpoint = builder.bind().await.expect("Could not bind to port");
97
98    info!(
99        target: LOG_NET_IROH,
100        %bind_addr,
101        node_id = %endpoint.node_id(),
102        node_id_pkarr = %z32::encode(endpoint.node_id().as_bytes()),
103        "Iroh p2p server endpoint"
104    );
105
106    Ok(endpoint)
107}