use super::router::{Messenger, OwnedMessenger};
use crate::{
Channel, Message as NetworkMessage, Recipients,
utils::limited::{CheckedSender, LimitedSender},
};
use commonware_actor::{
Feedback, Unreliable,
mailbox::{self, UnreliablePolicy},
};
use commonware_cryptography::PublicKey;
use commonware_runtime::{Clock, IoBufs, Metrics, Quota};
use std::{
collections::{BTreeMap, VecDeque},
fmt::Debug,
num::NonZeroUsize,
sync::Arc,
time::SystemTime,
};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error("network closed")]
NetworkClosed,
}
pub(crate) struct Inbound<P: PublicKey>(pub(crate) NetworkMessage<P>);
impl<P: PublicKey> UnreliablePolicy for Inbound<P> {
type Overflow = VecDeque<Self>;
fn handle(_overflow: &mut Self::Overflow, _message: Self) -> bool {
false
}
}
#[derive(Debug, Clone)]
pub struct UnlimitedSender<P: PublicKey> {
channel: Channel,
max_size: u32,
messenger: Messenger<P>,
}
impl<P: PublicKey> crate::UnlimitedSender for UnlimitedSender<P> {
type PublicKey = P;
fn send(
&mut self,
recipients: Recipients<Self::PublicKey>,
message: impl Into<IoBufs> + Send,
priority: bool,
) -> Unreliable<Feedback> {
let message = message.into();
assert!(
message.len() <= self.max_size as usize,
"message too large: {} > {}",
message.len(),
self.max_size
);
self.messenger
.content(recipients, self.channel, message, priority)
}
}
pub struct Sender<P: PublicKey, C: Clock> {
limited_sender: LimitedSender<C, UnlimitedSender<P>, Messenger<P>>,
}
impl<P: PublicKey, C: Clock> Clone for Sender<P, C> {
fn clone(&self) -> Self {
Self {
limited_sender: self.limited_sender.clone(),
}
}
}
impl<P: PublicKey, C: Clock> Sender<P, C> {
pub(super) fn new(
channel: Channel,
max_size: u32,
messenger: Messenger<P>,
clock: C,
quota: Quota,
) -> Self {
let master_sender = UnlimitedSender {
channel,
max_size,
messenger: messenger.clone(),
};
let limited_sender = LimitedSender::new(master_sender, quota, clock, messenger);
Self { limited_sender }
}
}
impl<P, C> crate::LimitedSender for Sender<P, C>
where
P: PublicKey,
C: Clock + Send + 'static,
{
type PublicKey = P;
type Checked<'a>
= CheckedSender<'a, UnlimitedSender<P>>
where
Self: 'a;
fn check(
&mut self,
recipients: Recipients<Self::PublicKey>,
) -> Result<Self::Checked<'_>, SystemTime> {
self.limited_sender.check(recipients)
}
}
pub struct Receiver<P: PublicKey> {
receiver: mailbox::UnreliableReceiver<Inbound<P>>,
}
impl<P: PublicKey> Debug for Receiver<P> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Receiver").finish_non_exhaustive()
}
}
impl<P: PublicKey> Receiver<P> {
pub(super) const fn new(receiver: mailbox::UnreliableReceiver<Inbound<P>>) -> Self {
Self { receiver }
}
}
impl<P: PublicKey> crate::Receiver for Receiver<P> {
type Error = Error;
type PublicKey = P;
async fn recv(&mut self) -> Result<NetworkMessage<Self::PublicKey>, Error> {
let Inbound((sender, message)) = self.receiver.recv().await.ok_or(Error::NetworkClosed)?;
Ok((sender, message))
}
}
#[derive(Clone, Debug)]
pub struct Channels<P: PublicKey> {
messenger: Arc<OwnedMessenger<P>>,
max_size: u32,
max_peers: NonZeroUsize,
outbound_capacity: usize,
receivers: BTreeMap<Channel, (Quota, mailbox::UnreliableSender<Inbound<P>>)>,
}
impl<P: PublicKey> Channels<P> {
pub const fn new(
messenger: Arc<OwnedMessenger<P>>,
max_size: u32,
max_peers: NonZeroUsize,
) -> Self {
Self {
messenger,
max_size,
max_peers,
outbound_capacity: 0,
receivers: BTreeMap::new(),
}
}
pub(super) const fn outbound_mailbox_size(&self, base: NonZeroUsize) -> NonZeroUsize {
base.checked_add(self.outbound_capacity)
.expect("router mailbox capacity overflow")
}
pub(super) fn bind(&self, mailbox: super::router::Mailbox<P>) {
self.messenger.bind(mailbox);
}
pub fn register<C: Clock + Metrics>(
&mut self,
channel: Channel,
rate: Quota,
context: C,
) -> (Sender<P, C>, Receiver<P>) {
if self.receivers.contains_key(&channel) {
panic!("duplicate channel registration: {channel}");
}
let capacity = self
.max_peers
.get()
.checked_mul(rate.burst_size().get() as usize)
.and_then(NonZeroUsize::new)
.expect("channel mailbox capacity overflow");
self.outbound_capacity = self
.outbound_capacity
.checked_add(capacity.get())
.expect("router mailbox capacity overflow");
let (sender, receiver) = mailbox::new_unreliable(context.child("mailbox"), capacity);
assert!(self.receivers.insert(channel, (rate, sender)).is_none());
(
Sender::new(
channel,
self.max_size,
self.messenger.handle(),
context,
rate,
),
Receiver::new(receiver),
)
}
pub fn collect(self) -> BTreeMap<u64, (Quota, mailbox::UnreliableSender<Inbound<P>>)> {
self.receivers
}
}
#[cfg(test)]
mod tests {
use super::*;
use commonware_cryptography::{
Signer as _,
ed25519::{PrivateKey, PublicKey},
};
use commonware_runtime::{
BufferPooler as _, IoBuf, Runner as _, Supervisor as _, deterministic,
};
use commonware_utils::{NZU32, NZUsize};
#[test]
fn registered_rate_sizes_inbound_mailbox_for_every_peer() {
deterministic::Runner::default().start(|context| async move {
let messenger = Messenger::unbound(context.network_buffer_pool().clone());
let mut channels = Channels::new(messenger, 1024, NZUsize!(2));
let quota = Quota::per_second(NZU32!(2));
let (_, mut receiver) = channels.register(1, quota, context.child("channel"));
let inbound = channels.receivers.get(&1).unwrap().1.clone();
let peer = PrivateKey::from_seed(1).public_key();
for _ in 0..4 {
assert!(
inbound
.enqueue(Inbound((peer.clone(), IoBuf::from(b"message"))))
.accepted()
);
}
assert_eq!(
inbound.enqueue(Inbound((peer, IoBuf::from(b"overflow")))),
Unreliable::Rejected
);
for _ in 0..4 {
assert!(receiver.receiver.try_recv().is_ok());
}
});
}
#[test]
fn registered_rates_size_shared_outbound_mailbox() {
deterministic::Runner::default().start(|context| async move {
let messenger = Messenger::<PublicKey>::unbound(context.network_buffer_pool().clone());
let mut channels = Channels::new(messenger, 1024, NZUsize!(2));
let quota = Quota::per_second(NZU32!(2));
let _ = channels.register(1, quota, context.child("first"));
let _ = channels.register(2, quota, context.child("second"));
assert_eq!(channels.outbound_mailbox_size(NZUsize!(2)), NZUsize!(10));
});
}
#[test]
#[should_panic(expected = "router mailbox capacity overflow")]
fn outbound_mailbox_size_panics_on_overflow() {
deterministic::Runner::default().start(|context| async move {
let messenger = Messenger::unbound(context.network_buffer_pool().clone());
let mut channels = Channels::<PublicKey>::new(messenger, 1024, NZUsize!(1));
channels.outbound_capacity = 1;
channels.outbound_mailbox_size(NonZeroUsize::new(usize::MAX).unwrap());
});
}
#[test]
#[should_panic(expected = "channel mailbox capacity overflow")]
fn derived_capacity_panics_on_overflow() {
let rate = Quota::per_second(NZU32!(2));
deterministic::Runner::default().start(|context| async move {
let messenger = Messenger::unbound(context.network_buffer_pool().clone());
let mut channels =
Channels::<PublicKey>::new(messenger, 1024, NonZeroUsize::new(usize::MAX).unwrap());
let _ = channels.register(0, rate, context);
});
}
}