diff --git a/cli/src/commands/start.rs b/cli/src/commands/start.rs index 1b3599593b..7c42980cc2 100644 --- a/cli/src/commands/start.rs +++ b/cli/src/commands/start.rs @@ -154,6 +154,9 @@ pub struct Start { /// If development mode is enabled, specify the custom bonded balances as a JSON object (default: None) #[clap(long)] pub dev_bonded_balances: Option, + /// Specify the path to an alternative genesis block + #[clap(long)] + pub genesis: Option, } impl Start { @@ -474,7 +477,11 @@ impl Start { eprintln!("The '--dev-num-validators' flag is ignored because '--dev' is not set"); } - Block::from_bytes_le(N::genesis_bytes()) + if let Some(path) = self.genesis.as_ref() { + Block::read_le(std::fs::File::open(path)?) + } else { + Block::from_bytes_le(N::genesis_bytes()) + } } } diff --git a/node/bft/src/gateway.rs b/node/bft/src/gateway.rs index 60af4c788f..631ea2b78f 100644 --- a/node/bft/src/gateway.rs +++ b/node/bft/src/gateway.rs @@ -274,12 +274,16 @@ impl Gateway { /// Returns `true` if the given IP is this node. pub fn is_local_ip(&self, ip: SocketAddr) -> bool { ip == self.local_ip() - || (ip.ip().is_unspecified() || ip.ip().is_loopback()) && ip.port() == self.local_ip().port() + || (ip.ip().is_unspecified() || ip.ip().is_loopback() && ip.ip() == self.local_ip().ip()) + && ip.port() == self.local_ip().port() } /// Returns `true` if the given IP is not this node, is not a bogon address, and is not unspecified. pub fn is_valid_peer_ip(&self, ip: SocketAddr) -> bool { - !self.is_local_ip(ip) && !is_bogon_ip(ip.ip()) && !is_unspecified_or_broadcast_ip(ip.ip()) + !self.is_local_ip(ip) + // Ignore bogon case for unique loopback ip connections (127.0.0.1 -> 127.0.0.2) + && (!is_bogon_ip(ip.ip()) || self.local_ip().ip().is_loopback() && ip.ip().is_loopback()) + && !is_unspecified_or_broadcast_ip(ip.ip()) } /// Returns the resolver. @@ -448,7 +452,7 @@ impl Gateway { bail!("{CONTEXT} Dropping connection request from '{peer_ip}' (already connected)") } // Ensure the peer is not spamming connection attempts. - if !peer_ip.ip().is_loopback() { + if !self.tcp.is_self_connect(peer_ip) { // Add this connection attempt and retrieve the number of attempts. let num_attempts = self.cache.insert_inbound_connection(peer_ip.ip(), RESTRICTED_INTERVAL); // Ensure the connecting peer has not surpassed the connection attempt limit. diff --git a/node/router/src/handshake.rs b/node/router/src/handshake.rs index 015162beac..47c3ce97eb 100644 --- a/node/router/src/handshake.rs +++ b/node/router/src/handshake.rs @@ -301,7 +301,7 @@ impl Router { bail!("Dropping connection request from '{peer_ip}' (restricted)") } // Ensure the peer is not spamming connection attempts. - if !peer_ip.ip().is_loopback() { + if !self.tcp.is_self_connect(peer_ip) { // Add this connection attempt and retrieve the number of attempts. let num_attempts = self.cache.insert_inbound_connection(peer_ip.ip(), Self::RADIO_SILENCE_IN_SECS as i64); // Ensure the connecting peer has not surpassed the connection attempt limit. diff --git a/node/router/src/lib.rs b/node/router/src/lib.rs index 376b68e73f..cdc218476d 100644 --- a/node/router/src/lib.rs +++ b/node/router/src/lib.rs @@ -222,12 +222,16 @@ impl Router { /// Returns `true` if the given IP is this node. pub fn is_local_ip(&self, ip: &SocketAddr) -> bool { *ip == self.local_ip() - || (ip.ip().is_unspecified() || ip.ip().is_loopback()) && ip.port() == self.local_ip().port() + || (ip.ip().is_unspecified() || ip.ip().is_loopback() && ip.ip() == self.local_ip().ip()) + && ip.port() == self.local_ip().port() } /// Returns `true` if the given IP is not this node, is not a bogon address, and is not unspecified. pub fn is_valid_peer_ip(&self, ip: &SocketAddr) -> bool { - !self.is_local_ip(ip) && !is_bogon_ip(ip.ip()) && !is_unspecified_or_broadcast_ip(ip.ip()) + !self.is_local_ip(ip) + // Ignore bogon case for unique loopback ip connections (127.0.0.1 -> 127.0.0.2) + && (!is_bogon_ip(ip.ip()) || self.local_ip().ip().is_loopback() && ip.ip().is_loopback()) + && !is_unspecified_or_broadcast_ip(ip.ip()) } /// Returns the node type. @@ -392,7 +396,10 @@ impl Router { /// Returns the list of bootstrap peers. #[allow(clippy::if_same_then_else)] pub fn bootstrap_peers(&self) -> Vec { - if cfg!(feature = "test") || self.is_dev { + // If the BOOTSTRAP_PEERS environment variable is set, use it. + if let Ok(bootstraps) = std::env::var("BOOTSTRAP_PEERS") { + bootstraps.split(',').filter_map(|peer| SocketAddr::from_str(peer).ok()).collect() + } else if cfg!(feature = "test") || self.is_dev { // Development testing contains no bootstrap peers. vec![] } else if N::ID == snarkvm::console::network::MainnetV0::ID { diff --git a/node/tcp/src/tcp.rs b/node/tcp/src/tcp.rs index 47f3a2f822..c9e524d2fa 100644 --- a/node/tcp/src/tcp.rs +++ b/node/tcp/src/tcp.rs @@ -393,16 +393,19 @@ impl Tcp { } /// Checks if the given IP address is the same as the listening address of this `Tcp`. - fn is_self_connect(&self, addr: SocketAddr) -> bool { + pub fn is_self_connect(&self, addr: SocketAddr) -> bool { // SAFETY: if we're opening connections, this should never fail. let listening_addr = self.listening_addr().unwrap(); + let is_same_ip = listening_addr.ip() == addr.ip(); match listening_addr.ip().is_loopback() { // If localhost, check the ports, this only works on outbound connections, since we // don't know the ephemeral port a peer might be using if they initiate the connection. - true => listening_addr.port() == addr.port(), + // + // The is_same_ip check is significant as 127.0.0.1 != 127.0.0.2 + true => is_same_ip && listening_addr.port() == addr.port(), // If it's not localhost, matching IPs indicate a self-connect in both directions. - false => listening_addr.ip() == addr.ip(), + false => is_same_ip, } }