github.com/zhiqiangxu/go-ethereum@v1.9.16-0.20210824055606-be91cfdebc48/p2p/discover/table.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package discover implements the Node Discovery Protocol.
    18  //
    19  // The Node Discovery protocol provides a way to find RLPx nodes that
    20  // can be connected to. It uses a Kademlia-like protocol to maintain a
    21  // distributed database of the IDs and endpoints of all listening
    22  // nodes.
    23  package discover
    24  
    25  import (
    26  	crand "crypto/rand"
    27  	"encoding/binary"
    28  	"fmt"
    29  	mrand "math/rand"
    30  	"net"
    31  	"sort"
    32  	"sync"
    33  	"time"
    34  
    35  	"github.com/zhiqiangxu/go-ethereum/common"
    36  	"github.com/zhiqiangxu/go-ethereum/log"
    37  	"github.com/zhiqiangxu/go-ethereum/p2p/enode"
    38  	"github.com/zhiqiangxu/go-ethereum/p2p/netutil"
    39  )
    40  
    41  const (
    42  	alpha           = 3  // Kademlia concurrency factor
    43  	bucketSize      = 16 // Kademlia bucket size
    44  	maxReplacements = 10 // Size of per-bucket replacement list
    45  
    46  	// We keep buckets for the upper 1/15 of distances because
    47  	// it's very unlikely we'll ever encounter a node that's closer.
    48  	hashBits          = len(common.Hash{}) * 8
    49  	nBuckets          = hashBits / 15       // Number of buckets
    50  	bucketMinDistance = hashBits - nBuckets // Log distance of closest bucket
    51  
    52  	// IP address limits.
    53  	bucketIPLimit, bucketSubnet = 2, 24 // at most 2 addresses from the same /24
    54  	tableIPLimit, tableSubnet   = 10, 24
    55  
    56  	refreshInterval    = 30 * time.Minute
    57  	revalidateInterval = 10 * time.Second
    58  	copyNodesInterval  = 30 * time.Second
    59  	seedMinTableTime   = 5 * time.Minute
    60  	seedCount          = 30
    61  	seedMaxAge         = 5 * 24 * time.Hour
    62  )
    63  
    64  // Table is the 'node table', a Kademlia-like index of neighbor nodes. The table keeps
    65  // itself up-to-date by verifying the liveness of neighbors and requesting their node
    66  // records when announcements of a new record version are received.
    67  type Table struct {
    68  	mutex   sync.Mutex        // protects buckets, bucket content, nursery, rand
    69  	buckets [nBuckets]*bucket // index of known nodes by distance
    70  	nursery []*node           // bootstrap nodes
    71  	rand    *mrand.Rand       // source of randomness, periodically reseeded
    72  	ips     netutil.DistinctNetSet
    73  
    74  	log        log.Logger
    75  	db         *enode.DB // database of known nodes
    76  	net        transport
    77  	refreshReq chan chan struct{}
    78  	initDone   chan struct{}
    79  	closeReq   chan struct{}
    80  	closed     chan struct{}
    81  
    82  	nodeAddedHook func(*node) // for testing
    83  }
    84  
    85  // transport is implemented by the UDP transports.
    86  type transport interface {
    87  	Self() *enode.Node
    88  	RequestENR(*enode.Node) (*enode.Node, error)
    89  	lookupRandom() []*enode.Node
    90  	lookupSelf() []*enode.Node
    91  	ping(*enode.Node) (seq uint64, err error)
    92  }
    93  
    94  // bucket contains nodes, ordered by their last activity. the entry
    95  // that was most recently active is the first element in entries.
    96  type bucket struct {
    97  	entries      []*node // live entries, sorted by time of last contact
    98  	replacements []*node // recently seen nodes to be used if revalidation fails
    99  	ips          netutil.DistinctNetSet
   100  }
   101  
   102  func newTable(t transport, db *enode.DB, bootnodes []*enode.Node, log log.Logger) (*Table, error) {
   103  	tab := &Table{
   104  		net:        t,
   105  		db:         db,
   106  		refreshReq: make(chan chan struct{}),
   107  		initDone:   make(chan struct{}),
   108  		closeReq:   make(chan struct{}),
   109  		closed:     make(chan struct{}),
   110  		rand:       mrand.New(mrand.NewSource(0)),
   111  		ips:        netutil.DistinctNetSet{Subnet: tableSubnet, Limit: tableIPLimit},
   112  		log:        log,
   113  	}
   114  	if err := tab.setFallbackNodes(bootnodes); err != nil {
   115  		return nil, err
   116  	}
   117  	for i := range tab.buckets {
   118  		tab.buckets[i] = &bucket{
   119  			ips: netutil.DistinctNetSet{Subnet: bucketSubnet, Limit: bucketIPLimit},
   120  		}
   121  	}
   122  	tab.seedRand()
   123  	tab.loadSeedNodes()
   124  
   125  	return tab, nil
   126  }
   127  
   128  func (tab *Table) self() *enode.Node {
   129  	return tab.net.Self()
   130  }
   131  
   132  func (tab *Table) seedRand() {
   133  	var b [8]byte
   134  	crand.Read(b[:])
   135  
   136  	tab.mutex.Lock()
   137  	tab.rand.Seed(int64(binary.BigEndian.Uint64(b[:])))
   138  	tab.mutex.Unlock()
   139  }
   140  
   141  // ReadRandomNodes fills the given slice with random nodes from the table. The results
   142  // are guaranteed to be unique for a single invocation, no node will appear twice.
   143  func (tab *Table) ReadRandomNodes(buf []*enode.Node) (n int) {
   144  	if !tab.isInitDone() {
   145  		return 0
   146  	}
   147  	tab.mutex.Lock()
   148  	defer tab.mutex.Unlock()
   149  
   150  	var nodes []*enode.Node
   151  	for _, b := range &tab.buckets {
   152  		for _, n := range b.entries {
   153  			nodes = append(nodes, unwrapNode(n))
   154  		}
   155  	}
   156  	// Shuffle.
   157  	for i := 0; i < len(nodes); i++ {
   158  		j := tab.rand.Intn(len(nodes))
   159  		nodes[i], nodes[j] = nodes[j], nodes[i]
   160  	}
   161  	return copy(buf, nodes)
   162  }
   163  
   164  // getNode returns the node with the given ID or nil if it isn't in the table.
   165  func (tab *Table) getNode(id enode.ID) *enode.Node {
   166  	tab.mutex.Lock()
   167  	defer tab.mutex.Unlock()
   168  
   169  	b := tab.bucket(id)
   170  	for _, e := range b.entries {
   171  		if e.ID() == id {
   172  			return unwrapNode(e)
   173  		}
   174  	}
   175  	return nil
   176  }
   177  
   178  // close terminates the network listener and flushes the node database.
   179  func (tab *Table) close() {
   180  	close(tab.closeReq)
   181  	<-tab.closed
   182  }
   183  
   184  // setFallbackNodes sets the initial points of contact. These nodes
   185  // are used to connect to the network if the table is empty and there
   186  // are no known nodes in the database.
   187  func (tab *Table) setFallbackNodes(nodes []*enode.Node) error {
   188  	for _, n := range nodes {
   189  		if err := n.ValidateComplete(); err != nil {
   190  			return fmt.Errorf("bad bootstrap node %q: %v", n, err)
   191  		}
   192  	}
   193  	tab.nursery = wrapNodes(nodes)
   194  	return nil
   195  }
   196  
   197  // isInitDone returns whether the table's initial seeding procedure has completed.
   198  func (tab *Table) isInitDone() bool {
   199  	select {
   200  	case <-tab.initDone:
   201  		return true
   202  	default:
   203  		return false
   204  	}
   205  }
   206  
   207  func (tab *Table) refresh() <-chan struct{} {
   208  	done := make(chan struct{})
   209  	select {
   210  	case tab.refreshReq <- done:
   211  	case <-tab.closeReq:
   212  		close(done)
   213  	}
   214  	return done
   215  }
   216  
   217  // loop schedules runs of doRefresh, doRevalidate and copyLiveNodes.
   218  func (tab *Table) loop() {
   219  	var (
   220  		revalidate     = time.NewTimer(tab.nextRevalidateTime())
   221  		refresh        = time.NewTicker(refreshInterval)
   222  		copyNodes      = time.NewTicker(copyNodesInterval)
   223  		refreshDone    = make(chan struct{})           // where doRefresh reports completion
   224  		revalidateDone chan struct{}                   // where doRevalidate reports completion
   225  		waiting        = []chan struct{}{tab.initDone} // holds waiting callers while doRefresh runs
   226  	)
   227  	defer refresh.Stop()
   228  	defer revalidate.Stop()
   229  	defer copyNodes.Stop()
   230  
   231  	// Start initial refresh.
   232  	go tab.doRefresh(refreshDone)
   233  
   234  loop:
   235  	for {
   236  		select {
   237  		case <-refresh.C:
   238  			tab.seedRand()
   239  			if refreshDone == nil {
   240  				refreshDone = make(chan struct{})
   241  				go tab.doRefresh(refreshDone)
   242  			}
   243  		case req := <-tab.refreshReq:
   244  			waiting = append(waiting, req)
   245  			if refreshDone == nil {
   246  				refreshDone = make(chan struct{})
   247  				go tab.doRefresh(refreshDone)
   248  			}
   249  		case <-refreshDone:
   250  			for _, ch := range waiting {
   251  				close(ch)
   252  			}
   253  			waiting, refreshDone = nil, nil
   254  		case <-revalidate.C:
   255  			revalidateDone = make(chan struct{})
   256  			go tab.doRevalidate(revalidateDone)
   257  		case <-revalidateDone:
   258  			revalidate.Reset(tab.nextRevalidateTime())
   259  			revalidateDone = nil
   260  		case <-copyNodes.C:
   261  			go tab.copyLiveNodes()
   262  		case <-tab.closeReq:
   263  			break loop
   264  		}
   265  	}
   266  
   267  	if refreshDone != nil {
   268  		<-refreshDone
   269  	}
   270  	for _, ch := range waiting {
   271  		close(ch)
   272  	}
   273  	if revalidateDone != nil {
   274  		<-revalidateDone
   275  	}
   276  	close(tab.closed)
   277  }
   278  
   279  // doRefresh performs a lookup for a random target to keep buckets full. seed nodes are
   280  // inserted if the table is empty (initial bootstrap or discarded faulty peers).
   281  func (tab *Table) doRefresh(done chan struct{}) {
   282  	defer close(done)
   283  
   284  	// Load nodes from the database and insert
   285  	// them. This should yield a few previously seen nodes that are
   286  	// (hopefully) still alive.
   287  	tab.loadSeedNodes()
   288  
   289  	// Run self lookup to discover new neighbor nodes.
   290  	tab.net.lookupSelf()
   291  
   292  	// The Kademlia paper specifies that the bucket refresh should
   293  	// perform a lookup in the least recently used bucket. We cannot
   294  	// adhere to this because the findnode target is a 512bit value
   295  	// (not hash-sized) and it is not easily possible to generate a
   296  	// sha3 preimage that falls into a chosen bucket.
   297  	// We perform a few lookups with a random target instead.
   298  	for i := 0; i < 3; i++ {
   299  		tab.net.lookupRandom()
   300  	}
   301  }
   302  
   303  func (tab *Table) loadSeedNodes() {
   304  	seeds := wrapNodes(tab.db.QuerySeeds(seedCount, seedMaxAge))
   305  	seeds = append(seeds, tab.nursery...)
   306  	for i := range seeds {
   307  		seed := seeds[i]
   308  		age := log.Lazy{Fn: func() interface{} { return time.Since(tab.db.LastPongReceived(seed.ID(), seed.IP())) }}
   309  		tab.log.Trace("Found seed node in database", "id", seed.ID(), "addr", seed.addr(), "age", age)
   310  		tab.addSeenNode(seed)
   311  	}
   312  }
   313  
   314  // doRevalidate checks that the last node in a random bucket is still live and replaces or
   315  // deletes the node if it isn't.
   316  func (tab *Table) doRevalidate(done chan<- struct{}) {
   317  	defer func() { done <- struct{}{} }()
   318  
   319  	last, bi := tab.nodeToRevalidate()
   320  	if last == nil {
   321  		// No non-empty bucket found.
   322  		return
   323  	}
   324  
   325  	// Ping the selected node and wait for a pong.
   326  	remoteSeq, err := tab.net.ping(unwrapNode(last))
   327  
   328  	// Also fetch record if the node replied and returned a higher sequence number.
   329  	if last.Seq() < remoteSeq {
   330  		n, err := tab.net.RequestENR(unwrapNode(last))
   331  		if err != nil {
   332  			tab.log.Debug("ENR request failed", "id", last.ID(), "addr", last.addr(), "err", err)
   333  		} else {
   334  			last = &node{Node: *n, addedAt: last.addedAt, livenessChecks: last.livenessChecks}
   335  		}
   336  	}
   337  
   338  	tab.mutex.Lock()
   339  	defer tab.mutex.Unlock()
   340  	b := tab.buckets[bi]
   341  	if err == nil {
   342  		// The node responded, move it to the front.
   343  		last.livenessChecks++
   344  		tab.log.Debug("Revalidated node", "b", bi, "id", last.ID(), "checks", last.livenessChecks)
   345  		tab.bumpInBucket(b, last)
   346  		return
   347  	}
   348  	// No reply received, pick a replacement or delete the node if there aren't
   349  	// any replacements.
   350  	if r := tab.replace(b, last); r != nil {
   351  		tab.log.Debug("Replaced dead node", "b", bi, "id", last.ID(), "ip", last.IP(), "checks", last.livenessChecks, "r", r.ID(), "rip", r.IP())
   352  	} else {
   353  		tab.log.Debug("Removed dead node", "b", bi, "id", last.ID(), "ip", last.IP(), "checks", last.livenessChecks)
   354  	}
   355  }
   356  
   357  // nodeToRevalidate returns the last node in a random, non-empty bucket.
   358  func (tab *Table) nodeToRevalidate() (n *node, bi int) {
   359  	tab.mutex.Lock()
   360  	defer tab.mutex.Unlock()
   361  
   362  	for _, bi = range tab.rand.Perm(len(tab.buckets)) {
   363  		b := tab.buckets[bi]
   364  		if len(b.entries) > 0 {
   365  			last := b.entries[len(b.entries)-1]
   366  			return last, bi
   367  		}
   368  	}
   369  	return nil, 0
   370  }
   371  
   372  func (tab *Table) nextRevalidateTime() time.Duration {
   373  	tab.mutex.Lock()
   374  	defer tab.mutex.Unlock()
   375  
   376  	return time.Duration(tab.rand.Int63n(int64(revalidateInterval)))
   377  }
   378  
   379  // copyLiveNodes adds nodes from the table to the database if they have been in the table
   380  // longer then minTableTime.
   381  func (tab *Table) copyLiveNodes() {
   382  	tab.mutex.Lock()
   383  	defer tab.mutex.Unlock()
   384  
   385  	now := time.Now()
   386  	for _, b := range &tab.buckets {
   387  		for _, n := range b.entries {
   388  			if n.livenessChecks > 0 && now.Sub(n.addedAt) >= seedMinTableTime {
   389  				tab.db.UpdateNode(unwrapNode(n))
   390  			}
   391  		}
   392  	}
   393  }
   394  
   395  // closest returns the n nodes in the table that are closest to the
   396  // given id. The caller must hold tab.mutex.
   397  func (tab *Table) closest(target enode.ID, nresults int, checklive bool) *nodesByDistance {
   398  	// This is a very wasteful way to find the closest nodes but
   399  	// obviously correct. I believe that tree-based buckets would make
   400  	// this easier to implement efficiently.
   401  	close := &nodesByDistance{target: target}
   402  	for _, b := range &tab.buckets {
   403  		for _, n := range b.entries {
   404  			if checklive && n.livenessChecks == 0 {
   405  				continue
   406  			}
   407  			close.push(n, nresults)
   408  		}
   409  	}
   410  	return close
   411  }
   412  
   413  // len returns the number of nodes in the table.
   414  func (tab *Table) len() (n int) {
   415  	tab.mutex.Lock()
   416  	defer tab.mutex.Unlock()
   417  
   418  	for _, b := range &tab.buckets {
   419  		n += len(b.entries)
   420  	}
   421  	return n
   422  }
   423  
   424  // bucket returns the bucket for the given node ID hash.
   425  func (tab *Table) bucket(id enode.ID) *bucket {
   426  	d := enode.LogDist(tab.self().ID(), id)
   427  	return tab.bucketAtDistance(d)
   428  }
   429  
   430  func (tab *Table) bucketAtDistance(d int) *bucket {
   431  	if d <= bucketMinDistance {
   432  		return tab.buckets[0]
   433  	}
   434  	return tab.buckets[d-bucketMinDistance-1]
   435  }
   436  
   437  // addSeenNode adds a node which may or may not be live to the end of a bucket. If the
   438  // bucket has space available, adding the node succeeds immediately. Otherwise, the node is
   439  // added to the replacements list.
   440  //
   441  // The caller must not hold tab.mutex.
   442  func (tab *Table) addSeenNode(n *node) {
   443  	if n.ID() == tab.self().ID() {
   444  		return
   445  	}
   446  
   447  	tab.mutex.Lock()
   448  	defer tab.mutex.Unlock()
   449  	b := tab.bucket(n.ID())
   450  	if contains(b.entries, n.ID()) {
   451  		// Already in bucket, don't add.
   452  		return
   453  	}
   454  	if len(b.entries) >= bucketSize {
   455  		// Bucket full, maybe add as replacement.
   456  		tab.addReplacement(b, n)
   457  		return
   458  	}
   459  	if !tab.addIP(b, n.IP()) {
   460  		// Can't add: IP limit reached.
   461  		return
   462  	}
   463  	// Add to end of bucket:
   464  	b.entries = append(b.entries, n)
   465  	b.replacements = deleteNode(b.replacements, n)
   466  	n.addedAt = time.Now()
   467  	if tab.nodeAddedHook != nil {
   468  		tab.nodeAddedHook(n)
   469  	}
   470  }
   471  
   472  // addVerifiedNode adds a node whose existence has been verified recently to the front of a
   473  // bucket. If the node is already in the bucket, it is moved to the front. If the bucket
   474  // has no space, the node is added to the replacements list.
   475  //
   476  // There is an additional safety measure: if the table is still initializing the node
   477  // is not added. This prevents an attack where the table could be filled by just sending
   478  // ping repeatedly.
   479  //
   480  // The caller must not hold tab.mutex.
   481  func (tab *Table) addVerifiedNode(n *node) {
   482  	if !tab.isInitDone() {
   483  		return
   484  	}
   485  	if n.ID() == tab.self().ID() {
   486  		return
   487  	}
   488  
   489  	tab.mutex.Lock()
   490  	defer tab.mutex.Unlock()
   491  	b := tab.bucket(n.ID())
   492  	if tab.bumpInBucket(b, n) {
   493  		// Already in bucket, moved to front.
   494  		return
   495  	}
   496  	if len(b.entries) >= bucketSize {
   497  		// Bucket full, maybe add as replacement.
   498  		tab.addReplacement(b, n)
   499  		return
   500  	}
   501  	if !tab.addIP(b, n.IP()) {
   502  		// Can't add: IP limit reached.
   503  		return
   504  	}
   505  	// Add to front of bucket.
   506  	b.entries, _ = pushNode(b.entries, n, bucketSize)
   507  	b.replacements = deleteNode(b.replacements, n)
   508  	n.addedAt = time.Now()
   509  	if tab.nodeAddedHook != nil {
   510  		tab.nodeAddedHook(n)
   511  	}
   512  }
   513  
   514  // delete removes an entry from the node table. It is used to evacuate dead nodes.
   515  func (tab *Table) delete(node *node) {
   516  	tab.mutex.Lock()
   517  	defer tab.mutex.Unlock()
   518  
   519  	tab.deleteInBucket(tab.bucket(node.ID()), node)
   520  }
   521  
   522  func (tab *Table) addIP(b *bucket, ip net.IP) bool {
   523  	if netutil.IsLAN(ip) {
   524  		return true
   525  	}
   526  	if !tab.ips.Add(ip) {
   527  		tab.log.Debug("IP exceeds table limit", "ip", ip)
   528  		return false
   529  	}
   530  	if !b.ips.Add(ip) {
   531  		tab.log.Debug("IP exceeds bucket limit", "ip", ip)
   532  		tab.ips.Remove(ip)
   533  		return false
   534  	}
   535  	return true
   536  }
   537  
   538  func (tab *Table) removeIP(b *bucket, ip net.IP) {
   539  	if netutil.IsLAN(ip) {
   540  		return
   541  	}
   542  	tab.ips.Remove(ip)
   543  	b.ips.Remove(ip)
   544  }
   545  
   546  func (tab *Table) addReplacement(b *bucket, n *node) {
   547  	for _, e := range b.replacements {
   548  		if e.ID() == n.ID() {
   549  			return // already in list
   550  		}
   551  	}
   552  	if !tab.addIP(b, n.IP()) {
   553  		return
   554  	}
   555  	var removed *node
   556  	b.replacements, removed = pushNode(b.replacements, n, maxReplacements)
   557  	if removed != nil {
   558  		tab.removeIP(b, removed.IP())
   559  	}
   560  }
   561  
   562  // replace removes n from the replacement list and replaces 'last' with it if it is the
   563  // last entry in the bucket. If 'last' isn't the last entry, it has either been replaced
   564  // with someone else or became active.
   565  func (tab *Table) replace(b *bucket, last *node) *node {
   566  	if len(b.entries) == 0 || b.entries[len(b.entries)-1].ID() != last.ID() {
   567  		// Entry has moved, don't replace it.
   568  		return nil
   569  	}
   570  	// Still the last entry.
   571  	if len(b.replacements) == 0 {
   572  		tab.deleteInBucket(b, last)
   573  		return nil
   574  	}
   575  	r := b.replacements[tab.rand.Intn(len(b.replacements))]
   576  	b.replacements = deleteNode(b.replacements, r)
   577  	b.entries[len(b.entries)-1] = r
   578  	tab.removeIP(b, last.IP())
   579  	return r
   580  }
   581  
   582  // bumpInBucket moves the given node to the front of the bucket entry list
   583  // if it is contained in that list.
   584  func (tab *Table) bumpInBucket(b *bucket, n *node) bool {
   585  	for i := range b.entries {
   586  		if b.entries[i].ID() == n.ID() {
   587  			if !n.IP().Equal(b.entries[i].IP()) {
   588  				// Endpoint has changed, ensure that the new IP fits into table limits.
   589  				tab.removeIP(b, b.entries[i].IP())
   590  				if !tab.addIP(b, n.IP()) {
   591  					// It doesn't, put the previous one back.
   592  					tab.addIP(b, b.entries[i].IP())
   593  					return false
   594  				}
   595  			}
   596  			// Move it to the front.
   597  			copy(b.entries[1:], b.entries[:i])
   598  			b.entries[0] = n
   599  			return true
   600  		}
   601  	}
   602  	return false
   603  }
   604  
   605  func (tab *Table) deleteInBucket(b *bucket, n *node) {
   606  	b.entries = deleteNode(b.entries, n)
   607  	tab.removeIP(b, n.IP())
   608  }
   609  
   610  func contains(ns []*node, id enode.ID) bool {
   611  	for _, n := range ns {
   612  		if n.ID() == id {
   613  			return true
   614  		}
   615  	}
   616  	return false
   617  }
   618  
   619  // pushNode adds n to the front of list, keeping at most max items.
   620  func pushNode(list []*node, n *node, max int) ([]*node, *node) {
   621  	if len(list) < max {
   622  		list = append(list, nil)
   623  	}
   624  	removed := list[len(list)-1]
   625  	copy(list[1:], list)
   626  	list[0] = n
   627  	return list, removed
   628  }
   629  
   630  // deleteNode removes n from list.
   631  func deleteNode(list []*node, n *node) []*node {
   632  	for i := range list {
   633  		if list[i].ID() == n.ID() {
   634  			return append(list[:i], list[i+1:]...)
   635  		}
   636  	}
   637  	return list
   638  }
   639  
   640  // nodesByDistance is a list of nodes, ordered by distance to target.
   641  type nodesByDistance struct {
   642  	entries []*node
   643  	target  enode.ID
   644  }
   645  
   646  // push adds the given node to the list, keeping the total size below maxElems.
   647  func (h *nodesByDistance) push(n *node, maxElems int) {
   648  	ix := sort.Search(len(h.entries), func(i int) bool {
   649  		return enode.DistCmp(h.target, h.entries[i].ID(), n.ID()) > 0
   650  	})
   651  	if len(h.entries) < maxElems {
   652  		h.entries = append(h.entries, n)
   653  	}
   654  	if ix == len(h.entries) {
   655  		// farther away than all nodes we already have.
   656  		// if there was room for it, the node is now the last element.
   657  	} else {
   658  		// slide existing entries down to make room
   659  		// this will overwrite the entry we just appended.
   660  		copy(h.entries[ix+1:], h.entries[ix:])
   661  		h.entries[ix] = n
   662  	}
   663  }