diff --git a/base_layer/p2p/src/initialization.rs b/base_layer/p2p/src/initialization.rs index 75465d69d6..843f629d2d 100644 --- a/base_layer/p2p/src/initialization.rs +++ b/base_layer/p2p/src/initialization.rs @@ -559,7 +559,7 @@ impl ServiceInitializer for P2pInitializer { .with_node_info(NodeNetworkInfo { major_version: MAJOR_NETWORK_VERSION, minor_version: MINOR_NETWORK_VERSION, - network_byte: self.network.as_byte(), + network_wire_byte: self.network.as_wire_byte(), user_agent: self.user_agent.clone(), }) .with_minimize_connections(if self.config.dht.minimize_connections { @@ -602,3 +602,14 @@ impl ServiceInitializer for P2pInitializer { Ok(()) } } + +#[cfg(test)] +mod test { + use tari_common::configuration::Network; + use tari_comms::connection_manager::WireMode; + #[test] + fn self_liveness_network_wire_byte_is_consistent() { + let wire_mode = WireMode::Liveness; + assert_eq!(wire_mode.as_byte(), Network::RESERVED_WIRE_BYTE); + } +} diff --git a/common/src/configuration/network.rs b/common/src/configuration/network.rs index bf265fa9b1..28dcd5e01f 100644 --- a/common/src/configuration/network.rs +++ b/common/src/configuration/network.rs @@ -49,6 +49,9 @@ pub enum Network { } impl Network { + /// The reserved wire byte for liveness ('LIVENESS_WIRE_MODE') + pub const RESERVED_WIRE_BYTE: u8 = 0xa7; + pub fn get_current_or_user_setting_or_default() -> Self { match CURRENT_NETWORK.get() { Some(&network) => network, @@ -86,6 +89,30 @@ impl Network { LocalNet => "localnet", } } + + /// This function returns the network wire byte for any chosen network. Increase these numbers for any given network + /// when network traffic separation is required. + /// Note: Do not re-use previous values. + pub fn as_wire_byte(self) -> u8 { + let wire_byte = match self { + // Choose a value in 'MAIN_NET_RANGE' or assign 'self.as_byte()' + Network::MainNet => self.as_byte(), + // Choose a value in 'STAGE_NET_RANGE' or assign 'self.as_byte()' + Network::StageNet => self.as_byte(), + // Choose a value in 'NEXT_NET_RANGE' or assign 'self.as_byte()' + Network::NextNet => self.as_byte(), + // Choose a value in 'LOCAL_NET_RANGE' or assign 'self.as_byte()' + Network::LocalNet => self.as_byte(), + // Choose a value in 'IGOR_RANGE' or assign 'self.as_byte()' + Network::Igor => self.as_byte(), + // Choose a value in 'ESMERALDA_RANGE' or assign 'self.as_byte()' + Network::Esmeralda => self.as_byte(), + }; + // The reserved wire byte for liveness ('LIVENESS_WIRE_MODE') is defined in another module, which is not + // accessible from here. + debug_assert!(wire_byte != Network::RESERVED_WIRE_BYTE); + wire_byte + } } /// The default network for all applications @@ -236,4 +263,151 @@ mod test { assert_eq!(Network::try_from(0x24).unwrap(), Network::Igor); assert_eq!(Network::try_from(0x26).unwrap(), Network::Esmeralda); } + + // Do not change these ranges + const MAIN_NET_RANGE: std::ops::Range = 0..40; + const STAGE_NET_RANGE: std::ops::Range = 40..80; + const NEXT_NET_RANGE: std::ops::Range = 80..120; + const LOCAL_NET_RANGE: std::ops::Range = 120..160; + const IGOR_RANGE: std::ops::Range = 160..200; + const ESMERALDA_RANGE: std::ops::Range = 200..240; + const LEGACY_RANGE: [u8; 6] = [0x00, 0x01, 0x02, 0x10, 0x24, 0x26]; + + /// Helper function to verify the network wire byte range + pub fn verify_network_wire_byte_range(network_wire_byte: u8, network: Network) -> Result<(), String> { + if network_wire_byte == Network::RESERVED_WIRE_BYTE { + return Err(format!( + "Invalid network wire byte, cannot be '{}', reserved for 'LIVENESS_WIRE_MODE'", + Network::RESERVED_WIRE_BYTE + )); + } + + // Legacy compatibility + if network_wire_byte == network.as_byte() { + return Ok(()); + } + if LEGACY_RANGE.contains(&network_wire_byte) { + return Err(format!( + "Invalid network wire byte `{}` for network `{}`", + network_wire_byte, network + )); + } + + // Verify binned values + let valid = match network { + Network::MainNet => MAIN_NET_RANGE.contains(&network_wire_byte), + Network::StageNet => STAGE_NET_RANGE.contains(&network_wire_byte), + Network::NextNet => NEXT_NET_RANGE.contains(&network_wire_byte), + Network::LocalNet => LOCAL_NET_RANGE.contains(&network_wire_byte), + Network::Igor => IGOR_RANGE.contains(&network_wire_byte), + Network::Esmeralda => ESMERALDA_RANGE.contains(&network_wire_byte), + }; + if !valid { + return Err(format!( + "Invalid network wire byte `{}` for network `{}`", + network_wire_byte, network + )); + } + Ok(()) + } + + #[test] + fn test_as_wire_byte() { + for network in [ + Network::MainNet, + Network::StageNet, + Network::NextNet, + Network::LocalNet, + Network::Igor, + Network::Esmeralda, + ] { + assert!(verify_network_wire_byte_range(Network::RESERVED_WIRE_BYTE, network).is_err()); + + let wire_byte = Network::as_wire_byte(network); + assert!(verify_network_wire_byte_range(wire_byte, network).is_ok()); + + for val in 0..255 { + match network { + Network::MainNet => { + if val == Network::RESERVED_WIRE_BYTE { + assert!(verify_network_wire_byte_range(val, network).is_err()); + } else if val == Network::MainNet.as_byte() { + assert!(verify_network_wire_byte_range(val, network).is_ok()); + } else if LEGACY_RANGE.contains(&val) { + assert!(verify_network_wire_byte_range(val, network).is_err()); + } else if MAIN_NET_RANGE.contains(&val) { + assert!(verify_network_wire_byte_range(val, network).is_ok()); + } else { + assert!(verify_network_wire_byte_range(val, network).is_err()); + } + }, + Network::StageNet => { + if val == Network::RESERVED_WIRE_BYTE { + assert!(verify_network_wire_byte_range(val, network).is_err()); + } else if val == Network::StageNet.as_byte() { + assert!(verify_network_wire_byte_range(val, network).is_ok()); + } else if LEGACY_RANGE.contains(&val) { + assert!(verify_network_wire_byte_range(val, network).is_err()); + } else if STAGE_NET_RANGE.contains(&val) { + assert!(verify_network_wire_byte_range(val, network).is_ok()); + } else { + assert!(verify_network_wire_byte_range(val, network).is_err()); + } + }, + Network::NextNet => { + if val == Network::RESERVED_WIRE_BYTE { + assert!(verify_network_wire_byte_range(val, network).is_err()); + } else if val == Network::NextNet.as_byte() { + assert!(verify_network_wire_byte_range(val, network).is_ok()); + } else if LEGACY_RANGE.contains(&val) { + assert!(verify_network_wire_byte_range(val, network).is_err()); + } else if NEXT_NET_RANGE.contains(&val) { + assert!(verify_network_wire_byte_range(val, network).is_ok()); + } else { + assert!(verify_network_wire_byte_range(val, network).is_err()); + } + }, + Network::LocalNet => { + if val == Network::RESERVED_WIRE_BYTE { + assert!(verify_network_wire_byte_range(val, network).is_err()); + } else if val == Network::LocalNet.as_byte() { + assert!(verify_network_wire_byte_range(val, network).is_ok()); + } else if LEGACY_RANGE.contains(&val) { + assert!(verify_network_wire_byte_range(val, network).is_err()); + } else if LOCAL_NET_RANGE.contains(&val) { + assert!(verify_network_wire_byte_range(val, network).is_ok()); + } else { + assert!(verify_network_wire_byte_range(val, network).is_err()); + } + }, + Network::Igor => { + if val == Network::RESERVED_WIRE_BYTE { + assert!(verify_network_wire_byte_range(val, network).is_err()); + } else if val == Network::Igor.as_byte() { + assert!(verify_network_wire_byte_range(val, network).is_ok()); + } else if LEGACY_RANGE.contains(&val) { + assert!(verify_network_wire_byte_range(val, network).is_err()); + } else if IGOR_RANGE.contains(&val) { + assert!(verify_network_wire_byte_range(val, network).is_ok()); + } else { + assert!(verify_network_wire_byte_range(val, network).is_err()); + } + }, + Network::Esmeralda => { + if val == Network::RESERVED_WIRE_BYTE { + assert!(verify_network_wire_byte_range(val, network).is_err()); + } else if val == Network::Esmeralda.as_byte() { + assert!(verify_network_wire_byte_range(val, network).is_ok()); + } else if LEGACY_RANGE.contains(&val) { + assert!(verify_network_wire_byte_range(val, network).is_err()); + } else if ESMERALDA_RANGE.contains(&val) { + assert!(verify_network_wire_byte_range(val, network).is_ok()); + } else { + assert!(verify_network_wire_byte_range(val, network).is_err()); + } + }, + } + } + } + } } diff --git a/comms/core/src/builder/mod.rs b/comms/core/src/builder/mod.rs index 43b78874b0..5cae88e774 100644 --- a/comms/core/src/builder/mod.rs +++ b/comms/core/src/builder/mod.rs @@ -174,7 +174,7 @@ impl CommsBuilder { /// Set a network byte as per [RFC-173 Versioning](https://rfc.tari.com/RFC-0173_Versioning.html) pub fn with_network_byte(mut self, network_byte: u8) -> Self { - self.connection_manager_config.network_info.network_byte = network_byte; + self.connection_manager_config.network_info.network_wire_byte = network_byte; self } diff --git a/comms/core/src/connection_manager/dialer.rs b/comms/core/src/connection_manager/dialer.rs index 0451d8b5b4..bd7315b024 100644 --- a/comms/core/src/connection_manager/dialer.rs +++ b/comms/core/src/connection_manager/dialer.rs @@ -515,7 +515,7 @@ where tokio::select! { _ = delay => { debug!(target: LOG_TARGET, "[Attempt {}] Connecting to peer '{}'", current_state.num_attempts(), current_state.peer().node_id.short_str()); - match Self::dial_peer(current_state, &noise_config, ¤t_transport, config.network_info.network_byte).await { + match Self::dial_peer(current_state, &noise_config, ¤t_transport, config.network_info.network_wire_byte).await { (state, Ok((socket, addr))) => { debug!(target: LOG_TARGET, "Dial succeeded for peer '{}' after {} attempt(s)", state.peer().node_id.short_str(), state.num_attempts()); break (state, Ok((socket, addr))); diff --git a/comms/core/src/connection_manager/listener.rs b/comms/core/src/connection_manager/listener.rs index f5f6b9c684..16e1cd7e7a 100644 --- a/comms/core/src/connection_manager/listener.rs +++ b/comms/core/src/connection_manager/listener.rs @@ -244,7 +244,7 @@ where #[cfg(feature = "metrics")] metrics::pending_connections(None, ConnectionDirection::Inbound).inc(); match Self::read_wire_format(&mut socket, config.time_to_first_byte).await { - Ok(WireMode::Comms(byte)) if byte == config.network_info.network_byte => { + Ok(WireMode::Comms(byte)) if byte == config.network_info.network_wire_byte => { let this_node_id_str = node_identity.node_id().short_str(); let result = Self::perform_socket_upgrade_procedure( &node_identity, @@ -290,7 +290,7 @@ where target: LOG_TARGET, "Peer at address '{}' sent invalid wire format byte. Expected {:x?} got: {:x?} ", peer_addr, - config.network_info.network_byte, + config.network_info.network_wire_byte, byte, ); let _result = socket.shutdown().await; @@ -320,7 +320,7 @@ where "Peer at address '{}' failed to send its wire format. Expected network byte {:x?} or liveness \ byte {:x?} not received. Error: {}", peer_addr, - config.network_info.network_byte, + config.network_info.network_wire_byte, LIVENESS_WIRE_MODE, err ); diff --git a/comms/core/src/connection_manager/mod.rs b/comms/core/src/connection_manager/mod.rs index 3ca92fe339..beb68a4995 100644 --- a/comms/core/src/connection_manager/mod.rs +++ b/comms/core/src/connection_manager/mod.rs @@ -56,6 +56,7 @@ pub(crate) use self_liveness::SelfLivenessCheck; pub use self_liveness::SelfLivenessStatus; mod wire_mode; +pub use wire_mode::WireMode; #[cfg(test)] mod tests; diff --git a/comms/core/src/protocol/network_info.rs b/comms/core/src/protocol/network_info.rs index 90968f8e65..ddcb0551cb 100644 --- a/comms/core/src/protocol/network_info.rs +++ b/comms/core/src/protocol/network_info.rs @@ -30,9 +30,9 @@ pub struct NodeNetworkInfo { /// NOT reject the connection if a remote peer advertises a different minor version number. pub minor_version: u8, /// The byte that MUST be sent (outbound connections) or MUST be received (inbound connections) for a connection to - /// be established. This byte cannot be 0x46 (E) because that is reserved for liveness. + /// be established. This byte cannot be `LIVENESS_WIRE_MODE` (E) because that is reserved for liveness. /// Default: 0x00 - pub network_byte: u8, + pub network_wire_byte: u8, /// The user agent string for this node pub user_agent: String, } diff --git a/comms/dht/examples/propagation/node.rs b/comms/dht/examples/propagation/node.rs index 3e06162a8d..54a492c69e 100644 --- a/comms/dht/examples/propagation/node.rs +++ b/comms/dht/examples/propagation/node.rs @@ -83,7 +83,7 @@ pub async fn create>( .with_node_info(NodeNetworkInfo { major_version: 0, minor_version: 0, - network_byte: 0x25, + network_wire_byte: 0x25, user_agent: "/tari/propagator/0.0.1".to_string(), }) .with_node_identity(node_identity.clone())