Browse Source

net: set metering threshold config and message max bytes size config for the basic protocols messages

    - set a maxmium limit on values of max field of GetAddrMessage to u8::MAX, this means the maximum size of addrs Vec in AddrsMessage will be u8::MAX * 2.
       this will help us to set MAX_BYTES for AddrsMessage
oars 1 year ago
parent
commit
525f5ef44e
3 changed files with 107 additions and 11 deletions
  1. 77 7
      src/net/message.rs
  2. 25 2
      src/net/protocol/protocol_address.rs
  3. 5 2
      src/net/protocol/protocol_seed.rs

+ 77 - 7
src/net/message.rs

@@ -23,7 +23,7 @@ use darkfi_serial::{
 };
 use url::{Host, Url};
 
-use crate::net::metering::{MeteringConfiguration, DEFAULT_METERING_CONFIGURATION};
+use crate::{net::metering::MeteringConfiguration, util::time::NanoTimestamp};
 
 /// Generic message template.
 pub trait Message: 'static + Send + Sync + AsyncDecodable + AsyncEncodable {
@@ -66,19 +66,31 @@ macro_rules! impl_p2p_message {
 /// Maximum command (message name) length in bytes
 pub const MAX_COMMAND_LENGTH: u8 = 255;
 
+/// For each message configs a threshold was calculated by taking the maximum number of messages
+/// in a 10 seconds window and multiply it by 2 not to be strict.
+pub const PING_PONG_METERING_CONFIGURATION: MeteringConfiguration = MeteringConfiguration {
+    threshold: 4,
+    sleep_step: 1000,
+    expiry_time: NanoTimestamp::from_secs(10),
+};
+
+/// Ping-Pong messages fields size
+/// * nonce = 2
+pub const PING_PONG_MAX_BYTES: u64 = 2;
+
 /// Outbound keepalive message.
 #[derive(Debug, Copy, Clone, SerialEncodable, SerialDecodable)]
 pub struct PingMessage {
     pub nonce: u16,
 }
-impl_p2p_message!(PingMessage, "ping", 0, 0, DEFAULT_METERING_CONFIGURATION);
+impl_p2p_message!(PingMessage, "ping", PING_PONG_MAX_BYTES, 1, PING_PONG_METERING_CONFIGURATION);
 
 /// Inbound keepalive message.
 #[derive(Debug, Copy, Clone, SerialEncodable, SerialDecodable)]
 pub struct PongMessage {
     pub nonce: u16,
 }
-impl_p2p_message!(PongMessage, "pong", 0, 0, DEFAULT_METERING_CONFIGURATION);
+impl_p2p_message!(PongMessage, "pong", PING_PONG_MAX_BYTES, 1, PING_PONG_METERING_CONFIGURATION);
 
 /// Requests address of outbound connection.
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
@@ -91,15 +103,45 @@ pub struct GetAddrsMessage {
     /// Preferred addresses transports
     pub transports: Vec<String>,
 }
-impl_p2p_message!(GetAddrsMessage, "getaddr", 0, 0, DEFAULT_METERING_CONFIGURATION);
+pub const GET_ADDRS_METERING_CONFIGURATION: MeteringConfiguration = MeteringConfiguration {
+    threshold: 6,
+    sleep_step: 1000,
+    expiry_time: NanoTimestamp::from_secs(10),
+};
+
+/// GetAddrs message fields size
+/// * max = 4
+/// * transports = 1 (vec_len) + 4 + 4 + 4 + 4 + 4 + 8 + 8 + 8 + 8 = 53
+///
+/// Transports is list of all transports to be shared specified in protocol_address
+pub const GET_ADDRS_MAX_BYTES: u64 = 57;
+
+impl_p2p_message!(
+    GetAddrsMessage,
+    "getaddr",
+    GET_ADDRS_MAX_BYTES,
+    1,
+    GET_ADDRS_METERING_CONFIGURATION
+);
 
 /// Sends address information to inbound connection.
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
 pub struct AddrsMessage {
     pub addrs: Vec<(Url, u64)>,
 }
+pub const ADDRS_METERING_CONFIGURATION: MeteringConfiguration = MeteringConfiguration {
+    threshold: 6,
+    sleep_step: 1000,
+    expiry_time: NanoTimestamp::from_secs(10),
+};
+
+/// Addrs message fields size
+/// * addrs = 1 (vec_len) + (u8::MAX * 2) * 128
+///
+/// Url type is estimated to be max 128 bytes here and for other message below
+pub const ADDRS_MAX_BYTES: u64 = 65281;
 
-impl_p2p_message!(AddrsMessage, "addr", 0, 0, DEFAULT_METERING_CONFIGURATION);
+impl_p2p_message!(AddrsMessage, "addr", ADDRS_MAX_BYTES, 1, ADDRS_METERING_CONFIGURATION);
 
 /// Requests version information of outbound connection.
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
@@ -123,7 +165,23 @@ pub struct VersionMessage {
     /// to be enabled for this connection
     pub features: Vec<(String, u32)>,
 }
-impl_p2p_message!(VersionMessage, "version", 0, 0, DEFAULT_METERING_CONFIGURATION);
+pub const VERSION_METERING_CONFIGURATION: MeteringConfiguration = MeteringConfiguration {
+    threshold: 4,
+    sleep_step: 1000,
+    expiry_time: NanoTimestamp::from_secs(10),
+};
+
+/// Version message fields size
+/// * node_id = 8  (this will be empty most of the time)
+/// * version = 128 (look at VerackMessage for the reasoning)
+/// * timestamp = 8
+/// * connect_recv_addr = 128
+/// * resolve_recv_addr = 1 (enum_len) + 128(url) = 129
+/// * ext_send_addr = 1 (vec_len)  + 128 * 10 = 1281 (10 is a reasonable cap for number of external addresses)
+/// * features = 1 (vec_len) + (32 (service_name) + 4 (service_version)) * 10 = 361 (10 features is an estimate)
+pub const VERSION_MAX_BYTES: u64 = 2043;
+
+impl_p2p_message!(VersionMessage, "version", VERSION_MAX_BYTES, 1, VERSION_METERING_CONFIGURATION);
 
 impl VersionMessage {
     pub(in crate::net) fn get_ipv6_addr(&self) -> Option<Ipv6Addr> {
@@ -143,4 +201,16 @@ pub struct VerackMessage {
     /// App version
     pub app_version: semver::Version,
 }
-impl_p2p_message!(VerackMessage, "verack", 0, 0, DEFAULT_METERING_CONFIGURATION);
+pub const VERACK_METERING_CONFIGURATION: MeteringConfiguration = MeteringConfiguration {
+    threshold: 4,
+    sleep_step: 1000,
+    expiry_time: NanoTimestamp::from_secs(10),
+};
+
+/// Verack message fields size
+/// * app_version = 24 (major = 8, minor = 8, patch = 8) + 52 (prerelease =  1(str_len) + 51(str)) + 52 (build = 1(str_len) + 51(str))
+///
+/// Prerelease and build strings are variable length but shouldn't be larger than 102 bytes
+pub const VERACK_MAX_BYTES: u64 = 128;
+
+impl_p2p_message!(VerackMessage, "verack", VERACK_MAX_BYTES, 1, VERACK_METERING_CONFIGURATION);

+ 25 - 2
src/net/protocol/protocol_address.rs

@@ -291,8 +291,11 @@ impl ProtocolBase for ProtocolAddress {
         self.jobsman.spawn(self.clone().handle_receive_get_addrs(), ex).await;
 
         // Send get_address message.
-        let get_addrs =
-            GetAddrsMessage { max: outbound_connections as u32, transports: allowed_transports };
+        // We ask for a maximum of u8::MAX addresses from a single node
+        let get_addrs = GetAddrsMessage {
+            max: outbound_connections.min(u8::MAX as usize) as u32,
+            transports: allowed_transports,
+        };
         self.channel.send(&get_addrs).await?;
 
         debug!(
@@ -306,3 +309,23 @@ impl ProtocolBase for ProtocolAddress {
         PROTO_NAME
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use darkfi_serial::serialize;
+
+    use crate::net::message::GET_ADDRS_MAX_BYTES;
+
+    use super::{GetAddrsMessage, TRANSPORT_COMBOS};
+
+    // Helps to check if the MAX_BYTES for GetAddrs message is valid as new transports are added
+    #[test]
+    fn test_get_addrs_msg_size() {
+        let message = GetAddrsMessage {
+            max: u8::MAX as u32,
+            transports: TRANSPORT_COMBOS.iter().map(|x| x.to_string()).collect(),
+        };
+
+        assert_eq!(serialize(&message).len() as u64, GET_ADDRS_MAX_BYTES);
+    }
+}

+ 5 - 2
src/net/protocol/protocol_seed.rs

@@ -114,8 +114,11 @@ impl ProtocolBase for ProtocolSeed {
         drop(settings);
 
         // Send get address message
-        let get_addr =
-            GetAddrsMessage { max: outbound_connections as u32, transports: allowed_transports };
+        // We ask for a maximum of u8::MAX addresses from a single node
+        let get_addr = GetAddrsMessage {
+            max: outbound_connections.min(u8::MAX as usize) as u32,
+            transports: allowed_transports,
+        };
         self.channel.send(&get_addr).await?;
 
         // Receive addresses