Prechádzať zdrojové kódy

net: and anchorlist and minimal utilities. also clarify hosts specific TODOs.

lunar-mining 2 rokov pred
rodič
commit
3725de07ec
1 zmenil súbory, kde vykonal 88 pridanie a 6 odobranie
  1. 88 6
      src/net/hosts/store.rs

+ 88 - 6
src/net/hosts/store.rs

@@ -44,6 +44,19 @@ const WHITELIST_MAX_LEN: usize = 5000;
 const GREYLIST_MAX_LEN: usize = 2000;
 const GREYLIST_MAX_LEN: usize = 2000;
 
 
 /// Manages a store of network addresses
 /// Manages a store of network addresses
+// TODO: 1. Hostlists will be stored on disk and loaded on start.
+//
+//       2. Potentially we should store the entire peer list as a single file,
+//       classified by grey/ white/ anchor (more in line with the monero impl).
+//
+//       3. Currently, we remove items from the greylist when they are promoted to whitelist.
+//       However, this is redundant: when we learn of the host from a seed node it will be re-added
+//       to the greylist again, resulting in duplicates across the grey and whitelist. The same 
+//       issue applies to the anchor list. Check how monero deals with this.
+//       
+//       4. Test the performance overhead of using vectors for white/grey/anchor lists. 
+//
+//       5. Check whether anchorlist has a max size in Monero.
 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)>>,
