1use std::collections::{BTreeMap, BTreeSet};
2use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
3
4use fedimint_core::envs::{
5 FM_GW_IROH_CONNECT_OVERRIDES_ENV, FM_GW_IROH_CONNECT_OVERRIDES_PLAIN_ENV,
6 FM_IROH_CONNECT_OVERRIDES_ENV, FM_IROH_CONNECT_OVERRIDES_PLAIN_ENV,
7};
8use fedimint_core::{NumPeers, PeerId};
9use iroh_base::NodeAddr;
10use iroh_base::ticket::{NodeTicket, Ticket};
11
12use super::ToEnvVar;
13use crate::federation::{
14 FEDIMINTD_API_PORT_OFFSET, FEDIMINTD_P2P_PORT_OFFSET, PORTS_PER_FEDIMINTD,
15};
16
17#[derive(Debug, Clone)]
18pub struct FedimintIrohEndpoint {
19 node_id: iroh_base::NodeId,
20 secret_key: iroh_base::SecretKey,
21 port: u16,
22}
23
24impl FedimintIrohEndpoint {
25 fn new(port: u16) -> Self {
26 let secret_key = iroh_base::SecretKey::generate(&mut rand::thread_rng());
27
28 Self {
29 node_id: secret_key.public(),
30 secret_key,
31 port,
32 }
33 }
34
35 pub fn secret_key(&self) -> String {
36 self.secret_key.to_string()
37 }
38
39 pub fn port(&self) -> u16 {
40 self.port
41 }
42
43 pub fn node_id(&self) -> iroh_base::NodeId {
44 self.node_id
45 }
46
47 fn to_override(&self) -> String {
48 let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, self.port));
53 format!("{}={},", self.node_id, addr)
54 }
55
56 fn to_override_legacy(&self) -> String {
59 let node_addr = NodeAddr {
60 node_id: self.node_id,
61 relay_url: None,
62 direct_addresses: BTreeSet::from([SocketAddr::V4(SocketAddrV4::new(
63 Ipv4Addr::LOCALHOST,
64 self.port,
65 ))]),
66 };
67 format!(
68 "{}={},",
69 self.node_id,
70 Ticket::serialize(&NodeTicket::from(node_addr))
71 )
72 }
73}
74
75#[derive(Debug, Clone)]
76pub struct FedimintdPeerOverrides {
77 pub p2p: FedimintIrohEndpoint,
78 pub api: FedimintIrohEndpoint,
79 pub base_port: u16,
80}
81
82impl FedimintdPeerOverrides {
83 fn new(base_port: u16) -> Self {
84 Self {
85 p2p: FedimintIrohEndpoint::new(base_port + FEDIMINTD_P2P_PORT_OFFSET),
86 api: FedimintIrohEndpoint::new(base_port + FEDIMINTD_API_PORT_OFFSET),
87 base_port,
88 }
89 }
90}
91
92#[derive(Debug, Clone)]
93pub struct FederationNetOverrides {
94 pub base_port: u16,
95 pub num_peers: NumPeers,
96 pub peers: BTreeMap<PeerId, FedimintdPeerOverrides>,
97}
98
99impl FederationNetOverrides {
100 pub fn new(base_port: u16, num_peers: NumPeers) -> Self {
101 let peers = num_peers
102 .peer_ids()
103 .map(|peer_id| {
104 (peer_id, {
105 FedimintdPeerOverrides::new(
106 base_port
107 + u16::try_from(peer_id.to_usize()).expect("Can't fail")
108 * PORTS_PER_FEDIMINTD,
109 )
110 })
111 })
112 .collect();
113 Self {
114 base_port,
115 num_peers,
116 peers,
117 }
118 }
119
120 pub fn peer_expect(&self, peer_id: PeerId) -> &FedimintdPeerOverrides {
121 self.peers.get(&peer_id).expect("Wrong peer_id?")
122 }
123}
124
125#[derive(Debug, Clone)]
126pub struct FederationsNetOverrides {
127 federations: Vec<FederationNetOverrides>,
128}
129
130impl FederationsNetOverrides {
131 pub fn new(base_port: u16, num_federations: usize, num_peers: NumPeers) -> Self {
132 Self {
133 federations: (0..num_federations)
134 .map(|fed_i| {
135 FederationNetOverrides::new(
136 base_port + fed_i as u16 * PORTS_PER_FEDIMINTD * num_peers.total() as u16,
137 num_peers,
138 )
139 })
140 .collect(),
141 }
142 }
143
144 pub fn fed_expect(&self, fed_i: usize) -> &FederationNetOverrides {
145 self.federations.get(fed_i).expect("Wrong fed_i")
146 }
147
148 pub fn peer_expect(&self, fed_i: usize, peer_id: PeerId) -> &FedimintdPeerOverrides {
149 self.federations
150 .get(fed_i)
151 .expect("Wrong fed_i")
152 .peers
153 .get(&peer_id)
154 .expect("Wrong peer_id?")
155 }
156
157 fn overrides_plain(&self) -> String {
160 self.federations
161 .iter()
162 .flat_map(|f| f.peers.values())
163 .map(|peer| format!("{},{}", peer.p2p.to_override(), peer.api.to_override()))
164 .collect::<Vec<String>>()
165 .join(",")
166 }
167
168 fn overrides_legacy(&self) -> String {
171 self.federations
172 .iter()
173 .flat_map(|f| f.peers.values())
174 .map(|peer| {
175 format!(
176 "{},{}",
177 peer.p2p.to_override_legacy(),
178 peer.api.to_override_legacy(),
179 )
180 })
181 .collect::<Vec<String>>()
182 .join(",")
183 }
184}
185
186impl ToEnvVar for FederationsNetOverrides {
187 fn to_env_values(&self, _base_env: &str) -> impl Iterator<Item = (String, String)> {
188 vec![
192 (
193 FM_IROH_CONNECT_OVERRIDES_PLAIN_ENV.to_string(),
194 self.overrides_plain(),
195 ),
196 (
197 FM_IROH_CONNECT_OVERRIDES_ENV.to_string(),
198 self.overrides_legacy(),
199 ),
200 ]
201 .into_iter()
202 }
203}
204
205#[derive(Debug, Clone)]
206pub struct GatewaydNetOverrides {
207 pub gateway_iroh_endpoints: Vec<FedimintIrohEndpoint>,
208}
209
210impl GatewaydNetOverrides {
211 pub fn new(base_port: u16, num_gateways: usize) -> Self {
212 Self {
213 gateway_iroh_endpoints: (0..num_gateways)
214 .map(|gw_i| FedimintIrohEndpoint::new(base_port + gw_i as u16))
215 .collect(),
216 }
217 }
218}
219
220impl GatewaydNetOverrides {
221 fn overrides_plain(&self) -> String {
224 self.gateway_iroh_endpoints
225 .iter()
226 .map(FedimintIrohEndpoint::to_override)
227 .collect::<Vec<String>>()
228 .join(",")
229 }
230
231 fn overrides_legacy(&self) -> String {
234 self.gateway_iroh_endpoints
235 .iter()
236 .map(FedimintIrohEndpoint::to_override_legacy)
237 .collect::<Vec<String>>()
238 .join(",")
239 }
240}
241
242impl ToEnvVar for GatewaydNetOverrides {
243 fn to_env_values(&self, _base_env: &str) -> impl Iterator<Item = (String, String)> {
244 vec![
246 (
247 FM_GW_IROH_CONNECT_OVERRIDES_PLAIN_ENV.to_string(),
248 self.overrides_plain(),
249 ),
250 (
251 FM_GW_IROH_CONNECT_OVERRIDES_ENV.to_string(),
252 self.overrides_legacy(),
253 ),
254 ]
255 .into_iter()
256 }
257}