Commit Diff


commit - c4076f54c9e66afb73081fd33b4176ba4407a8a5
commit + 4cff87560ba238ba6eebd16b1465c0ebae2f6ac2
blob - f4c5b2c0a88778c8c2f8ce7ab7cebe831cc5cb4b
blob + 574aca329b91f08b7b7a6c58f4b7d42bfb190799
--- src/handlers.rs
+++ src/handlers.rs
@@ -849,8 +849,7 @@ impl Node {
                             .closest
                             .iter()
                             .find(|p| {
-                                q.queried.contains(&p.id)
-                                    && p.id != sender_id
+                                q.queried.contains(&p.id) && p.id != sender_id
                             })
                             .cloned();
 
@@ -866,9 +865,7 @@ impl Node {
                                 is_unique: false,
                             };
                             if let Err(e) = self.send_store(&peer, &store_msg) {
-                                log::debug!(
-                                    "Republish-on-access failed: {e}"
-                                );
+                                log::debug!("Republish-on-access failed: {e}");
                             } else {
                                 log::debug!(
                                     "Republished value to {:?} (nearest without)",
blob - f956f9821695e00eff5516b1ab427b2fb9fa3b29
blob + 1c663d67f6ae60a6f30c58e43e29a63f2ef4f798
--- src/lib.rs
+++ src/lib.rs
@@ -124,5 +124,5 @@ pub use id::NodeId;
 pub use nat::NatState;
 
 // Re-export sha2 for downstream crates.
-pub use sha2;
 pub use node::Node;
+pub use sha2;
blob - a9b618d1fe724850b91c421c559f138e0d8c3cf8
blob + dad9bb5c17ac4ada87843841407c567e31aaa5cd
--- src/routing.rs
+++ src/routing.rs
@@ -140,10 +140,8 @@ impl KBucket {
     /// Add a contact to the replacement cache.
     fn add_to_cache(&mut self, peer: PeerInfo) {
         // Update if already in cache
-        if let Some(pos) = self
-            .replacements
-            .iter()
-            .position(|r| r.id == peer.id)
+        if let Some(pos) =
+            self.replacements.iter().position(|r| r.id == peer.id)
         {
             self.replacements.remove(pos);
             self.replacements.push(peer);
@@ -368,7 +366,9 @@ impl RoutingTable {
     /// Record a communication failure for a peer.
     /// If the peer becomes stale (exceeds threshold),
     /// tries to replace it with a cached contact.
-    /// Returns the evicted NodeId if replacement happened.
+    /// If no replacement is available, removes the stale
+    /// peer outright to avoid phantom entries.
+    /// Returns the evicted NodeId if removal happened.
     pub fn record_failure(&mut self, id: &NodeId) -> Option<NodeId> {
         // Never mark pinned nodes as stale
         if self.pinned.contains(id) {
@@ -377,7 +377,14 @@ impl RoutingTable {
         let idx = self.bucket_index(id)?;
         let became_stale = self.buckets[idx].record_failure(id);
         if became_stale {
-            self.buckets[idx].try_replace_stale(id)
+            // Try replacement cache first; if empty, just
+            // remove the dead peer so it doesn't linger.
+            let evicted = self.buckets[idx].try_replace_stale(id);
+            if evicted.is_none() {
+                self.remove(id);
+                return Some(*id);
+            }
+            evicted
         } else {
             None
         }