Skip to main content

commonware_p2p/authenticated/
channels.rs

1use super::router::{Messenger, OwnedMessenger};
2use crate::{
3    Channel, Message as NetworkMessage, Recipients,
4    utils::limited::{CheckedSender, LimitedSender},
5};
6use commonware_actor::{
7    Feedback, Unreliable,
8    mailbox::{self, UnreliablePolicy},
9};
10use commonware_cryptography::PublicKey;
11use commonware_runtime::{Clock, IoBufs, Metrics, Quota};
12use std::{
13    collections::{BTreeMap, VecDeque},
14    fmt::Debug,
15    num::NonZeroUsize,
16    sync::Arc,
17    time::SystemTime,
18};
19use thiserror::Error;
20
21/// Errors that can occur when interacting with the network.
22#[derive(Error, Debug)]
23pub enum Error {
24    #[error("network closed")]
25    NetworkClosed,
26}
27
28pub(crate) struct Inbound<P: PublicKey>(pub(crate) NetworkMessage<P>);
29
30impl<P: PublicKey> UnreliablePolicy for Inbound<P> {
31    type Overflow = VecDeque<Self>;
32
33    fn handle(_overflow: &mut Self::Overflow, _message: Self) -> bool {
34        false
35    }
36}
37
38/// An interior sender that enforces message size limits and
39/// supports sending arbitrary bytes to a set of recipients over
40/// a pre-defined [`Channel`].
41#[derive(Debug, Clone)]
42pub struct UnlimitedSender<P: PublicKey> {
43    channel: Channel,
44    max_size: u32,
45    messenger: Messenger<P>,
46}
47
48impl<P: PublicKey> crate::UnlimitedSender for UnlimitedSender<P> {
49    type PublicKey = P;
50
51    fn send(
52        &mut self,
53        recipients: Recipients<Self::PublicKey>,
54        message: impl Into<IoBufs> + Send,
55        priority: bool,
56    ) -> Unreliable<Feedback> {
57        let message = message.into();
58        assert!(
59            message.len() <= self.max_size as usize,
60            "message too large: {} > {}",
61            message.len(),
62            self.max_size
63        );
64
65        self.messenger
66            .content(recipients, self.channel, message, priority)
67    }
68}
69
70/// Sends arbitrary bytes over one registered channel.
71///
72/// The channel's quota is shared across clones and enforced independently for each recipient.
73/// All registered channels share one outbound router mailbox. Each channel contributes one quota
74/// burst for every configured peer, but does not reserve that capacity exclusively.
75pub struct Sender<P: PublicKey, C: Clock> {
76    limited_sender: LimitedSender<C, UnlimitedSender<P>, Messenger<P>>,
77}
78
79impl<P: PublicKey, C: Clock> Clone for Sender<P, C> {
80    fn clone(&self) -> Self {
81        Self {
82            limited_sender: self.limited_sender.clone(),
83        }
84    }
85}
86
87impl<P: PublicKey, C: Clock> Sender<P, C> {
88    pub(super) fn new(
89        channel: Channel,
90        max_size: u32,
91        messenger: Messenger<P>,
92        clock: C,
93        quota: Quota,
94    ) -> Self {
95        let master_sender = UnlimitedSender {
96            channel,
97            max_size,
98            messenger: messenger.clone(),
99        };
100        let limited_sender = LimitedSender::new(master_sender, quota, clock, messenger);
101        Self { limited_sender }
102    }
103}
104
105impl<P, C> crate::LimitedSender for Sender<P, C>
106where
107    P: PublicKey,
108    C: Clock + Send + 'static,
109{
110    type PublicKey = P;
111    type Checked<'a>
112        = CheckedSender<'a, UnlimitedSender<P>>
113    where
114        Self: 'a;
115
116    fn check(
117        &mut self,
118        recipients: Recipients<Self::PublicKey>,
119    ) -> Result<Self::Checked<'_>, SystemTime> {
120        self.limited_sender.check(recipients)
121    }
122}
123
124/// Lossy receiver for one registered channel.
125///
126/// Every peer connection feeds the same bounded inbound mailbox after independent per-peer rate
127/// limiting. If the mailbox is full, the arriving message is dropped and queued messages remain.
128/// Its capacity holds one quota burst from every peer allowed by the network configuration.
129pub struct Receiver<P: PublicKey> {
130    receiver: mailbox::UnreliableReceiver<Inbound<P>>,
131}
132
133impl<P: PublicKey> Debug for Receiver<P> {
134    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135        f.debug_struct("Receiver").finish_non_exhaustive()
136    }
137}
138
139impl<P: PublicKey> Receiver<P> {
140    pub(super) const fn new(receiver: mailbox::UnreliableReceiver<Inbound<P>>) -> Self {
141        Self { receiver }
142    }
143}
144
145impl<P: PublicKey> crate::Receiver for Receiver<P> {
146    type Error = Error;
147    type PublicKey = P;
148
149    /// Receives a message from the channel.
150    ///
151    /// This method will block until a message is received or the underlying
152    /// network shuts down.
153    async fn recv(&mut self) -> Result<NetworkMessage<Self::PublicKey>, Error> {
154        let Inbound((sender, message)) = self.receiver.recv().await.ok_or(Error::NetworkClosed)?;
155
156        // We don't check that the message is too large here because we already enforce
157        // that on the network layer.
158        Ok((sender, message))
159    }
160}
161
162#[derive(Clone, Debug)]
163pub struct Channels<P: PublicKey> {
164    messenger: Arc<OwnedMessenger<P>>,
165    max_size: u32,
166    max_peers: NonZeroUsize,
167    outbound_capacity: usize,
168    receivers: BTreeMap<Channel, (Quota, mailbox::UnreliableSender<Inbound<P>>)>,
169}
170
171impl<P: PublicKey> Channels<P> {
172    pub const fn new(
173        messenger: Arc<OwnedMessenger<P>>,
174        max_size: u32,
175        max_peers: NonZeroUsize,
176    ) -> Self {
177        Self {
178            messenger,
179            max_size,
180            max_peers,
181            outbound_capacity: 0,
182            receivers: BTreeMap::new(),
183        }
184    }
185
186    /// Adds internal-message headroom to the capacity derived from registered channel quotas.
187    ///
188    /// Internal and application messages share the entire router mailbox.
189    pub(super) const fn outbound_mailbox_size(&self, base: NonZeroUsize) -> NonZeroUsize {
190        base.checked_add(self.outbound_capacity)
191            .expect("router mailbox capacity overflow")
192    }
193
194    /// Connects every registered channel sender to the router mailbox.
195    pub(super) fn bind(&self, mailbox: super::router::Mailbox<P>) {
196        self.messenger.bind(mailbox);
197    }
198
199    pub fn register<C: Clock + Metrics>(
200        &mut self,
201        channel: Channel,
202        rate: Quota,
203        context: C,
204    ) -> (Sender<P, C>, Receiver<P>) {
205        if self.receivers.contains_key(&channel) {
206            panic!("duplicate channel registration: {channel}");
207        }
208        let capacity = self
209            .max_peers
210            .get()
211            .checked_mul(rate.burst_size().get() as usize)
212            .and_then(NonZeroUsize::new)
213            .expect("channel mailbox capacity overflow");
214        self.outbound_capacity = self
215            .outbound_capacity
216            .checked_add(capacity.get())
217            .expect("router mailbox capacity overflow");
218        let (sender, receiver) = mailbox::new_unreliable(context.child("mailbox"), capacity);
219        assert!(self.receivers.insert(channel, (rate, sender)).is_none());
220        (
221            Sender::new(
222                channel,
223                self.max_size,
224                self.messenger.handle(),
225                context,
226                rate,
227            ),
228            Receiver::new(receiver),
229        )
230    }
231
232    pub fn collect(self) -> BTreeMap<u64, (Quota, mailbox::UnreliableSender<Inbound<P>>)> {
233        self.receivers
234    }
235}
236
237#[cfg(test)]
238mod tests {
239    use super::*;
240    use commonware_cryptography::{
241        Signer as _,
242        ed25519::{PrivateKey, PublicKey},
243    };
244    use commonware_runtime::{
245        BufferPooler as _, IoBuf, Runner as _, Supervisor as _, deterministic,
246    };
247    use commonware_utils::{NZU32, NZUsize};
248
249    #[test]
250    fn registered_rate_sizes_inbound_mailbox_for_every_peer() {
251        deterministic::Runner::default().start(|context| async move {
252            let messenger = Messenger::unbound(context.network_buffer_pool().clone());
253            let mut channels = Channels::new(messenger, 1024, NZUsize!(2));
254            let quota = Quota::per_second(NZU32!(2));
255            let (_, mut receiver) = channels.register(1, quota, context.child("channel"));
256            let inbound = channels.receivers.get(&1).unwrap().1.clone();
257            let peer = PrivateKey::from_seed(1).public_key();
258
259            // Two peers can each contribute a two-message quota burst. Overflow leaves the four
260            // accepted messages queued.
261            for _ in 0..4 {
262                assert!(
263                    inbound
264                        .enqueue(Inbound((peer.clone(), IoBuf::from(b"message"))))
265                        .accepted()
266                );
267            }
268            assert_eq!(
269                inbound.enqueue(Inbound((peer, IoBuf::from(b"overflow")))),
270                Unreliable::Rejected
271            );
272
273            for _ in 0..4 {
274                assert!(receiver.receiver.try_recv().is_ok());
275            }
276        });
277    }
278
279    #[test]
280    fn registered_rates_size_shared_outbound_mailbox() {
281        deterministic::Runner::default().start(|context| async move {
282            let messenger = Messenger::<PublicKey>::unbound(context.network_buffer_pool().clone());
283            let mut channels = Channels::new(messenger, 1024, NZUsize!(2));
284            let quota = Quota::per_second(NZU32!(2));
285            let _ = channels.register(1, quota, context.child("first"));
286            let _ = channels.register(2, quota, context.child("second"));
287
288            // Two units of base headroom plus two channels with four slots each.
289            assert_eq!(channels.outbound_mailbox_size(NZUsize!(2)), NZUsize!(10));
290        });
291    }
292
293    #[test]
294    #[should_panic(expected = "router mailbox capacity overflow")]
295    fn outbound_mailbox_size_panics_on_overflow() {
296        deterministic::Runner::default().start(|context| async move {
297            let messenger = Messenger::unbound(context.network_buffer_pool().clone());
298            let mut channels = Channels::<PublicKey>::new(messenger, 1024, NZUsize!(1));
299            channels.outbound_capacity = 1;
300
301            channels.outbound_mailbox_size(NonZeroUsize::new(usize::MAX).unwrap());
302        });
303    }
304
305    #[test]
306    #[should_panic(expected = "channel mailbox capacity overflow")]
307    fn derived_capacity_panics_on_overflow() {
308        let rate = Quota::per_second(NZU32!(2));
309        deterministic::Runner::default().start(|context| async move {
310            let messenger = Messenger::unbound(context.network_buffer_pool().clone());
311            let mut channels =
312                Channels::<PublicKey>::new(messenger, 1024, NonZeroUsize::new(usize::MAX).unwrap());
313            let _ = channels.register(0, rate, context);
314        });
315    }
316}