Просмотр исходного кода

outbound_session: remove peer from anchor or whitelist when try_connect fails

lunar-mining 2 лет назад
Родитель
Сommit
5f00598c12
2 измененных файлов с 76 добавлено и 12 удалено
  1. 66 12
      src/net/hosts/store.rs
  2. 10 0
      src/net/session/outbound_session.rs

+ 66 - 12
src/net/hosts/store.rs

@@ -55,6 +55,7 @@ const GREYLIST_MAX_LEN: usize = 2000;
 /// Manages a store of network addresses
 /// Manages a store of network addresses
 // TODO: Test the performance overhead of using vectors for white/grey/anchor lists.
 // TODO: Test the performance overhead of using vectors for white/grey/anchor lists.
 // TODO: Check whether anchorlist has a max size in Monero.
 // TODO: Check whether anchorlist has a max size in Monero.
+// TODO: we can probably clean up a lot of the repetitive code in this module.
 pub struct Hosts {
 pub struct Hosts {
     // Intermediary node list that is periodically probed and updated to whitelist.
     // Intermediary node list that is periodically probed and updated to whitelist.
     pub greylist: RwLock<Vec<(Url, u64)>>,
     pub greylist: RwLock<Vec<(Url, u64)>>,
@@ -399,7 +400,7 @@ impl Hosts {
                 debug!(target: "net::hosts::anchorlist_store_or_update()",
                 debug!(target: "net::hosts::anchorlist_store_or_update()",
         "We have this entry in the anchorlist. Updating last seen...");
         "We have this entry in the anchorlist. Updating last seen...");
 
 
-                let index = self.get_anchorlist_index_at_addr(addr).await?;
+                let (index, entry) = self.get_anchorlist_entry_at_addr(addr).await?;
                 self.anchorlist_update_last_seen(addr, last_seen.clone(), index).await;
                 self.anchorlist_update_last_seen(addr, last_seen.clone(), index).await;
             }
             }
         }
         }
@@ -446,6 +447,29 @@ impl Hosts {
         debug!(target: "net::hosts::store::whitelist_store()", "[END]");
         debug!(target: "net::hosts::store::whitelist_store()", "[END]");
     }
     }
 
 
