1use std::{
2 collections::{HashMap, HashSet},
3 sync::Arc,
4};
5
6pub use cliquenet::{Config as CliquenetConfig, NetAddr, Role};
7use cliquenet::{NetworkReceiver, NetworkSender, Slot, noise::Protocol, x25519::PublicKey};
8use hotshot_types::{
9 PeerConnectInfo,
10 data::{EpochNumber, ViewNumber},
11 epoch_membership::EpochMembershipCoordinator,
12 message::{EXTERNAL_MESSAGE_VERSION, MessageKind, UpgradeLock},
13 traits::{
14 metrics::{Counter, CounterFamily, Gauge, GaugeFamily, Metrics},
15 node_implementation::NodeType,
16 },
17 x25519::{self, Keypair},
18};
19use hotshot_utils::anytrace;
20use parking_lot::RwLock;
21use tracing::{error, info};
22
23use crate::message::{Message, MessageType, Unchecked, Validated};
24
25#[derive(Debug)]
26pub struct Cliquenet<T: NodeType> {
27 inner: Sender<T>,
28 receiver: NetworkReceiver,
29}
30
31#[derive(Debug, Clone)]
32pub struct Sender<T: NodeType> {
33 my_keys: (T::SignatureKey, PublicKey),
34 sender: NetworkSender,
35 shared: Arc<RwLock<Shared<T::SignatureKey>>>,
36 upgrade_lock: UpgradeLock<T>,
37}
38
39#[derive(Debug)]
40struct Shared<K> {
41 peers: HashMap<K, PeerConnectInfo>,
42 epoch: EpochNumber,
43}
44
45impl<T: NodeType> Cliquenet<T> {
46 pub async fn create<A, P, S>(
47 name: S,
48 signing_key: T::SignatureKey,
49 keypair: Keypair,
50 addr: A,
51 parties: P,
52 upgrade_lock: UpgradeLock<T>,
53 metrics: Box<dyn Metrics>,
54 ) -> Result<Self, NetworkError>
55 where
56 A: Into<cliquenet::NetAddr>,
57 P: IntoIterator<Item = (T::SignatureKey, PeerConnectInfo)>,
58 S: Into<String>,
59 {
60 let parties: HashMap<T::SignatureKey, PeerConnectInfo> = parties.into_iter().collect();
61
62 let cfg = cliquenet::Config::builder()
63 .name(name)
64 .keypair(keypair.into())
65 .bind(addr.into())
66 .parties(
67 parties
68 .values()
69 .map(|info| (info.x25519_key.into(), info.p2p_addr.clone())),
70 )
71 .noise_protocols([(1.into(), Protocol::IK_25519_AesGcm_Blake2s)])
72 .build();
73
74 Self::create_with_config(signing_key, upgrade_lock, cfg, parties, metrics).await
75 }
76
77 pub(crate) async fn create_with_config<P>(
78 signing_key: T::SignatureKey,
79 upgrade_lock: UpgradeLock<T>,
80 config: cliquenet::Config,
81 parties: P,
82 metrics: Box<dyn Metrics>,
83 ) -> Result<Self, NetworkError>
84 where
85 P: IntoIterator<Item = (T::SignatureKey, PeerConnectInfo)>,
86 {
87 let public_key = config.public_key();
88 let metrics = CliquenetMetrics::new(metrics);
89 let network = cliquenet::Network::create(config.with_metrics(metrics)).await?;
90 let peers: HashMap<_, _> = parties.into_iter().collect();
91
92 info!(peers = %peers.len(), "cliquenet created");
93
94 let (send, recv) = network.split_into();
95
96 Ok(Self {
97 inner: Sender {
98 my_keys: (signing_key, public_key),
99 sender: send,
100 shared: Arc::new(RwLock::new(Shared {
101 peers,
102 epoch: EpochNumber::new(0),
103 })),
104 upgrade_lock,
105 },
106 receiver: recv,
107 })
108 }
109
110 pub fn sender(&self) -> &Sender<T> {
111 &self.inner
112 }
113
114 pub async fn receive(&mut self) -> Result<Message<T, Unchecked>, NetworkError> {
115 let (src, bytes) = self
116 .receiver
117 .receive()
118 .await
119 .ok_or(cliquenet::NetworkError::ChannelClosed)?;
120 let msg = self.deserialize(&bytes)?;
121 let key = self
122 .inner
123 .shared
124 .read()
125 .peers
126 .get(&msg.sender)
127 .map(|info| info.x25519_key)
128 .or_else(|| {
129 (msg.sender == self.inner.my_keys.0).then_some(self.inner.my_keys.1.into())
130 });
131 if Some(src.into()) != key {
132 return Err(NetworkError::InvalidSender {
133 msg: key,
134 src: src.into(),
135 });
136 }
137 Ok(msg)
138 }
139
140 pub async fn shutdown(&mut self) {
141 if let Ok(done) = self.inner.sender.shutdown() {
142 done.await
143 }
144 }
145
146 pub fn gc(&mut self, v: ViewNumber) -> Result<(), NetworkError> {
147 self.inner.sender.gc(Slot::new(*v))?;
148 Ok(())
149 }
150
151 pub fn add_peers(
152 &mut self,
153 r: Role,
154 ps: Vec<(T::SignatureKey, (PublicKey, NetAddr))>,
155 ) -> Result<(), NetworkError> {
156 let mut targets = Vec::new();
157 {
158 let mut shared = self.inner.shared.write();
159 for (k, (x, a)) in ps {
160 shared.peers.insert(
161 k,
162 PeerConnectInfo {
163 x25519_key: x.into(),
164 p2p_addr: a.clone(),
165 },
166 );
167 targets.push((x, a))
168 }
169 }
170 self.inner.sender.add_peers(r, targets)?;
171 Ok(())
172 }
173
174 pub fn remove_peers(&mut self, ps: Vec<&T::SignatureKey>) -> Result<(), NetworkError> {
175 let mut targets = Vec::new();
176 {
177 let mut shared = self.inner.shared.write();
178 for k in ps {
179 if let Some(info) = shared.peers.remove(k) {
180 targets.push(info.x25519_key.into())
181 }
182 }
183 }
184 self.inner.sender.remove_peers(targets)?;
185 Ok(())
186 }
187
188 pub fn assign_role(&mut self, r: Role, ps: Vec<&T::SignatureKey>) -> Result<(), NetworkError> {
189 let mut targets = Vec::new();
190 {
191 let shared = self.inner.shared.read();
192 for k in ps {
193 if let Some(info) = shared.peers.get(k) {
194 targets.push(info.x25519_key.into())
195 }
196 }
197 }
198 self.inner.sender.assign_peers(r, targets)?;
199 Ok(())
200 }
201
202 pub fn apply_epoch(
210 &mut self,
211 epoch: EpochNumber,
212 coord: &EpochMembershipCoordinator<T>,
213 ) -> Result<(), NetworkError> {
214 let ours = self.inner.shared.read().epoch;
215 if epoch <= ours {
216 info!(%epoch, %ours, "epoch already seen");
217 return Ok(());
218 }
219
220 let Some(curr_infos) = coord.epoch_peers(Some(epoch)) else {
222 error!(%epoch, "no stake table available");
223 return Ok(());
224 };
225
226 let prev_infos = if *epoch > 0 {
228 coord.epoch_peers(Some(epoch - 1)).unwrap_or_else(|| {
229 info!(%epoch, "previous epoch's stake table unavailable");
230 HashMap::new()
231 })
232 } else {
233 HashMap::new()
234 };
235
236 let next_infos = coord.epoch_peers(Some(epoch + 1)).unwrap_or_else(|| {
238 info!(%epoch, "next epoch's stake table not available");
239 HashMap::new()
240 });
241
242 let mut merged_infos = prev_infos.clone();
245 for (k, v) in curr_infos.iter().chain(&next_infos) {
246 merged_infos.insert(k.clone(), v.clone());
247 }
248
249 let wanted: HashSet<T::SignatureKey> = curr_infos
250 .keys()
251 .chain(next_infos.keys())
252 .cloned()
253 .collect();
254
255 let retained: HashSet<T::SignatureKey> = curr_infos
256 .keys()
257 .chain(prev_infos.keys())
258 .cloned()
259 .collect();
260
261 let mut to_add: Vec<(T::SignatureKey, PeerConnectInfo)> = Vec::new();
262 let mut to_del: Vec<(T::SignatureKey, PeerConnectInfo)> = Vec::new();
263
264 for k in &wanted {
265 if let Some(Some(new_info)) = merged_infos.get(k) {
266 if Some(new_info) != self.inner.shared.read().peers.get(k) {
267 info!(%epoch, peer = %k, "adding/updating network peer");
268 to_add.push((k.clone(), new_info.clone()));
269 } else {
270 info!(%epoch, peer = %k, "peer unchanged");
271 }
272 } else {
273 info!(%epoch, peer = %k, "ignoring peer without connection info");
274 }
275 }
276
277 for (k, info) in &self.inner.shared.read().peers {
279 if !(retained.contains(k) || wanted.contains(k)) {
280 info!(%epoch, peer = %k, "removing network peer");
281 to_del.push((k.clone(), info.clone()));
282 }
283 }
284
285 {
286 let peers = &mut self.inner.shared.write().peers;
287 for (k, _) in &to_del {
288 peers.remove(k);
289 }
290 for (k, info) in &to_add {
291 peers.insert(k.clone(), info.clone());
292 }
293 }
294
295 let add_targets: Vec<(PublicKey, NetAddr)> = to_add
296 .iter()
297 .map(|(_, i)| (i.x25519_key.into(), i.p2p_addr.clone()))
298 .collect();
299 let del_targets: Vec<PublicKey> = to_del.iter().map(|(_, i)| i.x25519_key.into()).collect();
300
301 if let Err(err) = self.inner.sender.add_peers(Role::Active, add_targets) {
302 error!(%epoch, %err, "network down; could not add peers to network");
303 return Err(err.into());
304 }
305
306 if let Err(err) = self.inner.sender.remove_peers(del_targets) {
307 error!(%epoch, %err, "network down; could not remove peers from network");
308 return Err(err.into());
309 }
310
311 info!(%epoch, peers = %self.inner.shared.read().peers.len());
312
313 self.inner.shared.write().epoch = epoch;
314
315 Ok(())
316 }
317
318 fn deserialize(&self, bytes: &[u8]) -> Result<Message<T, Unchecked>, NetworkError> {
319 match self
320 .inner
321 .upgrade_lock
322 .deserialize::<Message<T, Unchecked>>(bytes)
323 {
324 Ok((m, v)) => {
325 if v == EXTERNAL_MESSAGE_VERSION && !m.is_external() {
326 let e = anytrace::warn!("received a non-external message with version 0.0");
327 return Err(NetworkError::Serialize(e));
328 }
329 Ok(m)
330 },
331 Err(primary_err) => {
332 if let Ok((_v, hs_msg)) =
339 versions::decode::<hotshot_types::message::Message<T>>(bytes)
340 && let MessageKind::External(data) = hs_msg.kind
341 {
342 return Ok(Message {
343 sender: hs_msg.sender,
344 message_type: MessageType::External(data),
345 });
346 }
347 Err(NetworkError::Serialize(primary_err))
348 },
349 }
350 }
351}
352
353impl<T: NodeType> Sender<T> {
354 pub fn unicast(
355 &self,
356 v: ViewNumber,
357 to: &T::SignatureKey,
358 m: &Message<T, Validated>,
359 ) -> Result<(), NetworkError> {
360 let target = if *to == self.my_keys.0 {
361 self.my_keys.1
362 } else if let Some(info) = self.shared.read().peers.get(to) {
363 info.x25519_key.into()
364 } else {
365 error!(peer = %to, "unicast target not found");
366 return Ok(());
367 };
368 let bytes = self.serialize(m)?;
369 self.sender.unicast(Slot::new(*v), target, bytes)?;
370 Ok(())
371 }
372
373 pub fn multicast(
374 &self,
375 v: ViewNumber,
376 to: Vec<&T::SignatureKey>,
377 m: &Message<T, Validated>,
378 ) -> Result<(), NetworkError> {
379 let bytes = self.serialize(m)?;
380 let mut targets = Vec::new();
381 {
382 let shared = self.shared.read();
383 for t in to {
384 if let Some(info) = shared.peers.get(t) {
385 targets.push(info.x25519_key.into())
386 } else if *t == self.my_keys.0 {
387 targets.push(self.my_keys.1)
388 } else {
389 error!(peer = %t, "multicast target not found");
390 }
391 }
392 }
393 self.sender.multicast(Slot::new(*v), targets, bytes)?;
394 Ok(())
395 }
396
397 pub fn broadcast(&self, v: ViewNumber, m: &Message<T, Validated>) -> Result<(), NetworkError> {
398 let bytes = self.serialize(m)?;
399 self.sender.broadcast(Slot::new(*v), bytes)?;
400 Ok(())
401 }
402
403 fn serialize(&self, m: &Message<T, Validated>) -> Result<Vec<u8>, NetworkError> {
404 if let MessageType::External(bytes) = &m.message_type {
405 return Ok(bytes.clone());
406 }
407 let v = self.upgrade_lock.serialize(m)?;
408 Ok(v)
409 }
410}
411
412#[derive(Debug, thiserror::Error)]
413pub enum NetworkError {
414 #[error("cliquenet: {0}")]
415 Cliquenet(#[from] cliquenet::NetworkError),
416
417 #[error("serialization: {0}")]
418 Serialize(#[from] anytrace::Error),
419
420 #[error("message sender {msg:?} != message source {src}")]
421 InvalidSender {
422 msg: Option<x25519::PublicKey>,
423 src: x25519::PublicKey,
424 },
425}
426
427impl NetworkError {
428 pub fn is_critical(&self) -> bool {
429 matches!(
430 self,
431 Self::Cliquenet(
432 cliquenet::NetworkError::Bind(..)
433 | cliquenet::NetworkError::ChannelClosed
434 | cliquenet::NetworkError::BudgetClosed
435 )
436 )
437 }
438}
439
440struct CliquenetMetrics {
441 metrics: Box<dyn Metrics>,
442 gauges: RwLock<Gauges>,
443 counters: RwLock<Counters>,
444}
445
446#[derive(Default)]
447struct Gauges {
448 gauges: HashMap<PublicKey, HashMap<String, Box<dyn Gauge>>>,
449 family: HashMap<String, Box<dyn GaugeFamily>>,
450}
451
452#[derive(Default)]
453struct Counters {
454 counters: HashMap<PublicKey, HashMap<String, Box<dyn Counter>>>,
455 family: HashMap<String, Box<dyn CounterFamily>>,
456}
457
458impl CliquenetMetrics {
459 pub fn new(m: Box<dyn Metrics>) -> Self {
460 Self {
461 metrics: m.subgroup("cliquenet".to_string()),
462 gauges: RwLock::new(Gauges::default()),
463 counters: RwLock::new(Counters::default()),
464 }
465 }
466}
467
468impl cliquenet::Metrics for CliquenetMetrics {
474 fn set(&self, key: &PublicKey, label: &str, val: usize) {
475 if let Some(g) = self
476 .gauges
477 .read()
478 .gauges
479 .get(key)
480 .and_then(|m| m.get(label))
481 {
482 return g.set(val);
483 }
484
485 let mut gauges = self.gauges.write();
486
487 if let Some(g) = gauges.gauges.get(key).and_then(|m| m.get(label)) {
489 return g.set(val);
490 }
491
492 let g = gauges
493 .family
494 .entry(label.to_string())
495 .or_insert_with(|| {
496 self.metrics
497 .gauge_family(label.to_string(), vec!["peer".to_string()])
498 })
499 .create(vec![key.to_string()]);
500
501 gauges
502 .gauges
503 .entry(*key)
504 .or_default()
505 .entry(label.to_string())
506 .or_insert(g)
507 .set(val)
508 }
509
510 fn add(&self, key: &PublicKey, label: &str, val: usize) {
511 if let Some(c) = self
512 .counters
513 .read()
514 .counters
515 .get(key)
516 .and_then(|m| m.get(label))
517 {
518 return c.add(val);
519 }
520
521 let mut counters = self.counters.write();
522
523 if let Some(c) = counters.counters.get(key).and_then(|m| m.get(label)) {
525 return c.add(val);
526 }
527
528 let c = counters
529 .family
530 .entry(label.to_string())
531 .or_insert_with(|| {
532 self.metrics
533 .counter_family(label.to_string(), vec!["peer".to_string()])
534 })
535 .create(vec![key.to_string()]);
536
537 counters
538 .counters
539 .entry(*key)
540 .or_default()
541 .entry(label.to_string())
542 .or_insert(c)
543 .add(val)
544 }
545
546 fn del(&self, key: &PublicKey) {
547 let key_string = key.to_string();
548
549 {
550 let mut gauges = self.gauges.write();
551 for (label, _) in gauges.gauges.remove(key).into_iter().flatten() {
552 if let Some(f) = gauges.family.get(&label) {
553 f.destroy(&[&key_string]);
554 }
555 }
556 }
557
558 {
559 let mut counters = self.counters.write();
560 for (label, _) in counters.counters.remove(key).into_iter().flatten() {
561 if let Some(f) = counters.family.get(&label) {
562 f.destroy(&[&key_string]);
563 }
564 }
565 }
566 }
567}