Skip to content

Commit f539ed1

Browse files
karalabefjl
authored andcommitted
p2p/discover: force refresh if the table is empty
1 parent 5076170 commit f539ed1

File tree

1 file changed

+41
-13
lines changed

1 file changed

+41
-13
lines changed

p2p/discover/table.go

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,12 @@ func (tab *Table) Lookup(targetID NodeID) []*Node {
191191
result := tab.closest(target, bucketSize)
192192
tab.mutex.Unlock()
193193

194+
// If the result set is empty, all nodes were dropped, refresh
195+
if len(result.entries) == 0 {
196+
tab.refresh()
197+
return nil
198+
}
199+
194200
for {
195201
// ask the alpha closest nodes that we haven't asked yet
196202
for i := 0; i < len(result.entries) && pendingQueries < alpha; i++ {
@@ -207,7 +213,7 @@ func (tab *Table) Lookup(targetID NodeID) []*Node {
207213
tab.db.updateFindFails(n.ID, fails)
208214
glog.V(logger.Detail).Infof("Bumping failures for %x: %d", n.ID[:8], fails)
209215

210-
if fails > maxFindnodeFailures {
216+
if fails >= maxFindnodeFailures {
211217
glog.V(logger.Detail).Infof("Evacuating node %x: %d findnode failures", n.ID[:8], fails)
212218
tab.del(n)
213219
}
@@ -232,19 +238,41 @@ func (tab *Table) Lookup(targetID NodeID) []*Node {
232238
return result.entries
233239
}
234240

235-
// refresh performs a lookup for a random target to keep buckets full.
241+
// refresh performs a lookup for a random target to keep buckets full, or seeds
242+
// the table if it is empty (initial bootstrap or discarded faulty peers).
236243
func (tab *Table) refresh() {
237-
// The Kademlia paper specifies that the bucket refresh should
238-
// perform a refresh in the least recently used bucket. We cannot
239-
// adhere to this because the findnode target is a 512bit value
240-
// (not hash-sized) and it is not easily possible to generate a
241-
// sha3 preimage that falls into a chosen bucket.
242-
//
243-
// We perform a lookup with a random target instead.
244-
var target NodeID
245-
rand.Read(target[:])
246-
result := tab.Lookup(target)
247-
if len(result) == 0 {
244+
seed := true
245+
246+
// If the discovery table is empty, seed with previously known nodes
247+
tab.mutex.Lock()
248+
for _, bucket := range tab.buckets {
249+
if len(bucket.entries) > 0 {
250+
seed = false
251+
break
252+
}
253+
}
254+
tab.mutex.Unlock()
255+
256+
// If the table is not empty, try to refresh using the live entries
257+
if !seed {
258+
// The Kademlia paper specifies that the bucket refresh should
259+
// perform a refresh in the least recently used bucket. We cannot
260+
// adhere to this because the findnode target is a 512bit value
261+
// (not hash-sized) and it is not easily possible to generate a
262+
// sha3 preimage that falls into a chosen bucket.
263+
//
264+
// We perform a lookup with a random target instead.
265+
var target NodeID
266+
rand.Read(target[:])
267+
268+
result := tab.Lookup(target)
269+
if len(result) == 0 {
270+
// Lookup failed, seed after all
271+
seed = true
272+
}
273+
}
274+
275+
if seed {
248276
// Pick a batch of previously know seeds to lookup with
249277
seeds := tab.db.querySeeds(10)
250278
for _, seed := range seeds {

0 commit comments

Comments
 (0)