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, warn};
10use url::Url;
11
12use crate::envs::{
13 FM_IROH_DHT_ENABLE_ENV, FM_IROH_N0_DISCOVERY_ENABLE_ENV, FM_IROH_PKARR_PUBLISHER_ENABLE_ENV,
14 FM_IROH_PKARR_RESOLVER_ENABLE_ENV, FM_IROH_RELAYS_ENABLE_ENV, is_env_var_set,
15 is_env_var_set_opt,
16};
17use crate::iroh_prod::{FM_IROH_DNS_FEDIMINT_PROD, FM_IROH_RELAYS_FEDIMINT_PROD};
18
19pub async fn build_iroh_endpoint(
20 secret_key: SecretKey,
21 bind_addr: SocketAddr,
22 iroh_dns: Option<SafeUrl>,
23 iroh_relays: Vec<SafeUrl>,
24 alpn: &[u8],
25) -> Result<Endpoint, anyhow::Error> {
26 let iroh_dns_servers: Vec<_> = iroh_dns.clone().map_or_else(
27 || {
28 FM_IROH_DNS_FEDIMINT_PROD
29 .into_iter()
30 .map(|dns| dns.parse().expect("Can't fail"))
31 .collect()
32 },
33 |iroh_dns| vec![iroh_dns.to_unsafe()],
34 );
35
36 let relay_mode = if !is_env_var_set_opt(FM_IROH_RELAYS_ENABLE_ENV).unwrap_or(true) {
37 warn!(
38 target: LOG_NET_IROH,
39 "Iroh relays are disabled"
40 );
41 RelayMode::Disabled
42 } else if iroh_relays.is_empty() {
43 RelayMode::Custom(
44 FM_IROH_RELAYS_FEDIMINT_PROD
45 .into_iter()
46 .map(|url| RelayNode {
47 url: RelayUrl::from(Url::parse(url).expect("Hardcoded, can't fail")),
48 stun_only: false,
49 stun_port: DEFAULT_STUN_PORT,
50 quic: Some(RelayQuicConfig::default()),
51 })
52 .collect(),
53 )
54 } else {
55 RelayMode::Custom(
56 iroh_relays
57 .into_iter()
58 .map(|url| RelayNode {
59 url: RelayUrl::from(url.to_unsafe()),
60 stun_only: false,
61 stun_port: DEFAULT_STUN_PORT,
62 quic: Some(RelayQuicConfig::default()),
63 })
64 .collect(),
65 )
66 };
67
68 let mut builder = Endpoint::builder();
69
70 for iroh_dns in iroh_dns_servers {
71 if is_env_var_set_opt(FM_IROH_PKARR_PUBLISHER_ENABLE_ENV).unwrap_or(true) {
72 builder = builder.add_discovery({
73 let iroh_dns = iroh_dns.clone();
74 move |sk: &SecretKey| Some(PkarrPublisher::new(sk.clone(), iroh_dns))
75 });
76 } else {
77 warn!(
78 target: LOG_NET_IROH,
79 "Iroh pkarr publisher is disabled"
80 );
81 }
82
83 if is_env_var_set_opt(FM_IROH_PKARR_RESOLVER_ENABLE_ENV).unwrap_or(true) {
84 builder = builder.add_discovery(|_| Some(PkarrResolver::new(iroh_dns)));
85 } else {
86 warn!(
87 target: LOG_NET_IROH,
88 "Iroh pkarr resolver is disabled"
89 );
90 }
91 }
92
93 if is_env_var_set(FM_IROH_DHT_ENABLE_ENV) {
95 #[cfg(not(target_family = "wasm"))]
96 {
97 builder = builder.discovery_dht();
98 }
99 } else {
100 info!(
101 target: LOG_NET_IROH,
102 "Iroh DHT is disabled"
103 );
104 }
105
106 if is_env_var_set_opt(FM_IROH_N0_DISCOVERY_ENABLE_ENV).unwrap_or(true) {
107 builder = builder.discovery_n0();
108 } else {
109 warn!(
110 target: LOG_NET_IROH,
111 "Iroh n0 discovery is disabled"
112 );
113 }
114
115 let builder = builder
116 .relay_mode(relay_mode)
117 .secret_key(secret_key)
118 .alpns(vec![alpn.to_vec()]);
119
120 let builder = match bind_addr {
121 SocketAddr::V4(addr_v4) => builder.bind_addr_v4(addr_v4),
122 SocketAddr::V6(addr_v6) => builder.bind_addr_v6(addr_v6),
123 };
124
125 let endpoint = builder.bind().await.expect("Could not bind to port");
126
127 info!(
128 target: LOG_NET_IROH,
129 %bind_addr,
130 node_id = %endpoint.node_id(),
131 node_id_pkarr = %z32::encode(endpoint.node_id().as_bytes()),
132 "Iroh p2p server endpoint"
133 );
134
135 Ok(endpoint)
136}