Skip to content

Commit 371d4dc

Browse files
committed
fix: protect useful peers in low buckets
That way, we never disconnect from the core of the network. We don't protect our closest peers as: * We'll reconnect to them frequently when we query for ourself. * We use the core nodes most frequently.
1 parent 6a14d9c commit 371d4dc

File tree

2 files changed

+29
-9
lines changed

2 files changed

+29
-9
lines changed

dht.go

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,17 @@ const (
5858
kad2 protocol.ID = "/kad/2.0.0"
5959
)
6060

61+
const (
62+
dhtUsefulTag = "dht-useful"
63+
kbucketTag = "kbucket"
64+
)
65+
6166
// IpfsDHT is an implementation of Kademlia with S/Kademlia modifications.
6267
// It is used to implement the base Routing module.
6368
type IpfsDHT struct {
64-
host host.Host // the network services we need
65-
self peer.ID // Local peer (yourself)
69+
host host.Host // the network services we need
70+
self peer.ID // Local peer (yourself)
71+
selfKey kb.ID
6672
peerstore peerstore.Peerstore // Peer Registry
6773

6874
datastore ds.Datastore // Local data
@@ -250,6 +256,7 @@ func makeDHT(ctx context.Context, h host.Host, cfg config) (*IpfsDHT, error) {
250256
dht := &IpfsDHT{
251257
datastore: cfg.datastore,
252258
self: h.ID(),
259+
selfKey: kb.ConvertPeerID(h.ID()),
253260
peerstore: h.Peerstore(),
254261
host: h,
255262
strmap: make(map[peer.ID]*messageSender),
@@ -336,17 +343,16 @@ func makeRtRefreshManager(dht *IpfsDHT, cfg config, maxLastSuccessfulOutboundThr
336343
}
337344

338345
func makeRoutingTable(dht *IpfsDHT, cfg config, maxLastSuccessfulOutboundThreshold time.Duration) (*kb.RoutingTable, error) {
339-
self := kb.ConvertPeerID(dht.host.ID())
340-
341-
rt, err := kb.NewRoutingTable(cfg.bucketSize, self, time.Minute, dht.host.Peerstore(), maxLastSuccessfulOutboundThreshold)
346+
rt, err := kb.NewRoutingTable(cfg.bucketSize, dht.selfKey, time.Minute, dht.host.Peerstore(), maxLastSuccessfulOutboundThreshold)
342347
cmgr := dht.host.ConnManager()
343348

344349
rt.PeerAdded = func(p peer.ID) {
345-
commonPrefixLen := kb.CommonPrefixLen(self, kb.ConvertPeerID(p))
346-
cmgr.TagPeer(p, "kbucket", BaseConnMgrScore+commonPrefixLen)
350+
commonPrefixLen := kb.CommonPrefixLen(dht.selfKey, kb.ConvertPeerID(p))
351+
cmgr.TagPeer(p, kbucketTag, BaseConnMgrScore+commonPrefixLen)
347352
}
348353
rt.PeerRemoved = func(p peer.ID) {
349-
cmgr.UntagPeer(p, "kbucket")
354+
cmgr.Unprotect(p, dhtUsefulTag)
355+
cmgr.UntagPeer(p, kbucketTag)
350356

351357
// try to fix the RT
352358
dht.fixRTIfNeeded()

query.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,21 @@ func (dht *IpfsDHT) runQuery(ctx context.Context, target string, queryFn queryFn
174174
}
175175

176176
func (q *query) recordPeerIsValuable(p peer.ID) {
177-
q.dht.routingTable.UpdateLastUsefulAt(p, time.Now())
177+
if !q.dht.routingTable.UpdateLastUsefulAt(p, time.Now()) {
178+
// not in routing table
179+
return
180+
}
181+
182+
// Protect useful peers, when they're actually useful. This will last
183+
// through disconnects. However, we'll still evict them if they keep
184+
// disconnecting from us.
185+
//
186+
// Restrict to buckets 0, 1 (75% of requests, max 40 peers), so we don't
187+
// protect _too_ many peers.
188+
commonPrefixLen := kb.CommonPrefixLen(q.dht.selfKey, kb.ConvertPeerID(p))
189+
if commonPrefixLen < 2 {
190+
q.dht.host.ConnManager().Protect(p, dhtUsefulTag)
191+
}
178192
}
179193

180194
func (q *query) recordValuablePeers() {

0 commit comments

Comments
 (0)