github.com/quinndk/ethereum_read@v0.0.0-20181211143958-29c55eec3237/go-ethereum-master_read/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/ethereum/go-ethereum/common" 36 "github.com/ethereum/go-ethereum/crypto" 37 "github.com/ethereum/go-ethereum/log" 38 "github.com/ethereum/go-ethereum/p2p/netutil" 39 ) 40 41 const ( 42 // 并发因子 43 alpha = 3 // Kademlia concurrency factor 44 // k桶容量 45 bucketSize = 16 // Kademlia bucket size 46 // 每个k桶更换清单的大小 47 maxReplacements = 10 // Size of per-bucket replacement list 48 49 // We keep buckets for the upper 1/15 of distances because 50 // it's very unlikely we'll ever encounter a node that's closer. 51 // 52 hashBits = len(common.Hash{}) * 8 53 nBuckets = hashBits / 15 // Number of buckets 54 // 最近k桶的距离 55 bucketMinDistance = hashBits - nBuckets // Log distance of closest bucket 56 57 // IP address limits. 58 bucketIPLimit, bucketSubnet = 2, 24 // at most 2 addresses from the same /24 59 tableIPLimit, tableSubnet = 10, 24 60 61 // 节点丢弃的限制,超过这些限制的节点将被丢弃 62 maxFindnodeFailures = 5 // Nodes exceeding this limit are dropped 63 refreshInterval = 30 * time.Minute 64 revalidateInterval = 10 * time.Second 65 copyNodesInterval = 30 * time.Second 66 seedMinTableTime = 5 * time.Minute 67 seedCount = 30 68 seedMaxAge = 5 * 24 * time.Hour 69 ) 70 71 //k-bucket表 72 type Table struct { 73 mutex sync.Mutex // protects buckets, bucket content, nursery, rand 74 // k桶数组 75 buckets [nBuckets]*bucket // index of known nodes by distance 76 // 引导节点 77 nursery []*Node // bootstrap nodes 78 // 随机源头 79 rand *mrand.Rand // source of randomness, periodically reseeded 80 ips netutil.DistinctNetSet 81 82 // 节点数据库 83 db *nodeDB // database of known nodes 84 refreshReq chan chan struct{} 85 initDone chan struct{} 86 closeReq chan struct{} 87 closed chan struct{} 88 89 nodeAddedHook func(*Node) // for testing 90 91 net transport 92 self *Node // metadata of the local node 93 } 94 95 // transport is implemented by the UDP transport. 96 // it is an interface so we can test without opening lots of UDP 97 // sockets and without generating a private key. 98 // 真正寻找节点的接口 99 type transport interface { 100 ping(NodeID, *net.UDPAddr) error 101 findnode(toid NodeID, addr *net.UDPAddr, target NodeID) ([]*Node, error) 102 close() 103 } 104 105 // bucket contains nodes, ordered by their last activity. the entry 106 // that was most recently active is the first element in entries. 107 // 按上一个活动排序的节点 108 // 最近活动的条目是条目中的第一个元素 109 type bucket struct { 110 // 实时节点列表 111 entries []*Node // live entries, sorted by time of last contact 112 // 候补节点,entries满了后之后的节点会存储到这 113 replacements []*Node // recently seen nodes to be used if revalidation fails 114 ips netutil.DistinctNetSet 115 } 116 117 func newTable(t transport, ourID NodeID, ourAddr *net.UDPAddr, nodeDBPath string, bootnodes []*Node) (*Table, error) { 118 // If no node database was given, use an in-memory one 119 // 1.新建节点数据库 120 db, err := newNodeDB(nodeDBPath, nodeDBVersion, ourID) 121 if err != nil { 122 return nil, err 123 } 124 125 // 2.构造k桶表 126 tab := &Table{ 127 net: t, 128 db: db, 129 self: NewNode(ourID, ourAddr.IP, uint16(ourAddr.Port), uint16(ourAddr.Port)), 130 refreshReq: make(chan chan struct{}), 131 initDone: make(chan struct{}), 132 closeReq: make(chan struct{}), 133 closed: make(chan struct{}), 134 rand: mrand.New(mrand.NewSource(0)), 135 ips: netutil.DistinctNetSet{Subnet: tableSubnet, Limit: tableIPLimit}, 136 } 137 138 // 3.设置初始连接点 139 if err := tab.setFallbackNodes(bootnodes); err != nil { 140 return nil, err 141 } 142 143 // 4.填充k桶 144 for i := range tab.buckets { 145 tab.buckets[i] = &bucket{ 146 ips: netutil.DistinctNetSet{Subnet: bucketSubnet, Limit: bucketIPLimit}, 147 } 148 } 149 150 // 4.加载种子节点 151 tab.seedRand() 152 tab.loadSeedNodes() 153 // Start the background expiration goroutine after loading seeds so that the search for 154 // seed nodes also considers older nodes that would otherwise be removed by the 155 // expiration. 156 tab.db.ensureExpirer() 157 158 // 5.开启协程循环更新 159 go tab.loop() 160 return tab, nil 161 } 162 163 func (tab *Table) seedRand() { 164 var b [8]byte 165 crand.Read(b[:]) 166 167 tab.mutex.Lock() 168 tab.rand.Seed(int64(binary.BigEndian.Uint64(b[:]))) 169 tab.mutex.Unlock() 170 } 171 172 // Self returns the local node. 173 // The returned node should not be modified by the caller. 174 func (tab *Table) Self() *Node { 175 return tab.self 176 } 177 178 // ReadRandomNodes fills the given slice with random nodes from the 179 // table. It will not write the same node more than once. The nodes in 180 // the slice are copies and can be modified by the caller. 181 func (tab *Table) ReadRandomNodes(buf []*Node) (n int) { 182 if !tab.isInitDone() { 183 return 0 184 } 185 tab.mutex.Lock() 186 defer tab.mutex.Unlock() 187 188 // Find all non-empty buckets and get a fresh slice of their entries. 189 var buckets [][]*Node 190 for _, b := range tab.buckets { 191 if len(b.entries) > 0 { 192 buckets = append(buckets, b.entries[:]) 193 } 194 } 195 if len(buckets) == 0 { 196 return 0 197 } 198 // Shuffle the buckets. 199 for i := len(buckets) - 1; i > 0; i-- { 200 j := tab.rand.Intn(len(buckets)) 201 buckets[i], buckets[j] = buckets[j], buckets[i] 202 } 203 // Move head of each bucket into buf, removing buckets that become empty. 204 var i, j int 205 for ; i < len(buf); i, j = i+1, (j+1)%len(buckets) { 206 b := buckets[j] 207 buf[i] = &(*b[0]) 208 buckets[j] = b[1:] 209 if len(b) == 1 { 210 buckets = append(buckets[:j], buckets[j+1:]...) 211 } 212 if len(buckets) == 0 { 213 break 214 } 215 } 216 return i + 1 217 } 218 219 // Close terminates the network listener and flushes the node database. 220 func (tab *Table) Close() { 221 select { 222 case <-tab.closed: 223 // already closed. 224 case tab.closeReq <- struct{}{}: 225 <-tab.closed // wait for refreshLoop to end. 226 } 227 } 228 229 // setFallbackNodes sets the initial points of contact. These nodes 230 // are used to connect to the network if the table is empty and there 231 // are no known nodes in the database. 232 func (tab *Table) setFallbackNodes(nodes []*Node) error { 233 for _, n := range nodes { 234 if err := n.validateComplete(); err != nil { 235 return fmt.Errorf("bad bootstrap/fallback node %q (%v)", n, err) 236 } 237 } 238 tab.nursery = make([]*Node, 0, len(nodes)) 239 for _, n := range nodes { 240 cpy := *n 241 // Recompute cpy.sha because the node might not have been 242 // created by NewNode or ParseNode. 243 cpy.sha = crypto.Keccak256Hash(n.ID[:]) 244 tab.nursery = append(tab.nursery, &cpy) 245 } 246 return nil 247 } 248 249 // isInitDone returns whether the table's initial seeding procedure has completed. 250 func (tab *Table) isInitDone() bool { 251 select { 252 case <-tab.initDone: 253 return true 254 default: 255 return false 256 } 257 } 258 259 // Resolve searches for a specific node with the given ID. 260 // It returns nil if the node could not be found. 261 func (tab *Table) Resolve(targetID NodeID) *Node { 262 // If the node is present in the local table, no 263 // network interaction is required. 264 hash := crypto.Keccak256Hash(targetID[:]) 265 tab.mutex.Lock() 266 cl := tab.closest(hash, 1) 267 tab.mutex.Unlock() 268 if len(cl.entries) > 0 && cl.entries[0].ID == targetID { 269 return cl.entries[0] 270 } 271 // Otherwise, do a network lookup. 272 result := tab.Lookup(targetID) 273 for _, n := range result { 274 if n.ID == targetID { 275 return n 276 } 277 } 278 return nil 279 } 280 281 // Lookup performs a network search for nodes close 282 // to the given target. It approaches the target by querying 283 // nodes that are closer to it on each iteration. 284 // The given target does not need to be an actual node 285 // identifier. 286 // 搜索当前节点的附近节点 287 func (tab *Table) Lookup(targetID NodeID) []*Node { 288 return tab.lookup(targetID, true) 289 } 290 291 func (tab *Table) lookup(targetID NodeID, refreshIfEmpty bool) []*Node { 292 var ( 293 target = crypto.Keccak256Hash(targetID[:]) 294 asked = make(map[NodeID]bool) 295 seen = make(map[NodeID]bool) 296 reply = make(chan []*Node, alpha) 297 pendingQueries = 0 298 result *nodesByDistance 299 ) 300 // don't query further if we hit ourself. 301 // unlikely to happen often in practice. 302 // 一般询问自己是没有意义的 303 asked[tab.self.ID] = true 304 305 for { 306 tab.mutex.Lock() 307 // generate initial result set 308 // 获取k桶表中给定节点id的n个节点 309 result = tab.closest(target, bucketSize) 310 tab.mutex.Unlock() 311 if len(result.entries) > 0 || !refreshIfEmpty { 312 313 // k桶表不为空 314 break 315 } 316 // The result set is empty, all nodes were dropped, refresh. 317 // We actually wait for the refresh to complete here. The very 318 // first query will hit this case and run the bootstrapping 319 // logic. 320 321 // k桶表为空 322 <-tab.refresh() 323 refreshIfEmpty = false 324 } 325 326 for { 327 // ask the alpha closest nodes that we haven't asked yet 328 // 询问尚未询问的最接近的节点 329 for i := 0; i < len(result.entries) && pendingQueries < alpha; i++ { 330 n := result.entries[i] 331 // 未被查询的节点 332 if !asked[n.ID] { 333 asked[n.ID] = true 334 pendingQueries++ 335 // 查找节点 336 go tab.findnode(n, targetID, reply) 337 } 338 } 339 if pendingQueries == 0 { 340 // we have asked all closest nodes, stop the search 341 // 所有最近节点都询问过了 342 break 343 } 344 // wait for the next reply 345 for _, n := range <-reply { 346 if n != nil && !seen[n.ID] { 347 seen[n.ID] = true 348 result.push(n, bucketSize) 349 } 350 } 351 pendingQueries-- 352 } 353 return result.entries 354 } 355 356 func (tab *Table) findnode(n *Node, targetID NodeID, reply chan<- []*Node) { 357 fails := tab.db.findFails(n.ID) 358 r, err := tab.net.findnode(n.ID, n.addr(), targetID) 359 if err != nil || len(r) == 0 { 360 fails++ 361 tab.db.updateFindFails(n.ID, fails) 362 log.Trace("Findnode failed", "id", n.ID, "failcount", fails, "err", err) 363 if fails >= maxFindnodeFailures { 364 log.Trace("Too many findnode failures, dropping", "id", n.ID, "failcount", fails) 365 tab.delete(n) 366 } 367 } else if fails > 0 { 368 tab.db.updateFindFails(n.ID, fails-1) 369 } 370 371 // Grab as many nodes as possible. Some of them might not be alive anymore, but we'll 372 // just remove those again during revalidation. 373 // 将所有节点加入k桶表,尽管有些已经离线(我们会在重新验证时删除这些节点) 374 for _, n := range r { 375 tab.add(n) 376 } 377 reply <- r 378 } 379 380 func (tab *Table) refresh() <-chan struct{} { 381 done := make(chan struct{}) 382 select { 383 case tab.refreshReq <- done: 384 case <-tab.closed: 385 close(done) 386 } 387 return done 388 } 389 390 // loop schedules refresh, revalidate runs and coordinates shutdown. 391 func (tab *Table) loop() { 392 var ( 393 revalidate = time.NewTimer(tab.nextRevalidateTime()) 394 refresh = time.NewTicker(refreshInterval) 395 copyNodes = time.NewTicker(copyNodesInterval) 396 revalidateDone = make(chan struct{}) 397 refreshDone = make(chan struct{}) // where doRefresh reports completion 398 waiting = []chan struct{}{tab.initDone} // holds waiting callers while doRefresh runs 399 ) 400 defer refresh.Stop() 401 defer revalidate.Stop() 402 defer copyNodes.Stop() 403 404 // Start initial refresh. 405 // 初始化刷新 406 go tab.doRefresh(refreshDone) 407 408 loop: 409 for { 410 select { 411 case <-refresh.C: 412 tab.seedRand() 413 if refreshDone == nil { 414 refreshDone = make(chan struct{}) 415 go tab.doRefresh(refreshDone) 416 } 417 case req := <-tab.refreshReq: 418 // 将刷新请求加入通道数组 419 waiting = append(waiting, req) 420 if refreshDone == nil { 421 refreshDone = make(chan struct{}) 422 go tab.doRefresh(refreshDone) 423 } 424 case <-refreshDone: 425 // 刷新完毕,关闭通道 426 for _, ch := range waiting { 427 close(ch) 428 } 429 waiting, refreshDone = nil, nil 430 case <-revalidate.C: 431 // 重新验证 432 go tab.doRevalidate(revalidateDone) 433 case <-revalidateDone: 434 revalidate.Reset(tab.nextRevalidateTime()) 435 case <-copyNodes.C: 436 // 拷贝活跃节点 437 go tab.copyLiveNodes() 438 case <-tab.closeReq: 439 break loop 440 } 441 } 442 443 if tab.net != nil { 444 tab.net.close() 445 } 446 if refreshDone != nil { 447 <-refreshDone 448 } 449 for _, ch := range waiting { 450 close(ch) 451 } 452 tab.db.close() 453 close(tab.closed) 454 } 455 456 // doRefresh performs a lookup for a random target to keep buckets 457 // full. seed nodes are inserted if the table is empty (initial 458 // bootstrap or discarded faulty peers). 459 // 执行随机目标查找并保持桶满 460 // 会在第一次k桶表为空的时候插入种子节点 461 func (tab *Table) doRefresh(done chan struct{}) { 462 defer close(done) 463 464 // Load nodes from the database and insert 465 // them. This should yield a few previously seen nodes that are 466 // (hopefully) still alive. 467 // 加载种子节点 468 tab.loadSeedNodes() 469 470 // Run self lookup to discover new neighbor nodes. 471 // 发现当前节点的令居节点 472 tab.lookup(tab.self.ID, false) 473 474 // The Kademlia paper specifies that the bucket refresh should 475 // perform a lookup in the least recently used bucket. We cannot 476 // adhere to this because the findnode target is a 512bit value 477 // (not hash-sized) and it is not easily possible to generate a 478 // sha3 preimage that falls into a chosen bucket. 479 // We perform a few lookups with a random target instead. 480 // 使用随机的target进行查找,因为这里查找节点的id是一个512位的值, 481 // 我们不容易生成属于所选存储桶的sha3前缀映像 482 for i := 0; i < 3; i++ { 483 var target NodeID 484 crand.Read(target[:]) 485 tab.lookup(target, false) 486 } 487 } 488 489 func (tab *Table) loadSeedNodes() { 490 seeds := tab.db.querySeeds(seedCount, seedMaxAge) 491 seeds = append(seeds, tab.nursery...) 492 for i := range seeds { 493 seed := seeds[i] 494 age := log.Lazy{Fn: func() interface{} { return time.Since(tab.db.lastPongReceived(seed.ID)) }} 495 log.Debug("Found seed node in database", "id", seed.ID, "addr", seed.addr(), "age", age) 496 tab.add(seed) 497 } 498 } 499 500 // doRevalidate checks that the last node in a random bucket is still live 501 // and replaces or deletes the node if it isn't. 502 // 检查最后一个节点是否在线,不在线就更换或删除 503 func (tab *Table) doRevalidate(done chan<- struct{}) { 504 defer func() { done <- struct{}{} }() 505 506 last, bi := tab.nodeToRevalidate() 507 if last == nil { 508 // No non-empty bucket found. 509 return 510 } 511 512 // Ping the selected node and wait for a pong. 513 // 发出ping指令,等待pong回复 514 err := tab.net.ping(last.ID, last.addr()) 515 516 tab.mutex.Lock() 517 defer tab.mutex.Unlock() 518 b := tab.buckets[bi] 519 if err == nil { 520 // The node responded, move it to the front. 521 log.Trace("Revalidated node", "b", bi, "id", last.ID) 522 b.bump(last) 523 return 524 } 525 // No reply received, pick a replacement or delete the node if there aren't 526 // any replacements. 527 // 没有事收到ping的回复,更换或删除节点 528 if r := tab.replace(b, last); r != nil { 529 log.Trace("Replaced dead node", "b", bi, "id", last.ID, "ip", last.IP, "r", r.ID, "rip", r.IP) 530 } else { 531 log.Trace("Removed dead node", "b", bi, "id", last.ID, "ip", last.IP) 532 } 533 } 534 535 // nodeToRevalidate returns the last node in a random, non-empty bucket. 536 // 获取随机非空k桶的最后一个节点 537 func (tab *Table) nodeToRevalidate() (n *Node, bi int) { 538 tab.mutex.Lock() 539 defer tab.mutex.Unlock() 540 541 for _, bi = range tab.rand.Perm(len(tab.buckets)) { 542 b := tab.buckets[bi] 543 if len(b.entries) > 0 { 544 last := b.entries[len(b.entries)-1] 545 return last, bi 546 } 547 } 548 return nil, 0 549 } 550 551 func (tab *Table) nextRevalidateTime() time.Duration { 552 tab.mutex.Lock() 553 defer tab.mutex.Unlock() 554 555 return time.Duration(tab.rand.Int63n(int64(revalidateInterval))) 556 } 557 558 // copyLiveNodes adds nodes from the table to the database if they have been in the table 559 // longer then minTableTime. 560 func (tab *Table) copyLiveNodes() { 561 tab.mutex.Lock() 562 defer tab.mutex.Unlock() 563 564 now := time.Now() 565 for _, b := range tab.buckets { 566 for _, n := range b.entries { 567 if now.Sub(n.addedAt) >= seedMinTableTime { 568 tab.db.updateNode(n) 569 } 570 } 571 } 572 } 573 574 // closest returns the n nodes in the table that are closest to the 575 // given id. The caller must hold tab.mutex. 576 // 获取k桶表中给定节点id的n个节点 577 func (tab *Table) closest(target common.Hash, nresults int) *nodesByDistance { 578 // This is a very wasteful way to find the closest nodes but 579 // obviously correct. I believe that tree-based buckets would make 580 // this easier to implement efficiently. 581 close := &nodesByDistance{target: target} 582 for _, b := range tab.buckets { 583 for _, n := range b.entries { 584 close.push(n, nresults) 585 } 586 } 587 return close 588 } 589 590 func (tab *Table) len() (n int) { 591 for _, b := range tab.buckets { 592 n += len(b.entries) 593 } 594 return n 595 } 596 597 // bucket returns the bucket for the given node ID hash. 598 func (tab *Table) bucket(sha common.Hash) *bucket { 599 d := logdist(tab.self.sha, sha) 600 if d <= bucketMinDistance { 601 return tab.buckets[0] 602 } 603 return tab.buckets[d-bucketMinDistance-1] 604 } 605 606 // add attempts to add the given node to its corresponding bucket. If the bucket has space 607 // available, adding the node succeeds immediately. Otherwise, the node is added if the 608 // least recently active node in the bucket does not respond to a ping packet. 609 // 610 // The caller must not hold tab.mutex. 611 func (tab *Table) add(n *Node) { 612 tab.mutex.Lock() 613 defer tab.mutex.Unlock() 614 615 b := tab.bucket(n.sha) 616 if !tab.bumpOrAdd(b, n) { 617 // Node is not in table. Add it to the replacement list. 618 tab.addReplacement(b, n) 619 } 620 } 621 622 // addThroughPing adds the given node to the table. Compared to plain 623 // 'add' there is an additional safety measure: if the table is still 624 // initializing the node is not added. This prevents an attack where the 625 // table could be filled by just sending ping repeatedly. 626 // 627 // The caller must not hold tab.mutex. 628 // 与普通的“添加”相比,还有一个额外的安全措施:如果表仍在初始化,则不添加节点。 629 // 这样可以防止因重复发送ping而填充表的攻击 630 func (tab *Table) addThroughPing(n *Node) { 631 if !tab.isInitDone() { 632 return 633 } 634 tab.add(n) 635 } 636 637 // stuff adds nodes the table to the end of their corresponding bucket 638 // if the bucket is not full. The caller must not hold tab.mutex. 639 func (tab *Table) stuff(nodes []*Node) { 640 tab.mutex.Lock() 641 defer tab.mutex.Unlock() 642 643 for _, n := range nodes { 644 if n.ID == tab.self.ID { 645 continue // don't add self 646 } 647 b := tab.bucket(n.sha) 648 if len(b.entries) < bucketSize { 649 tab.bumpOrAdd(b, n) 650 } 651 } 652 } 653 654 // delete removes an entry from the node table. It is used to evacuate dead nodes. 655 func (tab *Table) delete(node *Node) { 656 tab.mutex.Lock() 657 defer tab.mutex.Unlock() 658 659 tab.deleteInBucket(tab.bucket(node.sha), node) 660 } 661 662 func (tab *Table) addIP(b *bucket, ip net.IP) bool { 663 if netutil.IsLAN(ip) { 664 return true 665 } 666 if !tab.ips.Add(ip) { 667 log.Debug("IP exceeds table limit", "ip", ip) 668 return false 669 } 670 if !b.ips.Add(ip) { 671 log.Debug("IP exceeds bucket limit", "ip", ip) 672 tab.ips.Remove(ip) 673 return false 674 } 675 return true 676 } 677 678 func (tab *Table) removeIP(b *bucket, ip net.IP) { 679 if netutil.IsLAN(ip) { 680 return 681 } 682 tab.ips.Remove(ip) 683 b.ips.Remove(ip) 684 } 685 686 func (tab *Table) addReplacement(b *bucket, n *Node) { 687 for _, e := range b.replacements { 688 if e.ID == n.ID { 689 return // already in list 690 } 691 } 692 if !tab.addIP(b, n.IP) { 693 return 694 } 695 var removed *Node 696 b.replacements, removed = pushNode(b.replacements, n, maxReplacements) 697 if removed != nil { 698 tab.removeIP(b, removed.IP) 699 } 700 } 701 702 // replace removes n from the replacement list and replaces 'last' with it if it is the 703 // last entry in the bucket. If 'last' isn't the last entry, it has either been replaced 704 // with someone else or became active. 705 // 这里验证失败后会把前面buket结构里replacements里的节点候补到entries 706 func (tab *Table) replace(b *bucket, last *Node) *Node { 707 if len(b.entries) == 0 || b.entries[len(b.entries)-1].ID != last.ID { 708 // Entry has moved, don't replace it. 709 return nil 710 } 711 // Still the last entry. 712 if len(b.replacements) == 0 { 713 tab.deleteInBucket(b, last) 714 return nil 715 } 716 r := b.replacements[tab.rand.Intn(len(b.replacements))] 717 b.replacements = deleteNode(b.replacements, r) 718 b.entries[len(b.entries)-1] = r 719 tab.removeIP(b, last.IP) 720 return r 721 } 722 723 // bump moves the given node to the front of the bucket entry list 724 // if it is contained in that list. 725 // 将节点node移动到最前 726 func (b *bucket) bump(n *Node) bool { 727 for i := range b.entries { 728 if b.entries[i].ID == n.ID { 729 // move it to the front 730 copy(b.entries[1:], b.entries[:i]) 731 b.entries[0] = n 732 return true 733 } 734 } 735 return false 736 } 737 738 // bumpOrAdd moves n to the front of the bucket entry list or adds it if the list isn't 739 // full. The return value is true if n is in the bucket. 740 func (tab *Table) bumpOrAdd(b *bucket, n *Node) bool { 741 if b.bump(n) { 742 return true 743 } 744 if len(b.entries) >= bucketSize || !tab.addIP(b, n.IP) { 745 return false 746 } 747 b.entries, _ = pushNode(b.entries, n, bucketSize) 748 b.replacements = deleteNode(b.replacements, n) 749 n.addedAt = time.Now() 750 if tab.nodeAddedHook != nil { 751 tab.nodeAddedHook(n) 752 } 753 return true 754 } 755 756 func (tab *Table) deleteInBucket(b *bucket, n *Node) { 757 b.entries = deleteNode(b.entries, n) 758 tab.removeIP(b, n.IP) 759 } 760 761 // pushNode adds n to the front of list, keeping at most max items. 762 func pushNode(list []*Node, n *Node, max int) ([]*Node, *Node) { 763 if len(list) < max { 764 list = append(list, nil) 765 } 766 removed := list[len(list)-1] 767 copy(list[1:], list) 768 list[0] = n 769 return list, removed 770 } 771 772 // deleteNode removes n from list. 773 func deleteNode(list []*Node, n *Node) []*Node { 774 for i := range list { 775 if list[i].ID == n.ID { 776 return append(list[:i], list[i+1:]...) 777 } 778 } 779 return list 780 } 781 782 // nodesByDistance is a list of nodes, ordered by 783 // distance to target. 784 // 根据距离远近排序的邻居节点 785 type nodesByDistance struct { 786 entries []*Node 787 target common.Hash 788 } 789 790 // push adds the given node to the list, keeping the total size below maxElems. 791 // 将节点添加到给定列表并维持大小小于maxElems 792 // 793 func (h *nodesByDistance) push(n *Node, maxElems int) { 794 795 // 根据节点到target的距离排序 796 ix := sort.Search(len(h.entries), func(i int) bool { 797 return distcmp(h.target, h.entries[i].sha, n.sha) > 0 798 }) 799 800 // 大小未超出限制,将节点加入 801 if len(h.entries) < maxElems { 802 h.entries = append(h.entries, n) 803 } 804 if ix == len(h.entries) { 805 // farther away than all nodes we already have. 806 // if there was room for it, the node is now the last element. 807 } else { 808 // slide existing entries down to make room 809 // this will overwrite the entry we just appended. 810 copy(h.entries[ix+1:], h.entries[ix:]) 811 h.entries[ix] = n 812 } 813 }