@@ -51,6 +64,9 @@ pub struct Hosts {
     // Recently seen nodes.
     // Recently seen nodes.
     pub whitelist: RwLock<Vec<(Url, u64)>>,
     pub whitelist: RwLock<Vec<(Url, u64)>>,
 
 
+    // Nodes to which we have already been able to establish a connection.
+    pub anchorlist: RwLock<Vec<(Url, u64)>>,
+
     /// Peers we reject from connecting
     /// Peers we reject from connecting
     rejected: RwLock<HashSet<String>>,
     rejected: RwLock<HashSet<String>>,
 
 
@@ -67,6 +83,7 @@ impl Hosts {
         Arc::new(Self {
         Arc::new(Self {
             whitelist: RwLock::new(Vec::new()),
             whitelist: RwLock::new(Vec::new()),
             greylist: RwLock::new(Vec::new()),
             greylist: RwLock::new(Vec::new()),
+            anchorlist: RwLock::new(Vec::new()),
             rejected: RwLock::new(HashSet::new()),
             rejected: RwLock::new(HashSet::new()),
             store_subscriber: Subscriber::new(),
             store_subscriber: Subscriber::new(),
             settings,
             settings,
@@ -161,7 +178,6 @@ impl Hosts {
 
 
     // Store the address in the whitelist if we don't have it.
     // Store the address in the whitelist if we don't have it.
     // Otherwise, update the last_seen field.
     // Otherwise, update the last_seen field.
-    // TODO: test the performance of this method. It might be costly.
     pub async fn whitelist_store_or_update(&self, addrs: &[(Url, u64)]) -> Result<()> {
     pub async fn whitelist_store_or_update(&self, addrs: &[(Url, u64)]) -> Result<()> {
         debug!(target: "net::hosts::whitelist_store_or_update()", "[START]");
         debug!(target: "net::hosts::whitelist_store_or_update()", "[START]");
 
 
@@ -186,7 +202,7 @@ impl Hosts {
         debug!(target: "net::hosts::store::greylist_store_or_update()", "[START]");
         debug!(target: "net::hosts::store::greylist_store_or_update()", "[START]");
 
 
         // We filter addresses before writing to the greylist.
         // We filter addresses before writing to the greylist.
-        // We don't need to do this for the whitelist the whitelist is created from the greylist.
+        // We don't need to do this for the whitelist (whitelist is created from greylist)
         let filtered_addrs = self.filter_addresses(addrs).await;
         let filtered_addrs = self.filter_addresses(addrs).await;
         let filtered_addrs_len = filtered_addrs.len();
         let filtered_addrs_len = filtered_addrs.len();
         for (addr, last_seen) in filtered_addrs {
         for (addr, last_seen) in filtered_addrs {
@@ -206,6 +222,26 @@ impl Hosts {
         Ok(())
         Ok(())
     }
     }
 
 
+    pub async fn anchorlist_store_or_update(&self, addrs: &[(Url, u64)]) -> Result<()> {
+        debug!(target: "net::hosts::store::anchor_store_or_update()", "[START]");
+
+        for (addr, last_seen) in addrs {
+            if !self.anchorlist_contains(addr).await {
+                debug!(target: "net::hosts::whitelist_store_or_update()",
+        "We do not have this entry in the whitelist. Adding to store...");
+
+                self.anchorlist_store(addr.clone(), last_seen.clone()).await;
+            } else {
+                debug!(target: "net::hosts::whitelist_store_or_update()",
+        "We have this entry in the whitelist. Updating last seen...");
+
+                let index = self.get_anchorlist_index_at_addr(addr).await?;
+                self.anchorlist_update_last_seen(addr, last_seen.clone(), index).await;
+            }
+        }
+        Ok(())
+    }
+
     // Append host to the greylist. Called on learning of a new peer.
     // Append host to the greylist. Called on learning of a new peer.
     pub async fn greylist_store(&self, addr: Url, last_seen: u64) {
     pub async fn greylist_store(&self, addr: Url, last_seen: u64) {
         debug!(target: "net::hosts::greylist_store()", "hosts::greylist_store() [START]");
         debug!(target: "net::hosts::greylist_store()", "hosts::greylist_store() [START]");
@@ -227,7 +263,6 @@ impl Hosts {
     }
     }
 
 
     // Append host to the whitelist. Called after a successful interaction with an online peer.
     // Append host to the whitelist. Called after a successful interaction with an online peer.
-    // TODO: FIXME: address filtering
     pub async fn whitelist_store(&self, addr: Url, last_seen: u64) {
     pub async fn whitelist_store(&self, addr: Url, last_seen: u64) {
         debug!(target: "net::hosts::whitelist_store()", "[START]");
         debug!(target: "net::hosts::whitelist_store()", "[START]");
 
 
@@ -247,6 +282,21 @@ impl Hosts {
         debug!(target: "net::hosts::store::whitelist_store()", "[END]");
         debug!(target: "net::hosts::store::whitelist_store()", "[END]");
     }
     }
 
 
+    // Append host to the anchorlist. Called after we have established a successful connection to a
+    // peer.
+    pub async fn anchorlist_store(&self, addr: Url, last_seen: u64) {
+        debug!(target: "net::hosts::anchorlist_store()", "[START]");
+
+        let mut anchorlist = self.anchorlist.write().await;
+
+        debug!(target: "net::hosts::anchorlist_store()", "Inserting {}", addr);
+        anchorlist.push((addr, last_seen));
+
+        // Sort the list by last_seen.
+        anchorlist.sort_by_key(|entry| entry.1);
+        debug!(target: "net::hosts::anchorlist_store()", "[END]");
+    }
+
     // Update the last_seen field of a peer on the whitelist.
     // Update the last_seen field of a peer on the whitelist.
     pub async fn whitelist_update_last_seen(&self, addr: &Url, last_seen: u64, index: usize) {
     pub async fn whitelist_update_last_seen(&self, addr: &Url, last_seen: u64, index: usize) {
         debug!(target: "net::hosts::store::whitelist_update_last_seen()", "[START]");
         debug!(target: "net::hosts::store::whitelist_update_last_seen()", "[START]");
@@ -275,6 +325,20 @@ impl Hosts {
         debug!(target: "net::hosts::store::greylist_update_last_seen()", "[END]");
         debug!(target: "net::hosts::store::greylist_update_last_seen()", "[END]");
     }
     }
 
 
+    // Update the last_seen field of a peer on the anchorlist.
+    pub async fn anchorlist_update_last_seen(&self, addr: &Url, last_seen: u64, index: usize) {
+        debug!(target: "net::hosts::store::anchorlist_update_last_seen()", "[START]");
+
+        let mut anchorlist = self.anchorlist.write().await;
+
+        anchorlist[index] = (addr.clone(), last_seen);
+
+        // Sort the list by last_seen.
+        anchorlist.sort_by_key(|entry| entry.1);
+
+        debug!(target: "net::hosts::store::anchorlist_update_last_seen()", "[END]");
+    }
+
     pub async fn whitelist_downgrade(&self, addr: &Url) {
     pub async fn whitelist_downgrade(&self, addr: &Url) {
         // First lookup the entry using its addr.
         // First lookup the entry using its addr.
         let mut entry = vec![];
         let mut entry = vec![];
@@ -286,9 +350,6 @@ impl Hosts {
             }
             }
         }
         }
 
 
-        // TODO: This is for testing purposes.
-        assert!(entry.len() == 1);
-
         // Remove this item from the whitelist.
         // Remove this item from the whitelist.
         let mut whitelist = self.whitelist.write().await;
         let mut whitelist = self.whitelist.write().await;
         // TODO: test!
         // TODO: test!
@@ -493,6 +554,15 @@ impl Hosts {
         return false
         return false
     }
     }
 
 
+    /// Check if host is in the anchorlist
+    pub async fn anchorlist_contains(&self, addr: &Url) -> bool {
+        let anchorlist = self.anchorlist.read().await;
+        if anchorlist.iter().any(|(u, _t)| u == addr) {
+            return true
+        }
+        return false
+    }
+
     /// 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;
@@ -514,6 +584,18 @@ impl Hosts {
         }
         }
         return Err(Error::InvalidIndex)
         return Err(Error::InvalidIndex)
     }
     }
+
+    /// 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::InvalidIndex)
+    }
+
     /// Return all known whitelisted hosts
     /// Return all known whitelisted hosts
     pub async fn whitelist_fetch_all(&self) -> Vec<(Url, u64)> {
     pub async fn whitelist_fetch_all(&self) -> Vec<(Url, u64)> {
         self.whitelist.read().await.iter().cloned().collect()
         self.whitelist.read().await.iter().cloned().collect()