Skip to main content

subspace_networking/
behavior.rs

1#![expect(
2    unreachable_code,
3    reason = "Some kind of false-positive related to proc macro handling"
4)]
5
6pub(crate) mod persistent_parameters;
7#[cfg(test)]
8mod tests;
9
10use crate::constructor::DummyRecordStore;
11use crate::protocols::autonat_wrapper::{
12    Behaviour as AutonatWrapper, Config as AutonatWrapperConfig,
13};
14use crate::protocols::request_response::request_response_factory::{
15    Event as RequestResponseEvent, RequestHandler, RequestResponseFactoryBehaviour,
16};
17use crate::protocols::reserved_peers::{
18    Behaviour as ReservedPeersBehaviour, Config as ReservedPeersConfig, Event as ReservedPeersEvent,
19};
20use crate::protocols::subspace_connection_limits::Behaviour as ConnectionLimitsBehaviour;
21use derive_more::From;
22use libp2p::PeerId;
23use libp2p::allow_block_list::{Behaviour as AllowBlockListBehaviour, BlockedPeers};
24use libp2p::autonat::Event as AutonatEvent;
25use libp2p::connection_limits::ConnectionLimits;
26use libp2p::gossipsub::{
27    Behaviour as Gossipsub, Config as GossipsubConfig, Event as GossipsubEvent, MessageAuthenticity,
28};
29use libp2p::identify::{Behaviour as Identify, Config as IdentifyConfig, Event as IdentifyEvent};
30use libp2p::kad::{Behaviour as Kademlia, Config as KademliaConfig, Event as KademliaEvent};
31use libp2p::ping::{Behaviour as Ping, Event as PingEvent};
32use libp2p::swarm::NetworkBehaviour;
33use libp2p::swarm::behaviour::toggle::Toggle;
34use void::Void as VoidEvent;
35
36type BlockListBehaviour = AllowBlockListBehaviour<BlockedPeers>;
37
38pub(crate) struct BehaviorConfig {
39    /// Identity keypair of a node used for authenticated connections.
40    pub(crate) peer_id: PeerId,
41    /// The configuration for the [`Identify`] behaviour.
42    pub(crate) identify: IdentifyConfig,
43    /// The configuration for the [`Kademlia`] behaviour.
44    pub(crate) kademlia: KademliaConfig,
45    /// The configuration for the [`Gossipsub`] behaviour.
46    pub(crate) gossipsub: Option<GossipsubConfig>,
47    /// The configuration for the [`RequestResponsesBehaviour`] protocol.
48    pub(crate) request_response_protocols: Vec<Box<dyn RequestHandler>>,
49    /// The upper bound for the number of concurrent inbound + outbound streams for request/response
50    /// protocols.
51    pub(crate) request_response_max_concurrent_streams: usize,
52    /// Connection limits for the swarm.
53    pub(crate) connection_limits: ConnectionLimits,
54    /// The configuration for the [`ReservedPeersBehaviour`].
55    pub(crate) reserved_peers: ReservedPeersConfig,
56    /// Autonat configuration.
57    pub(crate) autonat: AutonatWrapperConfig,
58}
59
60#[derive(NetworkBehaviour)]
61#[behaviour(to_swarm = "Event")]
62pub(crate) struct Behavior {
63    // TODO: Connection limits must be the first protocol due to https://github.com/libp2p/rust-libp2p/issues/4773 as
64    //  suggested in https://github.com/libp2p/rust-libp2p/issues/4898#issuecomment-1818013483
65    pub(crate) connection_limits: ConnectionLimitsBehaviour,
66    pub(crate) identify: Identify,
67    pub(crate) kademlia: Kademlia<DummyRecordStore>,
68    pub(crate) gossipsub: Toggle<Gossipsub>,
69    pub(crate) ping: Ping,
70    pub(crate) request_response: RequestResponseFactoryBehaviour,
71    pub(crate) block_list: BlockListBehaviour,
72    pub(crate) reserved_peers: ReservedPeersBehaviour,
73    pub(crate) autonat: AutonatWrapper,
74}
75
76impl Behavior {
77    pub(crate) fn new(config: BehaviorConfig) -> Self {
78        let kademlia = Kademlia::with_config(config.peer_id, DummyRecordStore, config.kademlia);
79
80        let gossipsub = config
81            .gossipsub
82            .map(|gossip_config| {
83                Gossipsub::new(
84                    // TODO: Do we want message signing?
85                    MessageAuthenticity::Anonymous,
86                    gossip_config,
87                )
88                .expect("Correct configuration")
89            })
90            .into();
91
92        Self {
93            connection_limits: ConnectionLimitsBehaviour::new(config.connection_limits),
94            identify: Identify::new(config.identify),
95            kademlia,
96            gossipsub,
97            ping: Ping::default(),
98            request_response: RequestResponseFactoryBehaviour::new(
99                config.request_response_protocols,
100                config.request_response_max_concurrent_streams,
101            )
102            //TODO: Convert to an error.
103            .expect("RequestResponse protocols registration failed."),
104            block_list: BlockListBehaviour::default(),
105            reserved_peers: ReservedPeersBehaviour::new(config.reserved_peers),
106            autonat: AutonatWrapper::new(config.autonat),
107        }
108    }
109}
110
111#[expect(clippy::large_enum_variant)]
112#[derive(Debug, From)]
113pub(crate) enum Event {
114    Identify(IdentifyEvent),
115    Kademlia(KademliaEvent),
116    Gossipsub(GossipsubEvent),
117    Ping(PingEvent),
118    RequestResponse(RequestResponseEvent),
119    /// Event stub for connection limits and block list behaviours. We won't receive such events.
120    VoidEventStub(VoidEvent),
121    ReservedPeers(ReservedPeersEvent),
122    Autonat(AutonatEvent),
123}
124
125// Infallible instances can never be created.
126impl From<!> for Event {
127    fn from(_: !) -> Self {
128        unreachable!()
129    }
130}