fedimint_server/net/p2p_connector/iroh/
endpoint.rs1use std::borrow::Cow;
8use std::net::SocketAddr;
9
10use anyhow::Context as _;
11use fedimint_core::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, FM_IROH_RELAYS_ENABLE_ENV, is_env_var_set,
14 is_env_var_set_opt,
15};
16use fedimint_core::net::iroh::{IROH_IDLE_TIMEOUT, IROH_KEEP_ALIVE_INTERVAL};
17use fedimint_core::util::SafeUrl;
18use fedimint_logging::LOG_NET_IROH;
19use iroh_next::address_lookup::{AddrFilter, DnsAddressLookup, PkarrPublisher, PkarrResolver};
20use iroh_next::endpoint::presets::Minimal;
21use iroh_next::endpoint::{Builder, QuicTransportConfig};
22use iroh_next::{Endpoint, RelayMode, RelayUrl, SecretKey, TransportAddr};
23use tracing::{debug, info, warn};
24
25pub(super) async fn build_iroh_endpoint(
27 secret_key: SecretKey,
28 bind_addr: SocketAddr,
29 iroh_dns: Option<SafeUrl>,
30 iroh_relays: Vec<SafeUrl>,
31 alpn: &[u8],
32) -> anyhow::Result<Endpoint> {
33 let relay_mode = if !is_env_var_set_opt(FM_IROH_RELAYS_ENABLE_ENV).unwrap_or(true) {
34 warn!(target: LOG_NET_IROH, "Iroh relays are disabled");
35 RelayMode::Disabled
36 } else if iroh_relays.is_empty() {
37 RelayMode::Default
38 } else {
39 RelayMode::Custom(
40 iroh_relays
41 .into_iter()
42 .map(|url| RelayUrl::from(url.to_unsafe()))
43 .collect(),
44 )
45 };
46
47 let mut builder = Endpoint::builder(Minimal);
48
49 if let Some(iroh_dns) = iroh_dns.map(SafeUrl::to_unsafe) {
50 if is_env_var_set_opt(FM_IROH_PKARR_PUBLISHER_ENABLE_ENV).unwrap_or(true) {
51 builder = builder.address_lookup(
52 PkarrPublisher::builder(iroh_dns.clone()).addr_filter(guardian_pkarr_addr_filter()),
53 );
54 } else {
55 warn!(target: LOG_NET_IROH, "Iroh pkarr publisher is disabled");
56 }
57
58 if is_env_var_set_opt(FM_IROH_PKARR_RESOLVER_ENABLE_ENV).unwrap_or(true) {
59 builder = builder.address_lookup(PkarrResolver::builder(iroh_dns));
60 } else {
61 warn!(target: LOG_NET_IROH, "Iroh pkarr resolver is disabled");
62 }
63 }
64
65 if is_env_var_set(FM_IROH_DHT_ENABLE_ENV) {
66 debug!(target: LOG_NET_IROH, "Iroh DHT is enabled");
67 builder = builder.address_lookup(iroh_mainline_address_lookup::DhtAddressLookup::builder());
68 } else {
69 info!(target: LOG_NET_IROH, "Iroh DHT is disabled");
70 }
71
72 builder = add_n0_discovery(builder);
73
74 let transport_config = QuicTransportConfig::builder()
75 .max_idle_timeout(Some(
76 IROH_IDLE_TIMEOUT
77 .try_into()
78 .expect("idle timeout fits in IdleTimeout"),
79 ))
80 .keep_alive_interval(IROH_KEEP_ALIVE_INTERVAL)
81 .build();
82
83 let endpoint = Box::pin(
84 builder
85 .relay_mode(relay_mode)
86 .secret_key(secret_key)
87 .alpns(vec![alpn.to_vec()])
88 .transport_config(transport_config)
89 .clear_ip_transports()
92 .bind_addr(bind_addr)
93 .context("Invalid Iroh bind address")?
94 .bind(),
95 )
96 .await
97 .context("Failed to bind Iroh endpoint")?;
98
99 info!(
100 target: LOG_NET_IROH,
101 %bind_addr,
102 endpoint_id = %endpoint.id(),
103 endpoint_id_pkarr = %z32::encode(endpoint.id().as_bytes()),
104 "Iroh P2P server endpoint"
105 );
106
107 Ok(endpoint)
108}
109
110fn add_n0_discovery(mut builder: Builder) -> Builder {
111 if !is_env_var_set_opt(FM_IROH_N0_DISCOVERY_ENABLE_ENV).unwrap_or(true) {
112 warn!(target: LOG_NET_IROH, "Iroh n0 discovery is disabled");
113 return builder;
114 }
115
116 builder = builder
119 .address_lookup(PkarrPublisher::n0_dns().addr_filter(guardian_pkarr_addr_filter()))
120 .address_lookup(DnsAddressLookup::n0_dns());
121
122 if is_env_var_set_opt(FM_IROH_PKARR_RESOLVER_ENABLE_ENV).unwrap_or(true) {
123 builder.address_lookup(PkarrResolver::n0_dns())
124 } else {
125 warn!(target: LOG_NET_IROH, "Iroh pkarr resolver is disabled");
126 builder
127 }
128}
129
130pub(super) fn guardian_pkarr_addr_filter() -> AddrFilter {
136 AddrFilter::new(|addrs| {
137 let publish_relay = addrs.iter().any(TransportAddr::is_relay);
138 Cow::Owned(
139 addrs
140 .iter()
141 .filter(|addr| {
142 if publish_relay {
143 addr.is_relay()
144 } else {
145 matches!(addr, TransportAddr::Ip(_))
146 }
147 })
148 .cloned()
149 .collect(),
150 )
151 })
152}