Skip to main content

cliquenet/
lib.rs

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