- How do the behaviours we use in our swarm for the p2p network behave?
- Do they start advertising right away?
- What events to they generate and consume?
- How can we modify them when we introduce NAT traversal capabilities?
Swarm behaviour
- Interactions with (all) behaviours happen when one of the following methods is invoked
listen_on
- Dispatches
FromSwarm::NewListener
events
add_external_address
- Dispatches
FromSwarm::ExternalAddrConfirmed
events
remove_external_address
- Dispatches
FromSwarm::ExternalAddrExpired
events
add_peer_address
(not really relevant in our case)
- Calls
handle_pending_outbound_connection
of behavior
Identify
- The protocol is triggered after we explicitly
dial
with another peer, so we can interact with this in a way that we don’t start this too early (e.g., we can expose a first Swarm
instance on which we can only call setup_addresses
, which performs NAT traversal, before returning the result to the current Swarm
object).
- Once the swarm is started, the protocol starts when the node is dialed by another peer, and I think we don’t need to modify anything, as long as we can first run the NAT setup procedure
- If we don’t want to kill existing connections for addresses that have not changed, we need a more “elaborate” approach where we don’t kill existing connections when we go back to square 1 after an address changes. So we start from
UninitialisedSwarm
, we call UninitialisedSwarm::initialise().await
, we returns a Swarm
. Then, whenever an address changes, we can call Swarm::re_initialise(self)
which returns a PreviouslyInitialisedSwarm
, which has the job of checking what changed, and stop all substreams for the changed addresses, before starting AutoNAT again, and merging the previous and new streams, creating a new Swarm
, which will contain the old substreams + the new ones started with the new AutoNAT addresses.
- This actually applies to all the different behaviours, since we would run the first swarm before starting the second
- The only question is what happens when an address change, and how does that interact with the running behaviours, for instance with
Identify
. Will the new address be “leaked” automatically before we have the chance of running AutoNAT at all? Can we control this behaviour at all? If we can, maybe it makes using different types even not necessary, since the logic would now be the same between startup and network change.
- This should be possible if we can control what addresses we listen to, so that we don’t start listening for an address that has not yet been “verified” by AutoNAT and co.
- Interface exposed by the behaviour
pub fn push<I>(&mut self, peers: I) where I: IntoIterator<Item = PeerId>
- To force push our info to a set of peers
- We can call this at the end of our NAT traversal procedure
- Swarm events that interact with the
Identify
behaviour are:
FromSwarm::ConnectionEstablished
- Remove remote peer from map of connected peers
FromSwarm::ConnectionClosed
- Remove the connection from the storage
FromSwarm::DialFailure
- Events that are sent to the swarm are:
ToSwarm::NotifyHandler
- When information is forcedly pushed to a specified remote peer ID, the handler for that connection is called
- When our listen or external addresses change
ToSwarm::NewExternalAddrCandidate
- When we observe a new external address as a response from another peer
ToSwarm::GenerateEvent(Event::Received)
- When new info about a remote peer is received
ToSwarm::NewExternalAddrOfPeer
ToSwarm::GenerateEvent(Event::Sent)
- When we reply a info request back to a remote
ToSwarm::GenerateEvent(Event::Pushed)
- When we push our info to another remote
- In general, we can relatively easily control Identify behaviour if we don’t push any addresses to it, meaning if we don’t start listening for addresses before we’ve run the NAT traversal procedure
Kademlia
- Can run in client mode or server mode
- By default, the node starts in client mode and switches to server as soon as a
FromSwarm::ExternalAddrConfirmed
is received by the behaviour
- Interface exposed by the behaviour
pub fn add_address(&mut self, peer: &PeerId, address: Multiaddr) -> RoutingUpdate
- Adds the address of a remote peer to the DHT
pub fn remove_address(&mut self, peer: &PeerId, address: &MultiAddr) -> Option<kbucket::EntryView<kbucket::Key<PeerId>, Addresses>>
- Removes the address of a remote peer from the DHT
pub fn remove_peer(&mut self, peer: &PeerId) -> Option<kbucket::EntryView<kbucket::Key<PeerId>, Addresses>>
- Same as above, but removes all addresses for the given peer
pub fn bootstrap(&mut self) -> Result<QueryId, NoKnownPeers>
- Kick off the boostrapping procedure
- As per the docs, this is also invoked periodically and every time a new peer is inserted into the routing table
pub fn set_mode(&mut self, mode: Option<Mode>)
- Can override the default mode selection with a specific value
- Swarm events that interact with the
Kademlia
behaviour are:
FromSwarm::ConnectionEstablished
FromSwarm::ConnectionClosed
- Remove the peer from the map
FromSwarm::DialFailure
FromSwarm::AddressChange
FromSwarm::NewListenAddr
- Trigger the bootstrapping procedure if no peer is connected (hence if the node is starting now)
- Events that are sent to the swarm are:
ToSwarm::GenerateEvent(Event::RoutingUpdated)d
- Upon routing table changes
ToSwarm::Dial
- When a new peer is added but the bucket is full, so the new entry is put in a pending state
- When the address of a remote peer changes
ToSwarm::NotifyHandler
- All connection handlers with the info about the new mode when it changes
- Whenever a new record is received
ToSwarm::NewExternalAddrOfPeer
- When an entry in the DHT is confirmed for a peer
- It seems fairly simple to control what addresses are advertised when. We could also manually change from client to server mode and back depending on the state we are in
Gossipsub
- Interface exposed by the behaviour