Skip to main content

cliquenet/
lib.rs

1mod addr;
2mod connection;
3mod metrics;
4mod msg;
5mod net;
6mod queue;
7mod time;
8mod util;
9
10pub mod error;
11pub mod noise;
12pub mod x25519;
13
14use std::{collections::BTreeMap, fmt, num::NonZeroUsize, sync::Arc, time::Duration};
15
16pub use addr::NetAddr;
17use bon::Builder;
18pub use error::NetworkError;
19pub use metrics::Metrics;
20pub use msg::Slot;
21pub use net::{
22    Network, NetworkController, NetworkReceiver, RetryPolicy, SendAction, SendCommand,
23    SendCommandBuilder,
24};
25
26use crate::{
27    util::nonempty::NonEmpty,
28    x25519::{Keypair, PublicKey},
29};
30
31#[derive(Builder)]
32#[builder(finish_fn(vis = "", name = "internal_build"))]
33#[non_exhaustive]
34pub struct Config {
35    /// Network name.
36    #[builder(with = |s: impl Into<String>| Arc::new(s.into()))]
37    name: Arc<String>,
38
39    /// The supported noise protocols.
40    ///
41    /// Nodes negotiate a common supported version which implies the exact
42    /// noise protocol parameters they are going to use for the subsequent
43    /// handshake.
44    ///
45    /// With this map, a node specifies the noise protocol names it supports
46    /// per version number.
47    #[builder(with = |it: impl IntoIterator<Item = (Version, noise::Protocol)>| {
48        NonEmpty::assert_non_empty_map(it)
49    })]
50    noise_protocols: NonEmpty<BTreeMap<Version, noise::Protocol>>,
51
52    /// DH keypair
53    keypair: Keypair,
54
55    /// Address to bind to.
56    bind: NetAddr,
57
58    /// Network members with public key and network address.
59    #[builder(with = <_>::from_iter)]
60    parties: Vec<(PublicKey, NetAddr)>,
61
62    #[builder(default = NonZeroUsize::new(100).expect("100 > 0"))]
63    peer_budget: NonZeroUsize,
64
65    /// Max. number of bytes per message to send or receive.
66    #[builder(default = NonZeroUsize::new(10485760).expect("10485760 > 0"))]
67    max_message_size: NonZeroUsize,
68
69    /// Connect retry delays in seconds.
70    #[builder(
71        default = NonEmpty::new(1, [3, 5, 15, 30]),
72        with = |it: impl IntoIterator<Item = u8>| NonEmpty::assert_non_empty_vec(it)
73    )]
74    connect_retry_delays: NonEmpty<Vec<u8>>,
75
76    /// Send retry delays in seconds.
77    #[builder(
78        default = NonEmpty::new(5, [15, 30]),
79        with = |it: impl IntoIterator<Item = u8>| NonEmpty::assert_non_empty_vec(it)
80    )]
81    send_retry_delays: NonEmpty<Vec<u8>>,
82
83    /// Randomly delay the initial connect attempt between 0 and 1s.
84    #[builder(default = true)]
85    random_connect_delay: bool,
86
87    /// How long to wait to establish a TCP connection?
88    #[builder(default = Duration::from_secs(30))]
89    connect_timeout: Duration,
90
91    /// How long to wait for a noise handshake to complete?
92    #[builder(default = Duration::from_secs(10))]
93    handshake_timeout: Duration,
94
95    /// After sending a message we expect to hear back from the peer.
96    ///
97    /// If we do not receive anything for this duration we reconnect.
98    #[builder(default = Duration::from_secs(30))]
99    receive_timeout: Duration,
100
101    /// If a party is not known we tell it to back off for this amount of time.
102    ///
103    /// This may happen when not all peers have a consistent configuration.
104    #[builder(default = Duration::from_secs(30))]
105    backoff_duration: Duration,
106
107    /// Optional metrics implementation.
108    metrics: Option<Arc<dyn Metrics>>,
109}
110
111impl<S: config_builder::IsComplete> ConfigBuilder<S> {
112    pub fn build(self) -> Config {
113        let conf = self.internal_build();
114
115        let v1 = conf.noise_protocols.iter().map(|(k, _)| k);
116        let v2 = conf.noise_protocols.iter().map(|(k, _)| k).skip(1);
117        assert! {
118            v1.zip(v2).all(|(a, b)| u16::from(*a) + 1 == u16::from(*b)),
119            "cliquenet configuration requires consecutive noise protocol versions"
120        }
121
122        conf
123    }
124}
125
126impl fmt::Debug for Config {
127    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
128        f.debug_struct("Config")
129            .field("name", &self.name)
130            .field("key", &self.keypair.public_key())
131            .field("bind", &self.bind)
132            .field("parties", &self.parties)
133            .field("peer_budget", &self.peer_budget)
134            .field("max_message_size", &self.max_message_size)
135            .field("connect_retry_delays", &self.connect_retry_delays)
136            .field("send_retry_delays", &self.send_retry_delays)
137            .field("random_connect_delay", &self.random_connect_delay)
138            .field("connect_timeout", &self.connect_timeout)
139            .field("handshake_timeout", &self.handshake_timeout)
140            .field("receive_timeout", &self.receive_timeout)
141            .field("backoff_duration", &self.backoff_duration)
142            .finish()
143    }
144}
145
146impl Config {
147    pub fn public_key(&self) -> PublicKey {
148        self.keypair.public_key()
149    }
150
151    pub fn with_metrics<M: Metrics + 'static>(mut self, m: M) -> Self {
152        self.metrics = Some(Arc::new(m));
153        self
154    }
155}
156
157/// Network peer role.
158#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
159pub enum Role {
160    /// Active peers receive broadcast messages.
161    Active,
162    /// Passive peers are excluded from broadcasts.
163    ///
164    /// Note however that passive peers can be addressed directly in
165    /// unicast or multicast operations.
166    Passive,
167}
168
169impl Role {
170    pub fn is_active(self) -> bool {
171        matches!(self, Self::Active)
172    }
173}
174
175impl fmt::Display for Role {
176    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177        match self {
178            Self::Active => f.write_str("active"),
179            Self::Passive => f.write_str("passive"),
180        }
181    }
182}
183
184#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
185pub struct Version(u16);
186
187impl From<u16> for Version {
188    fn from(v: u16) -> Self {
189        Self(v)
190    }
191}
192
193impl From<Version> for u16 {
194    fn from(v: Version) -> Self {
195        v.0
196    }
197}
198
199impl fmt::Display for Version {
200    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201        self.0.fmt(f)
202    }
203}