github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/p2p/discover/table.go (about) 1 // Package discover implements the Node Discovery Protocol. 2 // The Node Discovery protocol provides a way to find RLPx nodes that 3 // can be connected to. It uses a Kademlia-like protocol to maintain a 4 // distributed database of the IDs and endpoints of all listening 5 // nodes. 6 package discover 7 8 import ( 9 crand "crypto/rand" 10 "encoding/binary" 11 "errors" 12 "fmt" 13 mrand "math/rand" 14 "net" 15 "sort" 16 "sync" 17 "time" 18 19 "github.com/quickchainproject/quickchain/common" 20 "github.com/quickchainproject/quickchain/crypto" 21 "github.com/quickchainproject/quickchain/log" 22 "github.com/quickchainproject/quickchain/p2p/netutil" 23 ) 24 25 const ( 26 alpha = 3 // Kademlia concurrency factor 27 bucketSize = 16 // Kademlia bucket size 28 maxReplacements = 10 // Size of per-bucket replacement list 29 30 // We keep buckets for the upper 1/15 of distances because 31 // it's very unlikely we'll ever encounter a node that's closer. 32 hashBits = len(common.Hash{}) * 8 33 nBuckets = hashBits / 15 // Number of buckets 34 bucketMinDistance = hashBits - nBuckets // Log distance of closest bucket 35 36 // IP address limits. 37 bucketIPLimit, bucketSubnet = 2, 24 // at most 2 addresses from the same /24 38 tableIPLimit, tableSubnet = 10, 24 39 40 maxBondingPingPongs = 16 // Limit on the number of concurrent ping/pong interactions 41 maxFindnodeFailures = 5 // Nodes exceeding this limit are dropped 42 43 refreshInterval = 30 * time.Minute 44 revalidateInterval = 10 * time.Second 45 copyNodesInterval = 30 * time.Second 46 seedMinTableTime = 5 * time.Minute 47 seedCount = 30 48 seedMaxAge = 5 * 24 * time.Hour 49 ) 50 51 type Table struct { 52 mutex sync.Mutex // protects buckets, bucket content, nursery, rand 53 buckets [nBuckets]*bucket // index of known nodes by distance 54 nursery []*Node // bootstrap nodes 55 rand *mrand.Rand // source of randomness, periodically reseeded 56 ips netutil.DistinctNetSet 57 58 db *nodeDB // database of known nodes 59 refreshReq chan chan struct{} 60 initDone chan struct{} 61 closeReq chan struct{} 62 closed chan struct{} 63 64 bondmu sync.Mutex 65 bonding map[NodeID]*bondproc 66 bondslots chan struct{} // limits total number of active bonding processes 67 68 nodeAddedHook func(*Node) // for testing 69 70 net transport 71 self *Node // metadata of the local node 72 } 73 74 type bondproc struct { 75 err error 76 n *Node 77 done chan struct{} 78 } 79 80 // transport is implemented by the UDP transport. 81 // it is an interface so we can test without opening lots of UDP 82 // sockets and without generating a private key. 83 type transport interface { 84 ping(NodeID, *net.UDPAddr) error 85 waitping(NodeID) error 86 findnode(toid NodeID, addr *net.UDPAddr, target NodeID) ([]*Node, error) 87 close() 88 } 89 90 // bucket contains nodes, ordered by their last activity. the entry 91 // that was most recently active is the first element in entries. 92 type bucket struct { 93 entries []*Node // live entries, sorted by time of last contact 94 replacements []*Node // recently seen nodes to be used if revalidation fails 95 ips netutil.DistinctNetSet 96 } 97 98 func newTable(t transport, ourID NodeID, ourAddr *net.UDPAddr, nodeDBPath string, bootnodes []*Node) (*Table, error) { 99 // If no node database was given, use an in-memory one 100 db, err := newNodeDB(nodeDBPath, Version, ourID) 101 if err != nil { 102 return nil, err 103 } 104 tab := &Table{ 105 net: t, 106 db: db, 107 self: NewNode(ourID, ourAddr.IP, uint16(ourAddr.Port), uint16(ourAddr.Port)), 108 bonding: make(map[NodeID]*bondproc), 109 bondslots: make(chan struct{}, maxBondingPingPongs), 110 refreshReq: make(chan chan struct{}), 111 initDone: make(chan struct{}), 112 closeReq: make(chan struct{}), 113 closed: make(chan struct{}), 114 rand: mrand.New(mrand.NewSource(0)), 115 ips: netutil.DistinctNetSet{Subnet: tableSubnet, Limit: tableIPLimit}, 116 } 117 if err := tab.setFallbackNodes(bootnodes); err != nil { 118 return nil, err 119 } 120 for i := 0; i < cap(tab.bondslots); i++ { 121 tab.bondslots <- struct{}{} 122 } 123 for i := range tab.buckets { 124 tab.buckets[i] = &bucket{ 125 ips: netutil.DistinctNetSet{Subnet: bucketSubnet, Limit: bucketIPLimit}, 126 } 127 } 128 tab.seedRand() 129 tab.loadSeedNodes(false) 130 // Start the background expiration goroutine after loading seeds so that the search for 131 // seed nodes also considers older nodes that would otherwise be removed by the 132 // expiration. 133 tab.db.ensureExpirer() 134 go tab.loop() 135 return tab, nil 136 } 137 138 func (tab *Table) seedRand() { 139 var b [8]byte 140 crand.Read(b[:]) 141 142 tab.mutex.Lock() 143 tab.rand.Seed(int64(binary.BigEndian.Uint64(b[:]))) 144 tab.mutex.Unlock() 145 } 146 147 // Self returns the local node. 148 // The returned node should not be modified by the caller. 149 func (tab *Table) Self() *Node { 150 return tab.self 151 } 152 153 // ReadRandomNodes fills the given slice with random nodes from the 154 // table. It will not write the same node more than once. The nodes in 155 // the slice are copies and can be modified by the caller. 156 func (tab *Table) ReadRandomNodes(buf []*Node) (n int) { 157 if !tab.isInitDone() { 158 return 0 159 } 160 tab.mutex.Lock() 161 defer tab.mutex.Unlock() 162 163 // Find all non-empty buckets and get a fresh slice of their entries. 164 var buckets [][]*Node 165 for _, b := range tab.buckets { 166 if len(b.entries) > 0 { 167 buckets = append(buckets, b.entries[:]) 168 } 169 } 170 if len(buckets) == 0 { 171 return 0 172 } 173 // Shuffle the buckets. 174 for i := len(buckets) - 1; i > 0; i-- { 175 j := tab.rand.Intn(len(buckets)) 176 buckets[i], buckets[j] = buckets[j], buckets[i] 177 } 178 // Move head of each bucket into buf, removing buckets that become empty. 179 var i, j int 180 for ; i < len(buf); i, j = i+1, (j+1)%len(buckets) { 181 b := buckets[j] 182 buf[i] = &(*b[0]) 183 buckets[j] = b[1:] 184 if len(b) == 1 { 185 buckets = append(buckets[:j], buckets[j+1:]...) 186 } 187 if len(buckets) == 0 { 188 break 189 } 190 } 191 return i + 1 192 } 193 194 // Close terminates the network listener and flushes the node database. 195 func (tab *Table) Close() { 196 select { 197 case <-tab.closed: 198 // already closed. 199 case tab.closeReq <- struct{}{}: 200 <-tab.closed // wait for refreshLoop to end. 201 } 202 } 203 204 // setFallbackNodes sets the initial points of contact. These nodes 205 // are used to connect to the network if the table is empty and there 206 // are no known nodes in the database. 207 func (tab *Table) setFallbackNodes(nodes []*Node) error { 208 for _, n := range nodes { 209 if err := n.validateComplete(); err != nil { 210 return fmt.Errorf("bad bootstrap/fallback node %q (%v)", n, err) 211 } 212 } 213 tab.nursery = make([]*Node, 0, len(nodes)) 214 for _, n := range nodes { 215 cpy := *n 216 // Recompute cpy.sha because the node might not have been 217 // created by NewNode or ParseNode. 218 cpy.sha = crypto.Keccak256Hash(n.ID[:]) 219 tab.nursery = append(tab.nursery, &cpy) 220 } 221 return nil 222 } 223 224 // isInitDone returns whether the table's initial seeding procedure has completed. 225 func (tab *Table) isInitDone() bool { 226 select { 227 case <-tab.initDone: 228 return true 229 default: 230 return false 231 } 232 } 233 234 // Resolve searches for a specific node with the given ID. 235 // It returns nil if the node could not be found. 236 func (tab *Table) Resolve(targetID NodeID) *Node { 237 // If the node is present in the local table, no 238 // network interaction is required. 239 hash := crypto.Keccak256Hash(targetID[:]) 240 tab.mutex.Lock() 241 cl := tab.closest(hash, 1) 242 tab.mutex.Unlock() 243 if len(cl.entries) > 0 && cl.entries[0].ID == targetID { 244 return cl.entries[0] 245 } 246 // Otherwise, do a network lookup. 247 result := tab.Lookup(targetID) 248 for _, n := range result { 249 if n.ID == targetID { 250 return n 251 } 252 } 253 return nil 254 } 255 256 // Lookup performs a network search for nodes close 257 // to the given target. It approaches the target by querying 258 // nodes that are closer to it on each iteration. 259 // The given target does not need to be an actual node 260 // identifier. 261 func (tab *Table) Lookup(targetID NodeID) []*Node { 262 return tab.lookup(targetID, true) 263 } 264 265 func (tab *Table) lookup(targetID NodeID, refreshIfEmpty bool) []*Node { 266 var ( 267 target = crypto.Keccak256Hash(targetID[:]) 268 asked = make(map[NodeID]bool) 269 seen = make(map[NodeID]bool) 270 reply = make(chan []*Node, alpha) 271 pendingQueries = 0 272 result *nodesByDistance 273 ) 274 // don't query further if we hit ourself. 275 // unlikely to happen often in practice. 276 asked[tab.self.ID] = true 277 278 for { 279 tab.mutex.Lock() 280 // generate initial result set 281 result = tab.closest(target, bucketSize) 282 tab.mutex.Unlock() 283 if len(result.entries) > 0 || !refreshIfEmpty { 284 break 285 } 286 // The result set is empty, all nodes were dropped, refresh. 287 // We actually wait for the refresh to complete here. The very 288 // first query will hit this case and run the bootstrapping 289 // logic. 290 <-tab.refresh() 291 refreshIfEmpty = false 292 } 293 294 for { 295 // ask the alpha closest nodes that we haven't asked yet 296 for i := 0; i < len(result.entries) && pendingQueries < alpha; i++ { 297 n := result.entries[i] 298 if !asked[n.ID] { 299 asked[n.ID] = true 300 pendingQueries++ 301 go func() { 302 // Find potential neighbors to bond with 303 r, err := tab.net.findnode(n.ID, n.addr(), targetID) 304 if err != nil { 305 // Bump the failure counter to detect and evacuate non-bonded entries 306 fails := tab.db.findFails(n.ID) + 1 307 tab.db.updateFindFails(n.ID, fails) 308 log.Trace("Bumping findnode failure counter", "id", n.ID, "failcount", fails) 309 310 if fails >= maxFindnodeFailures { 311 log.Trace("Too many findnode failures, dropping", "id", n.ID, "failcount", fails) 312 tab.delete(n) 313 } 314 } 315 reply <- tab.bondall(r) 316 }() 317 } 318 } 319 if pendingQueries == 0 { 320 // we have asked all closest nodes, stop the search 321 break 322 } 323 // wait for the next reply 324 for _, n := range <-reply { 325 if n != nil && !seen[n.ID] { 326 seen[n.ID] = true 327 result.push(n, bucketSize) 328 } 329 } 330 pendingQueries-- 331 } 332 return result.entries 333 } 334 335 func (tab *Table) refresh() <-chan struct{} { 336 done := make(chan struct{}) 337 select { 338 case tab.refreshReq <- done: 339 case <-tab.closed: 340 close(done) 341 } 342 return done 343 } 344 345 // loop schedules refresh, revalidate runs and coordinates shutdown. 346 func (tab *Table) loop() { 347 var ( 348 revalidate = time.NewTimer(tab.nextRevalidateTime()) 349 refresh = time.NewTicker(refreshInterval) 350 copyNodes = time.NewTicker(copyNodesInterval) 351 revalidateDone = make(chan struct{}) 352 refreshDone = make(chan struct{}) // where doRefresh reports completion 353 waiting = []chan struct{}{tab.initDone} // holds waiting callers while doRefresh runs 354 ) 355 defer refresh.Stop() 356 defer revalidate.Stop() 357 defer copyNodes.Stop() 358 359 // Start initial refresh. 360 go tab.doRefresh(refreshDone) 361 362 loop: 363 for { 364 select { 365 case <-refresh.C: 366 tab.seedRand() 367 if refreshDone == nil { 368 refreshDone = make(chan struct{}) 369 go tab.doRefresh(refreshDone) 370 } 371 case req := <-tab.refreshReq: 372 waiting = append(waiting, req) 373 if refreshDone == nil { 374 refreshDone = make(chan struct{}) 375 go tab.doRefresh(refreshDone) 376 } 377 case <-refreshDone: 378 for _, ch := range waiting { 379 close(ch) 380 } 381 waiting, refreshDone = nil, nil 382 case <-revalidate.C: 383 go tab.doRevalidate(revalidateDone) 384 case <-revalidateDone: 385 revalidate.Reset(tab.nextRevalidateTime()) 386 case <-copyNodes.C: 387 go tab.copyBondedNodes() 388 case <-tab.closeReq: 389 break loop 390 } 391 } 392 393 if tab.net != nil { 394 tab.net.close() 395 } 396 if refreshDone != nil { 397 <-refreshDone 398 } 399 for _, ch := range waiting { 400 close(ch) 401 } 402 tab.db.close() 403 close(tab.closed) 404 } 405 406 // doRefresh performs a lookup for a random target to keep buckets 407 // full. seed nodes are inserted if the table is empty (initial 408 // bootstrap or discarded faulty peers). 409 func (tab *Table) doRefresh(done chan struct{}) { 410 defer close(done) 411 412 // Load nodes from the database and insert 413 // them. This should yield a few previously seen nodes that are 414 // (hopefully) still alive. 415 tab.loadSeedNodes(true) 416 417 // Run self lookup to discover new neighbor nodes. 418 tab.lookup(tab.self.ID, false) 419 420 // The Kademlia paper specifies that the bucket refresh should 421 // perform a lookup in the least recently used bucket. We cannot 422 // adhere to this because the findnode target is a 512bit value 423 // (not hash-sized) and it is not easily possible to generate a 424 // sha3 preimage that falls into a chosen bucket. 425 // We perform a few lookups with a random target instead. 426 for i := 0; i < 3; i++ { 427 var target NodeID 428 crand.Read(target[:]) 429 tab.lookup(target, false) 430 } 431 } 432 433 func (tab *Table) loadSeedNodes(bond bool) { 434 seeds := tab.db.querySeeds(seedCount, seedMaxAge) 435 seeds = append(seeds, tab.nursery...) 436 if bond { 437 seeds = tab.bondall(seeds) 438 } 439 for i := range seeds { 440 seed := seeds[i] 441 age := log.Lazy{Fn: func() interface{} { return time.Since(tab.db.bondTime(seed.ID)) }} 442 log.Debug("Found seed node in database", "id", seed.ID, "addr", seed.addr(), "age", age) 443 tab.add(seed) 444 } 445 } 446 447 // doRevalidate checks that the last node in a random bucket is still live 448 // and replaces or deletes the node if it isn't. 449 func (tab *Table) doRevalidate(done chan<- struct{}) { 450 defer func() { done <- struct{}{} }() 451 452 last, bi := tab.nodeToRevalidate() 453 if last == nil { 454 // No non-empty bucket found. 455 return 456 } 457 458 // Ping the selected node and wait for a pong. 459 err := tab.ping(last.ID, last.addr()) 460 461 tab.mutex.Lock() 462 defer tab.mutex.Unlock() 463 b := tab.buckets[bi] 464 if err == nil { 465 // The node responded, move it to the front. 466 log.Debug("Revalidated node", "b", bi, "id", last.ID) 467 b.bump(last) 468 return 469 } 470 // No reply received, pick a replacement or delete the node if there aren't 471 // any replacements. 472 if r := tab.replace(b, last); r != nil { 473 log.Debug("Replaced dead node", "b", bi, "id", last.ID, "ip", last.IP, "r", r.ID, "rip", r.IP) 474 } else { 475 log.Debug("Removed dead node", "b", bi, "id", last.ID, "ip", last.IP) 476 } 477 } 478 479 // nodeToRevalidate returns the last node in a random, non-empty bucket. 480 func (tab *Table) nodeToRevalidate() (n *Node, bi int) { 481 tab.mutex.Lock() 482 defer tab.mutex.Unlock() 483 484 for _, bi = range tab.rand.Perm(len(tab.buckets)) { 485 b := tab.buckets[bi] 486 if len(b.entries) > 0 { 487 last := b.entries[len(b.entries)-1] 488 return last, bi 489 } 490 } 491 return nil, 0 492 } 493 494 func (tab *Table) nextRevalidateTime() time.Duration { 495 tab.mutex.Lock() 496 defer tab.mutex.Unlock() 497 498 return time.Duration(tab.rand.Int63n(int64(revalidateInterval))) 499 } 500 501 // copyBondedNodes adds nodes from the table to the database if they have been in the table 502 // longer then minTableTime. 503 func (tab *Table) copyBondedNodes() { 504 tab.mutex.Lock() 505 defer tab.mutex.Unlock() 506 507 now := time.Now() 508 for _, b := range tab.buckets { 509 for _, n := range b.entries { 510 if now.Sub(n.addedAt) >= seedMinTableTime { 511 tab.db.updateNode(n) 512 } 513 } 514 } 515 } 516 517 // closest returns the n nodes in the table that are closest to the 518 // given id. The caller must hold tab.mutex. 519 func (tab *Table) closest(target common.Hash, nresults int) *nodesByDistance { 520 // This is a very wasteful way to find the closest nodes but 521 // obviously correct. I believe that tree-based buckets would make 522 // this easier to implement efficiently. 523 close := &nodesByDistance{target: target} 524 for _, b := range tab.buckets { 525 for _, n := range b.entries { 526 close.push(n, nresults) 527 } 528 } 529 return close 530 } 531 532 func (tab *Table) len() (n int) { 533 for _, b := range tab.buckets { 534 n += len(b.entries) 535 } 536 return n 537 } 538 539 // bondall bonds with all given nodes concurrently and returns 540 // those nodes for which bonding has probably succeeded. 541 func (tab *Table) bondall(nodes []*Node) (result []*Node) { 542 rc := make(chan *Node, len(nodes)) 543 for i := range nodes { 544 go func(n *Node) { 545 nn, _ := tab.bond(false, n.ID, n.addr(), n.TCP) 546 rc <- nn 547 }(nodes[i]) 548 } 549 for range nodes { 550 if n := <-rc; n != nil { 551 result = append(result, n) 552 } 553 } 554 return result 555 } 556 557 // bond ensures the local node has a bond with the given remote node. 558 // It also attempts to insert the node into the table if bonding succeeds. 559 // The caller must not hold tab.mutex. 560 // 561 // A bond is must be established before sending findnode requests. 562 // Both sides must have completed a ping/pong exchange for a bond to 563 // exist. The total number of active bonding processes is limited in 564 // order to restrain network use. 565 // 566 // bond is meant to operate idempotently in that bonding with a remote 567 // node which still remembers a previously established bond will work. 568 // The remote node will simply not send a ping back, causing waitping 569 // to time out. 570 // 571 // If pinged is true, the remote node has just pinged us and one half 572 // of the process can be skipped. 573 func (tab *Table) bond(pinged bool, id NodeID, addr *net.UDPAddr, tcpPort uint16) (*Node, error) { 574 if id == tab.self.ID { 575 return nil, errors.New("is self") 576 } 577 if pinged && !tab.isInitDone() { 578 return nil, errors.New("still initializing") 579 } 580 // Start bonding if we haven't seen this node for a while or if it failed findnode too often. 581 node, fails := tab.db.node(id), tab.db.findFails(id) 582 age := time.Since(tab.db.bondTime(id)) 583 var result error 584 if fails > 0 || age > nodeDBNodeExpiration { 585 log.Trace("Starting bonding ping/pong", "id", id, "known", node != nil, "failcount", fails, "age", age) 586 587 tab.bondmu.Lock() 588 w := tab.bonding[id] 589 if w != nil { 590 // Wait for an existing bonding process to complete. 591 tab.bondmu.Unlock() 592 <-w.done 593 } else { 594 // Register a new bonding process. 595 w = &bondproc{done: make(chan struct{})} 596 tab.bonding[id] = w 597 tab.bondmu.Unlock() 598 // Do the ping/pong. The result goes into w. 599 tab.pingpong(w, pinged, id, addr, tcpPort) 600 // Unregister the process after it's done. 601 tab.bondmu.Lock() 602 delete(tab.bonding, id) 603 tab.bondmu.Unlock() 604 } 605 // Retrieve the bonding results 606 result = w.err 607 if result == nil { 608 node = w.n 609 } 610 } 611 // Add the node to the table even if the bonding ping/pong 612 // fails. It will be relaced quickly if it continues to be 613 // unresponsive. 614 if node != nil { 615 tab.add(node) 616 tab.db.updateFindFails(id, 0) 617 } 618 return node, result 619 } 620 621 func (tab *Table) pingpong(w *bondproc, pinged bool, id NodeID, addr *net.UDPAddr, tcpPort uint16) { 622 // Request a bonding slot to limit network usage 623 <-tab.bondslots 624 defer func() { tab.bondslots <- struct{}{} }() 625 626 // Ping the remote side and wait for a pong. 627 if w.err = tab.ping(id, addr); w.err != nil { 628 close(w.done) 629 return 630 } 631 if !pinged { 632 // Give the remote node a chance to ping us before we start 633 // sending findnode requests. If they still remember us, 634 // waitping will simply time out. 635 tab.net.waitping(id) 636 } 637 // Bonding succeeded, update the node database. 638 w.n = NewNode(id, addr.IP, uint16(addr.Port), tcpPort) 639 close(w.done) 640 } 641 642 // ping a remote endpoint and wait for a reply, also updating the node 643 // database accordingly. 644 func (tab *Table) ping(id NodeID, addr *net.UDPAddr) error { 645 tab.db.updateLastPing(id, time.Now()) 646 if err := tab.net.ping(id, addr); err != nil { 647 return err 648 } 649 tab.db.updateBondTime(id, time.Now()) 650 return nil 651 } 652 653 // bucket returns the bucket for the given node ID hash. 654 func (tab *Table) bucket(sha common.Hash) *bucket { 655 d := logdist(tab.self.sha, sha) 656 if d <= bucketMinDistance { 657 return tab.buckets[0] 658 } 659 return tab.buckets[d-bucketMinDistance-1] 660 } 661 662 // add attempts to add the given node its corresponding bucket. If the 663 // bucket has space available, adding the node succeeds immediately. 664 // Otherwise, the node is added if the least recently active node in 665 // the bucket does not respond to a ping packet. 666 // 667 // The caller must not hold tab.mutex. 668 func (tab *Table) add(new *Node) { 669 tab.mutex.Lock() 670 defer tab.mutex.Unlock() 671 672 b := tab.bucket(new.sha) 673 if !tab.bumpOrAdd(b, new) { 674 // Node is not in table. Add it to the replacement list. 675 tab.addReplacement(b, new) 676 } 677 } 678 679 // stuff adds nodes the table to the end of their corresponding bucket 680 // if the bucket is not full. The caller must not hold tab.mutex. 681 func (tab *Table) stuff(nodes []*Node) { 682 tab.mutex.Lock() 683 defer tab.mutex.Unlock() 684 685 for _, n := range nodes { 686 if n.ID == tab.self.ID { 687 continue // don't add self 688 } 689 b := tab.bucket(n.sha) 690 if len(b.entries) < bucketSize { 691 tab.bumpOrAdd(b, n) 692 } 693 } 694 } 695 696 // delete removes an entry from the node table (used to evacuate 697 // failed/non-bonded discovery peers). 698 func (tab *Table) delete(node *Node) { 699 tab.mutex.Lock() 700 defer tab.mutex.Unlock() 701 702 tab.deleteInBucket(tab.bucket(node.sha), node) 703 } 704 705 func (tab *Table) addIP(b *bucket, ip net.IP) bool { 706 if netutil.IsLAN(ip) { 707 return true 708 } 709 if !tab.ips.Add(ip) { 710 log.Debug("IP exceeds table limit", "ip", ip) 711 return false 712 } 713 if !b.ips.Add(ip) { 714 log.Debug("IP exceeds bucket limit", "ip", ip) 715 tab.ips.Remove(ip) 716 return false 717 } 718 return true 719 } 720 721 func (tab *Table) removeIP(b *bucket, ip net.IP) { 722 if netutil.IsLAN(ip) { 723 return 724 } 725 tab.ips.Remove(ip) 726 b.ips.Remove(ip) 727 } 728 729 func (tab *Table) addReplacement(b *bucket, n *Node) { 730 for _, e := range b.replacements { 731 if e.ID == n.ID { 732 return // already in list 733 } 734 } 735 if !tab.addIP(b, n.IP) { 736 return 737 } 738 var removed *Node 739 b.replacements, removed = pushNode(b.replacements, n, maxReplacements) 740 if removed != nil { 741 tab.removeIP(b, removed.IP) 742 } 743 } 744 745 // replace removes n from the replacement list and replaces 'last' with it if it is the 746 // last entry in the bucket. If 'last' isn't the last entry, it has either been replaced 747 // with someone else or became active. 748 func (tab *Table) replace(b *bucket, last *Node) *Node { 749 if len(b.entries) == 0 || b.entries[len(b.entries)-1].ID != last.ID { 750 // Entry has moved, don't replace it. 751 return nil 752 } 753 // Still the last entry. 754 if len(b.replacements) == 0 { 755 tab.deleteInBucket(b, last) 756 return nil 757 } 758 r := b.replacements[tab.rand.Intn(len(b.replacements))] 759 b.replacements = deleteNode(b.replacements, r) 760 b.entries[len(b.entries)-1] = r 761 tab.removeIP(b, last.IP) 762 return r 763 } 764 765 // bump moves the given node to the front of the bucket entry list 766 // if it is contained in that list. 767 func (b *bucket) bump(n *Node) bool { 768 for i := range b.entries { 769 if b.entries[i].ID == n.ID { 770 // move it to the front 771 copy(b.entries[1:], b.entries[:i]) 772 b.entries[0] = n 773 return true 774 } 775 } 776 return false 777 } 778 779 // bumpOrAdd moves n to the front of the bucket entry list or adds it if the list isn't 780 // full. The return value is true if n is in the bucket. 781 func (tab *Table) bumpOrAdd(b *bucket, n *Node) bool { 782 if b.bump(n) { 783 return true 784 } 785 if len(b.entries) >= bucketSize || !tab.addIP(b, n.IP) { 786 return false 787 } 788 b.entries, _ = pushNode(b.entries, n, bucketSize) 789 b.replacements = deleteNode(b.replacements, n) 790 n.addedAt = time.Now() 791 if tab.nodeAddedHook != nil { 792 tab.nodeAddedHook(n) 793 } 794 return true 795 } 796 797 func (tab *Table) deleteInBucket(b *bucket, n *Node) { 798 b.entries = deleteNode(b.entries, n) 799 tab.removeIP(b, n.IP) 800 } 801 802 // pushNode adds n to the front of list, keeping at most max items. 803 func pushNode(list []*Node, n *Node, max int) ([]*Node, *Node) { 804 if len(list) < max { 805 list = append(list, nil) 806 } 807 removed := list[len(list)-1] 808 copy(list[1:], list) 809 list[0] = n 810 return list, removed 811 } 812 813 // deleteNode removes n from list. 814 func deleteNode(list []*Node, n *Node) []*Node { 815 for i := range list { 816 if list[i].ID == n.ID { 817 return append(list[:i], list[i+1:]...) 818 } 819 } 820 return list 821 } 822 823 // nodesByDistance is a list of nodes, ordered by 824 // distance to target. 825 type nodesByDistance struct { 826 entries []*Node 827 target common.Hash 828 } 829 830 // push adds the given node to the list, keeping the total size below maxElems. 831 func (h *nodesByDistance) push(n *Node, maxElems int) { 832 ix := sort.Search(len(h.entries), func(i int) bool { 833 return distcmp(h.target, h.entries[i].sha, n.sha) > 0 834 }) 835 if len(h.entries) < maxElems { 836 h.entries = append(h.entries, n) 837 } 838 if ix == len(h.entries) { 839 // farther away than all nodes we already have. 840 // if there was room for it, the node is now the last element. 841 } else { 842 // slide existing entries down to make room 843 // this will overwrite the entry we just appended. 844 copy(h.entries[ix+1:], h.entries[ix:]) 845 h.entries[ix] = n 846 } 847 }