Skip to main content

commonware_p2p/authenticated/discovery/
network.rs

1//! Implementation of an `authenticated` network.
2
3use super::{
4    actors::{dialer, listener, router, spawner, tracker},
5    channels::{self, Channels},
6    config::Config,
7    types,
8};
9use crate::{authenticated::discovery::types::InfoVerifier, Channel};
10use commonware_cryptography::Signer;
11use commonware_macros::select;
12use commonware_runtime::{
13    spawn_cell, BufferPooler, Clock, ContextCell, Handle, Metrics, Network as RNetwork, Quota,
14    Resolver, Spawner,
15};
16use commonware_stream::encrypted::Config as StreamConfig;
17use commonware_utils::union;
18use rand_core::CryptoRng;
19use tracing::{debug, info};
20
21/// Unique suffix for all messages signed by the tracker.
22const TRACKER_SUFFIX: &[u8] = b"_TRACKER";
23
24/// Unique suffix for all messages signed in a stream.
25const STREAM_SUFFIX: &[u8] = b"_STREAM";
26
27/// Implementation of an `authenticated` network.
28pub struct Network<
29    E: Spawner + BufferPooler + Clock + CryptoRng + RNetwork + Resolver + Metrics,
30    C: Signer,
31> {
32    context: ContextCell<E>,
33    cfg: Config<C>,
34
35    channels: Channels<C::PublicKey>,
36    tracker: tracker::Actor<E, C>,
37    tracker_mailbox: tracker::Mailbox<C::PublicKey>,
38    router: router::Actor<E, C::PublicKey>,
39    router_mailbox: router::Mailbox<C::PublicKey>,
40    info_verifier: InfoVerifier<C::PublicKey>,
41}
42
43impl<E: Spawner + BufferPooler + Clock + CryptoRng + RNetwork + Resolver + Metrics, C: Signer>
44    Network<E, C>
45{
46    /// Create a new instance of an `authenticated` network.
47    ///
48    /// # Parameters
49    ///
50    /// * `cfg` - Configuration for the network.
51    ///
52    /// # Returns
53    ///
54    /// * A tuple containing the network instance and the oracle that
55    ///   can be used by a developer to configure which peers are authorized.
56    pub fn new(context: E, cfg: Config<C>) -> (Self, tracker::Oracle<C::PublicKey>) {
57        let (tracker, tracker_mailbox, oracle, info_verifier) = tracker::Actor::new(
58            context.child("tracker"),
59            tracker::Config {
60                crypto: cfg.crypto.clone(),
61                namespace: union(&cfg.namespace, TRACKER_SUFFIX),
62                address: cfg.dialable.clone(),
63                bootstrappers: cfg.bootstrappers.clone(),
64                allow_private_ips: cfg.allow_private_ips,
65                allow_dns: cfg.allow_dns,
66                synchrony_bound: cfg.synchrony_bound,
67                mailbox_size: cfg.mailbox_size,
68                tracked_peer_sets: cfg.tracked_peer_sets,
69                peer_connection_cooldown: cfg.peer_connection_cooldown,
70                peer_gossip_max_count: cfg.peer_gossip_max_count,
71                max_peer_set_size: cfg.max_peer_set_size,
72                dial_fail_limit: cfg.dial_fail_limit,
73                block_duration: cfg.block_duration,
74            },
75        );
76        let (router, router_mailbox, messenger) = router::Actor::new(
77            context.child("router"),
78            router::Config {
79                mailbox_size: cfg.mailbox_size,
80            },
81        );
82        let channels = Channels::new(messenger, cfg.max_message_size);
83
84        (
85            Self {
86                context: ContextCell::new(context),
87                cfg,
88
89                channels,
90                tracker,
91                tracker_mailbox,
92                router,
93                router_mailbox,
94                info_verifier,
95            },
96            oracle,
97        )
98    }
99
100    /// Register a new channel over the network.
101    ///
102    /// # Parameters
103    ///
104    /// * `channel` - Unique identifier for the channel.
105    /// * `rate` - Rate at which messages can be received over the channel.
106    /// * `backlog` - Maximum number of messages that can be queued on the channel before blocking.
107    ///
108    /// # Returns
109    ///
110    /// * A tuple containing the sender and receiver for the channel (how to communicate
111    ///   with external peers on the network). It is safe to close either the sender or receiver
112    ///   without impacting the ability to process messages on other channels.
113    #[allow(clippy::type_complexity)]
114    pub fn register(
115        &mut self,
116        channel: Channel,
117        rate: Quota,
118        backlog: usize,
119    ) -> (
120        channels::Sender<C::PublicKey, E>,
121        channels::Receiver<C::PublicKey>,
122    ) {
123        let context = self
124            .context
125            .child("channel")
126            .with_attribute("index", channel);
127        self.channels.register(channel, rate, backlog, context)
128    }
129
130    /// Starts the network.
131    ///
132    /// After the network is started, it is not possible to add more channels.
133    pub fn start(mut self) -> Handle<()> {
134        spawn_cell!(self.context, self.run())
135    }
136
137    async fn run(self) {
138        // Start tracker
139        let mut tracker_task = self.tracker.start();
140
141        // Start router
142        let mut router_task = self.router.start(self.channels);
143
144        // Start spawner
145        let (spawner, spawner_mailbox) = spawner::Actor::new(
146            self.context.child("spawner"),
147            spawner::Config {
148                mailbox_size: self.cfg.mailbox_size,
149                send_batch_size: self.cfg.send_batch_size,
150                gossip_bit_vec_frequency: self.cfg.gossip_bit_vec_frequency,
151                max_peer_set_size: self.cfg.max_peer_set_size,
152                peer_gossip_max_count: self.cfg.peer_gossip_max_count,
153                info_verifier: self.info_verifier,
154            },
155        );
156        let mut spawner_task =
157            spawner.start(self.tracker_mailbox.clone(), self.router_mailbox.clone());
158
159        // Start listener
160        let stream_cfg = StreamConfig {
161            signing_key: self.cfg.crypto,
162            namespace: union(&self.cfg.namespace, STREAM_SUFFIX),
163            max_message_size: self
164                .cfg
165                .max_message_size
166                .saturating_add(types::MAX_PAYLOAD_DATA_OVERHEAD),
167            synchrony_bound: self.cfg.synchrony_bound,
168            max_handshake_age: self.cfg.max_handshake_age,
169            handshake_timeout: self.cfg.handshake_timeout,
170        };
171        let listener = listener::Actor::new(
172            self.context.child("listener"),
173            listener::Config {
174                address: self.cfg.listen,
175                stream_cfg: stream_cfg.clone(),
176                allow_private_ips: self.cfg.allow_private_ips,
177                max_concurrent_handshakes: self.cfg.max_concurrent_handshakes,
178                allowed_handshake_rate_per_ip: self.cfg.allowed_handshake_rate_per_ip,
179                allowed_handshake_rate_per_subnet: self.cfg.allowed_handshake_rate_per_subnet,
180            },
181        );
182        let mut listener_task =
183            listener.start(self.tracker_mailbox.clone(), spawner_mailbox.clone());
184
185        // Start dialer
186        let dialer = dialer::Actor::new(
187            self.context.child("dialer"),
188            dialer::Config {
189                stream_cfg,
190                dial_frequency: self.cfg.dial_frequency,
191                peer_connection_cooldown: self.cfg.peer_connection_cooldown,
192                allow_private_ips: self.cfg.allow_private_ips,
193            },
194        );
195        let mut dialer_task = dialer.start(self.tracker_mailbox, spawner_mailbox);
196
197        let mut shutdown = self.context.stopped();
198
199        // If any task completes, the network should stop
200        info!("network started");
201        select! {
202            _ = &mut shutdown => {
203                debug!("context shutdown, stopping network");
204            },
205            tracker = &mut tracker_task => {
206                debug!(?tracker, "tracker stopped, shutting down network");
207            },
208            router = &mut router_task => {
209                debug!(?router, "router stopped, shutting down network");
210            },
211            spawner = &mut spawner_task => {
212                debug!(?spawner, "spawner stopped, shutting down network");
213            },
214            listener = &mut listener_task => {
215                debug!(?listener, "listener stopped, shutting down network");
216            },
217            dialer = &mut dialer_task => {
218                debug!(?dialer, "dialer stopped, shutting down network");
219            },
220        }
221    }
222}