+    pub async fn downgrade_host(&self, addr: &Url) -> Result<()> {
+        if self.anchorlist_contains(addr).await {
+            debug!(target: "net::store::downgrade_host()", 
+                   "Removing non responsive peer from anchorlist");
+            let (index, entry) = self.get_anchorlist_entry_at_addr(addr).await?;
+            self.anchorlist_remove(addr, index).await;
+            self.greylist_store_or_update(&[entry]).await?;
+            Ok(())
+        } else if self.whitelist_contains(addr).await {
+            debug!(target: "net::store::downgrade_host()", 
+                   "Removing non responsive peer from whitelist");
+            let (index, entry) = self.get_whitelist_entry_at_addr(addr).await?;
+            self.whitelist_remove(addr, index).await;
+            self.greylist_store_or_update(&[entry]).await?;
+            Ok(())
+        } else {
+            debug!(target: "net::store::downgrade_host()", 
+                   "Greylist entry detected! Do nothing for now...");
+            // TODO
+            Ok(())
+        }
+    }
+
     // Append host to the anchorlist. Called after we have established a successful connection to a
     // Append host to the anchorlist. Called after we have established a successful connection to a
     // peer.
     // peer.
     pub async fn anchorlist_store(&self, addr: Url, last_seen: u64) {
     pub async fn anchorlist_store(&self, addr: Url, last_seen: u64) {
@@ -523,6 +547,16 @@ impl Hosts {
         anchorlist.sort_by_key(|entry| entry.1);
         anchorlist.sort_by_key(|entry| entry.1);
     }
     }
 
 
+    pub async fn whitelist_remove(&self, addr: &Url, position: usize) {
+        debug!(target: "net::refinery::run()", "Removing disconnected peer {} from whitelist", addr);
+        let mut whitelist = self.whitelist.write().await;
+
+        whitelist.remove(position);
+
+        // Sort the list by last_seen.
+        whitelist.sort_by_key(|entry| entry.1);
+    }
+
     pub async fn subscribe_store(&self) -> Result<Subscription<usize>> {
     pub async fn subscribe_store(&self) -> Result<Subscription<usize>> {
         let sub = self.store_subscriber.clone().subscribe().await;
         let sub = self.store_subscriber.clone().subscribe().await;
         Ok(sub)
         Ok(sub)
@@ -743,6 +777,17 @@ impl Hosts {
         return false
         return false
     }
     }
 
 
+    /// Get the index for a given addr on the anchorlist.
+    pub async fn get_anchorlist_index_at_addr(&self, addr: &Url) -> Result<usize> {
+        let anchorlist = self.anchorlist.read().await;
+        for (i, (url, time)) in anchorlist.iter().enumerate() {
+            if url == addr {
+                return Ok(i)
+            }
+        }
+        return Err(Error::HostDoesNotExist)
+    }
+
     /// Get the index for a given addr on the whitelist.
     /// Get the index for a given addr on the whitelist.
     pub async fn get_whitelist_index_at_addr(&self, addr: &Url) -> Result<usize> {
     pub async fn get_whitelist_index_at_addr(&self, addr: &Url) -> Result<usize> {
         let whitelist = self.whitelist.read().await;
         let whitelist = self.whitelist.read().await;
@@ -765,12 +810,22 @@ impl Hosts {
         return Err(Error::HostDoesNotExist)
         return Err(Error::HostDoesNotExist)
     }
     }
 
 
-    /// Get the index for a given addr on the anchorlist.
-    pub async fn get_anchorlist_index_at_addr(&self, addr: &Url) -> Result<usize> {
+    /// Get the index and entry for a given addr on the whitelist.
+    pub async fn get_whitelist_entry_at_addr(&self, addr: &Url) -> Result<(usize, (Url, u64))> {
+        let whitelist = self.whitelist.read().await;
+        for (i, (url, time)) in whitelist.iter().enumerate() {
+            if url == addr {
+                return Ok((i, (url.clone(), time.clone())))
+            }
+        }
+        return Err(Error::HostDoesNotExist)
+    }
+    /// Get the index and entry for a given addr on the anchorlist.
+    pub async fn get_anchorlist_entry_at_addr(&self, addr: &Url) -> Result<(usize, (Url, u64))> {
         let anchorlist = self.anchorlist.read().await;
         let anchorlist = self.anchorlist.read().await;
-        for (i, (url, _time)) in anchorlist.iter().enumerate() {
+        for (i, (url, time)) in anchorlist.iter().enumerate() {
             if url == addr {
             if url == addr {
-                return Ok(i)
+                return Ok((i, (url.clone(), time.clone())))
             }
             }
         }
         }
         return Err(Error::HostDoesNotExist)
         return Err(Error::HostDoesNotExist)
@@ -878,9 +933,7 @@ impl Hosts {
         debug!(target: "store::whitelist_fetch_with_schemes", "[START]");
         debug!(target: "store::whitelist_fetch_with_schemes", "[START]");
         let mut ret = vec![];
         let mut ret = vec![];
 
 
-        // Anchorlist is empty!
         if !self.is_empty_whitelist().await {
         if !self.is_empty_whitelist().await {
-            // Select from the whitelist providing it's not empty.
             let whitelist = self.whitelist.read().await;
             let whitelist = self.whitelist.read().await;
 
 
             let mut limit = match limit {
             let mut limit = match limit {
@@ -894,10 +947,11 @@ impl Hosts {
                     limit -= 1;
                     limit -= 1;
                     if limit == 0 {
                     if limit == 0 {
                         debug!(target: "store::whitelist_fetch_with_schemes",
                         debug!(target: "store::whitelist_fetch_with_schemes",
-                           "Found matching scheme, returning");
+                           "Found matching white scheme, returning");
                         return ret
                         return ret
                     }
                     }
                 } else {
                 } else {
+                    // TODO: select from greylist?
                     debug!(target: "store::whitelist_fetch_with_schemes",
                     debug!(target: "store::whitelist_fetch_with_schemes",
                           "No matching schemes");
                           "No matching schemes");
                 }
                 }
@@ -919,7 +973,7 @@ impl Hosts {
                         limit -= 1;
                         limit -= 1;
                         if limit == 0 {
                         if limit == 0 {
                             debug!(target: "store::whitelist_fetch_with_schemes",
                             debug!(target: "store::whitelist_fetch_with_schemes",
-                           "Found matching scheme, returning");
+                           "Found matching greylist scheme, returning");
                             return ret
                             return ret
                         }
                         }
                     } else {
                     } else {
@@ -992,7 +1046,7 @@ impl Hosts {
                     limit -= 1;
                     limit -= 1;
                     if limit == 0 {
                     if limit == 0 {
                         debug!(target: "store::anchorlist_fetch_with_schemes",
                         debug!(target: "store::anchorlist_fetch_with_schemes",
-                           "Found matching scheme, returning");
+                           "Found matching anchor scheme, returning {:?}", ret);
                         return ret
                         return ret
                     }
                     }
                 } else {
                 } else {
@@ -1021,7 +1075,7 @@ impl Hosts {
                         limit -= 1;
                         limit -= 1;
                         if limit == 0 {
                         if limit == 0 {
                             debug!(target: "store::anchorlist_fetch_with_schemes",
                             debug!(target: "store::anchorlist_fetch_with_schemes",
-                           "Found matching scheme, returning");
+                           "Found matching white scheme, returning {:?}", ret);
                             return ret
                             return ret
                         }
                         }
                     } else {
                     } else {
@@ -1046,7 +1100,7 @@ impl Hosts {
                             limit -= 1;
                             limit -= 1;
                             if limit == 0 {
                             if limit == 0 {
                                 debug!(target: "store::anchorlist_fetch_with_schemes",
                                 debug!(target: "store::anchorlist_fetch_with_schemes",
-                           "Found matching scheme, returning");
+                           "Found matching grey scheme, returning {:?}", ret);
                                 return ret
                                 return ret
                             }
                             }
                         } else {
                         } else {

+ 10 - 0
src/net/session/outbound_session.rs

@@ -201,6 +201,8 @@ impl Slot {
         //  If the whitelist is empty, select from the greylist
         //  If the whitelist is empty, select from the greylist
         //  If the greylist is empty, do peer discovery
         //  If the greylist is empty, do peer discovery
         if connect_count < self.p2p().settings().anchor_connection_count {
         if connect_count < self.p2p().settings().anchor_connection_count {
+            debug!(target: "outbound_session::fetch_address()",
+            "First two connections- prefer anchor connections");
             return hosts.anchorlist_fetch_address_with_lock(self.p2p(), transports).await
             return hosts.anchorlist_fetch_address_with_lock(self.p2p(), transports).await
         }
         }
         // Up to white_connection_percent connections:
         // Up to white_connection_percent connections:
@@ -209,6 +211,8 @@ impl Slot {
         //  If the whitelist is empty, select from the greylist
         //  If the whitelist is empty, select from the greylist
         //  If the greylist is empty, do peer discovery
         //  If the greylist is empty, do peer discovery
         if connect_count < white_count {
         if connect_count < white_count {
+            debug!(target: "outbound_session::fetch_address()",
+            "Next N connections- prefer white connections");
             return hosts.whitelist_fetch_address_with_lock(self.p2p(), transports).await
             return hosts.whitelist_fetch_address_with_lock(self.p2p(), transports).await
         }
         }
         // All other connections:
         // All other connections:
@@ -216,6 +220,8 @@ impl Slot {
         //  Select from the greylist
         //  Select from the greylist
         //  If the greylist is empty, do peer discovery
         //  If the greylist is empty, do peer discovery
         if connect_count < slot_count {
         if connect_count < slot_count {
+            debug!(target: "outbound_session::fetch_address()",
+            "All other connections- get grey connections");
             return hosts.greylist_fetch_address_with_lock(self.p2p(), transports).await
             return hosts.greylist_fetch_address_with_lock(self.p2p(), transports).await
         } else {
         } else {
             return None
             return None
@@ -369,6 +375,10 @@ impl Slot {
                     self.slot, addr, e
                     self.slot, addr, e
                 );
                 );
 
 
+                // At this point we've failed to connect.
+                // If the host is in the anchorlist or whitelist, downgrade it to greylist.
+                self.p2p().hosts().downgrade_host(&addr).await?;
+
                 // Remove connection from pending
                 // Remove connection from pending
                 self.p2p().remove_pending(&addr).await;
                 self.p2p().remove_pending(&addr).await;