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    /// Optional metrics implementation.
122    metrics: Option<Arc<dyn Metrics>>,
123}
124
125impl<S: config_builder::IsComplete> ConfigBuilder<S> {
126    pub fn build(self) -> Config {
127        let conf = self.internal_build();
128
129        let v1 = conf.noise_protocols.iter().map(|(k, _)| k);
130        let v2 = conf.noise_protocols.iter().map(|(k, _)| k).skip(1);
131        assert! {
132            v1.zip(v2).all(|(a, b)| u16::from(*a) + 1 == u16::from(*b)),
133            "cliquenet configuration requires consecutive noise protocol versions"
134        }
135
136        conf
137    }
138}
139
140impl fmt::Debug for Config {
141    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142        f.debug_struct("Config")
143            .field("name", &self.name)
144            .field("key", &self.keypair.public_key())
145            .field("bind", &self.bind)
146            .field("parties", &self.parties)
147            .field("peer_budget", &self.peer_budget)
148            .field("max_message_size", &self.max_message_size)
149            .field("connect_retry_delays", &self.connect_retry_delays)
150            .field("send_retry_delays", &self.send_retry_delays)
151            .field("random_connect_delay", &self.random_connect_delay)
152            .field("connect_timeout", &self.connect_timeout)
153            .field("handshake_timeout", &self.handshake_timeout)
154            .field("receive_timeout", &self.receive_timeout)
155            .field("backoff_duration", &self.backoff_duration)
156            .field("keepalive_after", &self.keep_alive_after)
157            .field("keepalive_interval", &self.keep_alive_interval)
158            .field("keepalive_retries", &self.keep_alive_retries)
159            .finish()
160    }
161}
162
163impl Config {
164    pub fn public_key(&self) -> PublicKey {
165        self.keypair.public_key()
166    }
167
168    pub fn with_metrics<M: Metrics + 'static>(mut self, m: M) -> Self {
169        self.metrics = Some(Arc::new(m));
170        self
171    }
172}
173
174/// Network peer role.
175#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
176pub enum Role {
177    /// Active peers receive broadcast messages.
178    Active,
179    /// Passive peers are excluded from broadcasts.
180    ///
181    /// Note however that passive peers can be addressed directly in
182    /// unicast or multicast operations.
183    Passive,
184}
185
186impl Role {
187    pub fn is_active(self) -> bool {
188        matches!(self, Self::Active)
189    }
190}
191
192impl fmt::Display for Role {
193    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
194        match self {
195            Self::Active => f.write_str("active"),
196            Self::Passive => f.write_str("passive"),
197        }
198    }
199}
200
201#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
202pub struct Version(u16);
203
204impl From<u16> for Version {
205    fn from(v: u16) -> Self {
206        Self(v)
207    }
208}
209
210impl From<Version> for u16 {
211    fn from(v: Version) -> Self {
212        v.0
213    }
214}
215
216impl fmt::Display for Version {
217    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218        self.0.fmt(f)
219    }
220}