From d414f9cf1523c4f4d34e6acdca84a8d20d8aa111 Mon Sep 17 00:00:00 2001 From: Richard Watts Date: Tue, 3 Dec 2024 15:17:47 +0000 Subject: [PATCH] (feat) Rebootstrap if you end up with no nodes and no active connections, unles you are the bootstrap, in which case wait for someone to contact you. --- z2/src/setup.rs | 14 ++++++++------ zilliqa/src/p2p_node.rs | 27 ++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/z2/src/setup.rs b/z2/src/setup.rs index cd4a1b2b8..28547fb74 100644 --- a/z2/src/setup.rs +++ b/z2/src/setup.rs @@ -544,12 +544,14 @@ impl Setup { bootstrap_address: bootstrap_address.clone(), nodes: Vec::new(), p2p_port: self.get_p2p_port(node_index_u16), - // No external address is needed right now, because tcp connections can be - // called back, so can act as an autonat server. Effectively, this means the - // bootstrap_address specifies the external address. If this is ever not the - // case, we will need an external_address to be specified here. - // - rrw 2024-12-02 - external_address: None, + // libp2p's autonat will attempt to infer an external address by having + // the called peer call back. The caller attempts to facilitate this by + // careful choice of outgoing port. + // Sometimes this isn't possible, external address discovery fails, and in + // z2's case, the network cannot form. Specify the external address so that + // we never need to ask (autonat will still fail, but kademlia will be happy + // and the network will operate) + external_address: Some(self.get_p2p_multiaddr(node_index_u16)), }; // @todo should pass this in! let port = self.get_json_rpc_port(*node_index as u16, false); diff --git a/zilliqa/src/p2p_node.rs b/zilliqa/src/p2p_node.rs index 3e3d5e127..c37bac0d4 100644 --- a/zilliqa/src/p2p_node.rs +++ b/zilliqa/src/p2p_node.rs @@ -26,6 +26,7 @@ use tokio::{ signal::{self, unix::SignalKind}, sync::mpsc::{self, error::SendError, UnboundedSender}, task::JoinSet, + time::{self, Instant}, }; use tokio_stream::wrappers::UnboundedReceiverStream; use tracing::*; @@ -239,6 +240,9 @@ impl P2pNode { } } + let sleep = time::sleep(Duration::from_millis(5)); + tokio::pin!(sleep); + let mut terminate = signal::unix::signal(SignalKind::terminate())?; loop { @@ -294,7 +298,6 @@ impl P2pNode { } } } - SwarmEvent::Behaviour(BehaviourEvent::RequestResponse(request_response::Event::Message { message, peer: _source })) => { match message { request_response::Message::Request { request, channel: _channel, request_id: _request_id, .. } => { @@ -434,6 +437,28 @@ impl P2pNode { break; } } + () = &mut sleep => { + let net_info = self.swarm.network_info(); + trace!("p2p_node tick {0} / {1} ", net_info.num_peers(), net_info.connection_counters().num_connections() ); + if net_info.num_peers() == 0 && net_info.connection_counters().num_connections() == 0 { + // We have no peers and no connections. Try bootstrapping.. + if let Some((peer, address)) = &self.config.bootstrap_address { + if self.swarm.local_peer_id() == peer { + debug!("p2p_node: can't bootstrap against myself"); + } else { + debug!("p2p_node: no peers and no connections - bootstrapping!"); + self.swarm + .behaviour_mut() + .kademlia + .add_address(peer, address.clone()); + self.swarm.behaviour_mut().kademlia.bootstrap()?; + } + } else { + debug!("p2p_node: no peers and no connections, but no bootstrap either! We may be stuck"); + } + } + sleep.as_mut().reset(Instant::now() + Duration::from_millis(10000)); + }, _ = terminate.recv() => { self.shard_threads.shutdown().await; break;