github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/p2p/discover/table.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2015 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 //包发现实现了节点发现协议。 26 // 27 //节点发现协议提供了一种查找 28 //可以连接到。它使用一个类似kademlia的协议来维护 29 //所有监听的ID和端点的分布式数据库 30 //节点。 31 package discover 32 33 import ( 34 crand "crypto/rand" 35 "encoding/binary" 36 "fmt" 37 mrand "math/rand" 38 "net" 39 "sort" 40 "sync" 41 "time" 42 43 "github.com/ethereum/go-ethereum/common" 44 "github.com/ethereum/go-ethereum/crypto" 45 "github.com/ethereum/go-ethereum/log" 46 "github.com/ethereum/go-ethereum/p2p/netutil" 47 ) 48 49 const ( 50 alpha = 3 //Kademlia并发因子 51 bucketSize = 16 //卡德米利亚水桶尺寸 52 maxReplacements = 10 //每个桶更换清单的尺寸 53 54 //我们把桶放在距离的1/15以上,因为 55 //我们不太可能遇到更近的节点。 56 hashBits = len(common.Hash{}) * 8 57 nBuckets = hashBits / 15 //桶数 58 bucketMinDistance = hashBits - nBuckets //最近桶的对数距离 59 60 //IP地址限制。 61 bucketIPLimit, bucketSubnet = 2, 24 //最多2个地址来自同一个/24 62 tableIPLimit, tableSubnet = 10, 24 63 64 maxFindnodeFailures = 5 //将删除超过此限制的节点 65 refreshInterval = 30 * time.Minute 66 revalidateInterval = 10 * time.Second 67 copyNodesInterval = 30 * time.Second 68 seedMinTableTime = 5 * time.Minute 69 seedCount = 30 70 seedMaxAge = 5 * 24 * time.Hour 71 ) 72 73 type Table struct { 74 mutex sync.Mutex //保护存储桶、存储桶内容、托儿所、兰特 75 buckets [nBuckets]*bucket //已知节点的距离索引 76 nursery []*Node //引导节点 77 rand *mrand.Rand //随机性来源,定期重新播种 78 ips netutil.DistinctNetSet 79 80 db *nodeDB //已知节点数据库 81 refreshReq chan chan struct{} 82 initDone chan struct{} 83 closeReq chan struct{} 84 closed chan struct{} 85 86 nodeAddedHook func(*Node) //用于测试 87 88 net transport 89 self *Node //本地节点的元数据 90 } 91 92 //传输由UDP传输实现。 93 //它是一个接口,因此我们可以在不打开大量UDP的情况下进行测试 94 //不生成私钥的套接字。 95 type transport interface { 96 ping(NodeID, *net.UDPAddr) error 97 findnode(toid NodeID, addr *net.UDPAddr, target NodeID) ([]*Node, error) 98 close() 99 } 100 101 //bucket包含按其上一个活动排序的节点。条目 102 //最近激活的元素是条目中的第一个元素。 103 type bucket struct { 104 entries []*Node //实时条目,按上次联系时间排序 105 replacements []*Node //如果重新验证失败,则使用最近看到的节点 106 ips netutil.DistinctNetSet 107 } 108 109 func newTable(t transport, ourID NodeID, ourAddr *net.UDPAddr, nodeDBPath string, bootnodes []*Node) (*Table, error) { 110 //如果没有提供节点数据库,请使用内存中的数据库 111 db, err := newNodeDB(nodeDBPath, nodeDBVersion, ourID) 112 if err != nil { 113 return nil, err 114 } 115 tab := &Table{ 116 net: t, 117 db: db, 118 self: NewNode(ourID, ourAddr.IP, uint16(ourAddr.Port), uint16(ourAddr.Port)), 119 refreshReq: make(chan chan struct{}), 120 initDone: make(chan struct{}), 121 closeReq: make(chan struct{}), 122 closed: make(chan struct{}), 123 rand: mrand.New(mrand.NewSource(0)), 124 ips: netutil.DistinctNetSet{Subnet: tableSubnet, Limit: tableIPLimit}, 125 } 126 if err := tab.setFallbackNodes(bootnodes); err != nil { 127 return nil, err 128 } 129 for i := range tab.buckets { 130 tab.buckets[i] = &bucket{ 131 ips: netutil.DistinctNetSet{Subnet: bucketSubnet, Limit: bucketIPLimit}, 132 } 133 } 134 tab.seedRand() 135 tab.loadSeedNodes() 136 //加载种子后启动后台过期goroutine,以便搜索 137 //种子节点还考虑将由 138 //到期。 139 tab.db.ensureExpirer() 140 go tab.loop() 141 return tab, nil 142 } 143 144 func (tab *Table) seedRand() { 145 var b [8]byte 146 crand.Read(b[:]) 147 148 tab.mutex.Lock() 149 tab.rand.Seed(int64(binary.BigEndian.Uint64(b[:]))) 150 tab.mutex.Unlock() 151 } 152 153 //self返回本地节点。 154 //调用方不应修改返回的节点。 155 func (tab *Table) Self() *Node { 156 return tab.self 157 } 158 159 //readrandomnodes用来自 160 //表。它不会多次写入同一节点。节点 161 //切片是副本,可以由调用方修改。 162 func (tab *Table) ReadRandomNodes(buf []*Node) (n int) { 163 if !tab.isInitDone() { 164 return 0 165 } 166 tab.mutex.Lock() 167 defer tab.mutex.Unlock() 168 169 //找到所有非空桶,并从中获取新的部分。 170 var buckets [][]*Node 171 for _, b := range &tab.buckets { 172 if len(b.entries) > 0 { 173 buckets = append(buckets, b.entries[:]) 174 } 175 } 176 if len(buckets) == 0 { 177 return 0 178 } 179 //洗牌。 180 for i := len(buckets) - 1; i > 0; i-- { 181 j := tab.rand.Intn(len(buckets)) 182 buckets[i], buckets[j] = buckets[j], buckets[i] 183 } 184 //将每个桶的头部移入buf,移除变空的桶。 185 var i, j int 186 for ; i < len(buf); i, j = i+1, (j+1)%len(buckets) { 187 b := buckets[j] 188 buf[i] = &(*b[0]) 189 buckets[j] = b[1:] 190 if len(b) == 1 { 191 buckets = append(buckets[:j], buckets[j+1:]...) 192 } 193 if len(buckets) == 0 { 194 break 195 } 196 } 197 return i + 1 198 } 199 200 //close终止网络侦听器并刷新节点数据库。 201 func (tab *Table) Close() { 202 select { 203 case <-tab.closed: 204 //已经关闭。 205 case tab.closeReq <- struct{}{}: 206 <-tab.closed //等待RefreshLoop结束。 207 } 208 } 209 210 //setFallbackNodes设置初始接触点。这些节点 211 //如果表为空,则用于连接到网络 212 //数据库中没有已知节点。 213 func (tab *Table) setFallbackNodes(nodes []*Node) error { 214 for _, n := range nodes { 215 if err := n.validateComplete(); err != nil { 216 return fmt.Errorf("bad bootstrap/fallback node %q (%v)", n, err) 217 } 218 } 219 tab.nursery = make([]*Node, 0, len(nodes)) 220 for _, n := range nodes { 221 cpy := *n 222 //重新计算cpy.sha,因为节点可能没有 223 //由newnode或parsenode创建。 224 cpy.sha = crypto.Keccak256Hash(n.ID[:]) 225 tab.nursery = append(tab.nursery, &cpy) 226 } 227 return nil 228 } 229 230 //IsInitDone返回表的初始种子设定过程是否已完成。 231 func (tab *Table) isInitDone() bool { 232 select { 233 case <-tab.initDone: 234 return true 235 default: 236 return false 237 } 238 } 239 240 //解析搜索具有给定ID的特定节点。 241 //如果找不到节点,则返回nil。 242 func (tab *Table) Resolve(targetID NodeID) *Node { 243 //如果节点存在于本地表中,则否 244 //需要网络交互。 245 hash := crypto.Keccak256Hash(targetID[:]) 246 tab.mutex.Lock() 247 cl := tab.closest(hash, 1) 248 tab.mutex.Unlock() 249 if len(cl.entries) > 0 && cl.entries[0].ID == targetID { 250 return cl.entries[0] 251 } 252 //否则,请执行网络查找。 253 result := tab.Lookup(targetID) 254 for _, n := range result { 255 if n.ID == targetID { 256 return n 257 } 258 } 259 return nil 260 } 261 262 //查找对关闭的节点执行网络搜索 263 //目标。它通过查询接近目标 264 //在每次迭代中离它更近的节点。 265 //给定目标不需要是实际节点 266 //标识符。 267 func (tab *Table) Lookup(targetID NodeID) []*Node { 268 return tab.lookup(targetID, true) 269 } 270 271 func (tab *Table) lookup(targetID NodeID, refreshIfEmpty bool) []*Node { 272 var ( 273 target = crypto.Keccak256Hash(targetID[:]) 274 asked = make(map[NodeID]bool) 275 seen = make(map[NodeID]bool) 276 reply = make(chan []*Node, alpha) 277 pendingQueries = 0 278 result *nodesByDistance 279 ) 280 //如果我们撞到自己,不要再问了。 281 //在实践中不太可能经常发生。 282 asked[tab.self.ID] = true 283 284 for { 285 tab.mutex.Lock() 286 //生成初始结果集 287 result = tab.closest(target, bucketSize) 288 tab.mutex.Unlock() 289 if len(result.entries) > 0 || !refreshIfEmpty { 290 break 291 } 292 //结果集为空,删除了所有节点,刷新。 293 //我们实际上在这里等待刷新完成。非常 294 //第一个查询将命中此情况并运行引导 295 //逻辑。 296 <-tab.refresh() 297 refreshIfEmpty = false 298 } 299 300 for { 301 //询问我们尚未询问的alpha最近的节点 302 for i := 0; i < len(result.entries) && pendingQueries < alpha; i++ { 303 n := result.entries[i] 304 if !asked[n.ID] { 305 asked[n.ID] = true 306 pendingQueries++ 307 go tab.findnode(n, targetID, reply) 308 } 309 } 310 if pendingQueries == 0 { 311 //我们要求所有最近的节点停止搜索 312 break 313 } 314 //等待下一个答复 315 for _, n := range <-reply { 316 if n != nil && !seen[n.ID] { 317 seen[n.ID] = true 318 result.push(n, bucketSize) 319 } 320 } 321 pendingQueries-- 322 } 323 return result.entries 324 } 325 326 func (tab *Table) findnode(n *Node, targetID NodeID, reply chan<- []*Node) { 327 fails := tab.db.findFails(n.ID) 328 r, err := tab.net.findnode(n.ID, n.addr(), targetID) 329 if err != nil || len(r) == 0 { 330 fails++ 331 tab.db.updateFindFails(n.ID, fails) 332 log.Trace("Findnode failed", "id", n.ID, "failcount", fails, "err", err) 333 if fails >= maxFindnodeFailures { 334 log.Trace("Too many findnode failures, dropping", "id", n.ID, "failcount", fails) 335 tab.delete(n) 336 } 337 } else if fails > 0 { 338 tab.db.updateFindFails(n.ID, fails-1) 339 } 340 341 //抓取尽可能多的节点。他们中的一些人可能已经不在了,但我们会 342 //在重新验证期间,只需再次移除这些。 343 for _, n := range r { 344 tab.add(n) 345 } 346 reply <- r 347 } 348 349 func (tab *Table) refresh() <-chan struct{} { 350 done := make(chan struct{}) 351 select { 352 case tab.refreshReq <- done: 353 case <-tab.closed: 354 close(done) 355 } 356 return done 357 } 358 359 //循环计划刷新、重新验证运行并协调关闭。 360 func (tab *Table) loop() { 361 var ( 362 revalidate = time.NewTimer(tab.nextRevalidateTime()) 363 refresh = time.NewTicker(refreshInterval) 364 copyNodes = time.NewTicker(copyNodesInterval) 365 revalidateDone = make(chan struct{}) 366 refreshDone = make(chan struct{}) //Dorefresh报告完成 367 waiting = []chan struct{}{tab.initDone} //在DoRefresh运行时保留等待的呼叫者 368 ) 369 defer refresh.Stop() 370 defer revalidate.Stop() 371 defer copyNodes.Stop() 372 373 //开始初始刷新。 374 go tab.doRefresh(refreshDone) 375 376 loop: 377 for { 378 select { 379 case <-refresh.C: 380 tab.seedRand() 381 if refreshDone == nil { 382 refreshDone = make(chan struct{}) 383 go tab.doRefresh(refreshDone) 384 } 385 case req := <-tab.refreshReq: 386 waiting = append(waiting, req) 387 if refreshDone == nil { 388 refreshDone = make(chan struct{}) 389 go tab.doRefresh(refreshDone) 390 } 391 case <-refreshDone: 392 for _, ch := range waiting { 393 close(ch) 394 } 395 waiting, refreshDone = nil, nil 396 case <-revalidate.C: 397 go tab.doRevalidate(revalidateDone) 398 case <-revalidateDone: 399 revalidate.Reset(tab.nextRevalidateTime()) 400 case <-copyNodes.C: 401 go tab.copyLiveNodes() 402 case <-tab.closeReq: 403 break loop 404 } 405 } 406 407 if tab.net != nil { 408 tab.net.close() 409 } 410 if refreshDone != nil { 411 <-refreshDone 412 } 413 for _, ch := range waiting { 414 close(ch) 415 } 416 tab.db.close() 417 close(tab.closed) 418 } 419 420 //DoRefresh执行查找随机目标以保留存储桶 421 //满的。如果表为空,则插入种子节点(初始 422 //引导或丢弃错误对等)。 423 func (tab *Table) doRefresh(done chan struct{}) { 424 defer close(done) 425 426 //从数据库加载节点并插入 427 //他们。这将产生一些以前看到的节点, 428 //(希望)还活着。 429 tab.loadSeedNodes() 430 431 //运行自我查找以发现新的邻居节点。 432 tab.lookup(tab.self.ID, false) 433 434 //kademlia文件指定bucket刷新应该 435 //在最近使用最少的存储桶中执行查找。我们不能 436 //坚持这一点,因为findnode目标是512位值 437 //(不是哈希大小)并且不容易生成 438 //属于选定的桶中的sha3 preimage。 439 //我们用随机目标执行一些查找。 440 for i := 0; i < 3; i++ { 441 var target NodeID 442 crand.Read(target[:]) 443 tab.lookup(target, false) 444 } 445 } 446 447 func (tab *Table) loadSeedNodes() { 448 seeds := tab.db.querySeeds(seedCount, seedMaxAge) 449 seeds = append(seeds, tab.nursery...) 450 for i := range seeds { 451 seed := seeds[i] 452 age := log.Lazy{Fn: func() interface{} { return time.Since(tab.db.lastPongReceived(seed.ID)) }} 453 log.Debug("Found seed node in database", "id", seed.ID, "addr", seed.addr(), "age", age) 454 tab.add(seed) 455 } 456 } 457 458 //Dorevalidate检查随机存储桶中的最后一个节点是否仍然活动 459 //如果没有,则替换或删除节点。 460 func (tab *Table) doRevalidate(done chan<- struct{}) { 461 defer func() { done <- struct{}{} }() 462 463 last, bi := tab.nodeToRevalidate() 464 if last == nil { 465 //找不到非空存储桶。 466 return 467 } 468 469 //ping所选节点并等待pong。 470 err := tab.net.ping(last.ID, last.addr()) 471 472 tab.mutex.Lock() 473 defer tab.mutex.Unlock() 474 b := tab.buckets[bi] 475 if err == nil { 476 //节点响应,将其移到前面。 477 log.Trace("Revalidated node", "b", bi, "id", last.ID) 478 b.bump(last) 479 return 480 } 481 //未收到回复,请选择替换项或删除节点(如果没有) 482 //任何替代品。 483 if r := tab.replace(b, last); r != nil { 484 log.Trace("Replaced dead node", "b", bi, "id", last.ID, "ip", last.IP, "r", r.ID, "rip", r.IP) 485 } else { 486 log.Trace("Removed dead node", "b", bi, "id", last.ID, "ip", last.IP) 487 } 488 } 489 490 //nodetorefalidate返回随机非空bucket中的最后一个节点。 491 func (tab *Table) nodeToRevalidate() (n *Node, bi int) { 492 tab.mutex.Lock() 493 defer tab.mutex.Unlock() 494 495 for _, bi = range tab.rand.Perm(len(tab.buckets)) { 496 b := tab.buckets[bi] 497 if len(b.entries) > 0 { 498 last := b.entries[len(b.entries)-1] 499 return last, bi 500 } 501 } 502 return nil, 0 503 } 504 505 func (tab *Table) nextRevalidateTime() time.Duration { 506 tab.mutex.Lock() 507 defer tab.mutex.Unlock() 508 509 return time.Duration(tab.rand.Int63n(int64(revalidateInterval))) 510 } 511 512 //CopyLiveNodes将表中的节点添加到数据库中(如果它们在表中)。 513 //比Mintable时间长。 514 func (tab *Table) copyLiveNodes() { 515 tab.mutex.Lock() 516 defer tab.mutex.Unlock() 517 518 now := time.Now() 519 for _, b := range &tab.buckets { 520 for _, n := range b.entries { 521 if now.Sub(n.addedAt) >= seedMinTableTime { 522 tab.db.updateNode(n) 523 } 524 } 525 } 526 } 527 528 //最近返回表中最接近 529 //给定的ID。调用方必须保持tab.mutex。 530 func (tab *Table) closest(target common.Hash, nresults int) *nodesByDistance { 531 //这是一种非常浪费的查找最近节点的方法,但是 532 //显然是正确的。我相信以树为基础的桶可以 533 //这更容易有效地实施。 534 close := &nodesByDistance{target: target} 535 for _, b := range &tab.buckets { 536 for _, n := range b.entries { 537 close.push(n, nresults) 538 } 539 } 540 return close 541 } 542 543 func (tab *Table) len() (n int) { 544 for _, b := range &tab.buckets { 545 n += len(b.entries) 546 } 547 return n 548 } 549 550 //bucket返回给定节点id散列的bucket。 551 func (tab *Table) bucket(sha common.Hash) *bucket { 552 d := logdist(tab.self.sha, sha) 553 if d <= bucketMinDistance { 554 return tab.buckets[0] 555 } 556 return tab.buckets[d-bucketMinDistance-1] 557 } 558 559 //添加将给定节点添加到其相应存储桶的尝试。如果桶有空间 560 //可用,添加节点立即成功。否则,如果 561 //bucket中最近活动的节点不响应ping数据包。 562 // 563 //调用方不能持有tab.mutex。 564 func (tab *Table) add(n *Node) { 565 tab.mutex.Lock() 566 defer tab.mutex.Unlock() 567 568 b := tab.bucket(n.sha) 569 if !tab.bumpOrAdd(b, n) { 570 //节点不在表中。将其添加到替换列表中。 571 tab.addReplacement(b, n) 572 } 573 } 574 575 //addthroughping将给定节点添加到表中。与平原相比 576 //“添加”有一个附加的安全措施:如果表仍然存在 577 //未添加初始化节点。这可以防止攻击 578 //只需重复发送ping就可以填写表格。 579 // 580 //调用方不能持有tab.mutex。 581 func (tab *Table) addThroughPing(n *Node) { 582 if !tab.isInitDone() { 583 return 584 } 585 tab.add(n) 586 } 587 588 //stufacture将表中的节点添加到相应bucket的末尾 589 //如果桶没满。调用方不能持有tab.mutex。 590 func (tab *Table) stuff(nodes []*Node) { 591 tab.mutex.Lock() 592 defer tab.mutex.Unlock() 593 594 for _, n := range nodes { 595 if n.ID == tab.self.ID { 596 continue //不要增加自我 597 } 598 b := tab.bucket(n.sha) 599 if len(b.entries) < bucketSize { 600 tab.bumpOrAdd(b, n) 601 } 602 } 603 } 604 605 //删除从节点表中删除一个条目。用于疏散死节点。 606 func (tab *Table) delete(node *Node) { 607 tab.mutex.Lock() 608 defer tab.mutex.Unlock() 609 610 tab.deleteInBucket(tab.bucket(node.sha), node) 611 } 612 613 func (tab *Table) addIP(b *bucket, ip net.IP) bool { 614 if netutil.IsLAN(ip) { 615 return true 616 } 617 if !tab.ips.Add(ip) { 618 log.Debug("IP exceeds table limit", "ip", ip) 619 return false 620 } 621 if !b.ips.Add(ip) { 622 log.Debug("IP exceeds bucket limit", "ip", ip) 623 tab.ips.Remove(ip) 624 return false 625 } 626 return true 627 } 628 629 func (tab *Table) removeIP(b *bucket, ip net.IP) { 630 if netutil.IsLAN(ip) { 631 return 632 } 633 tab.ips.Remove(ip) 634 b.ips.Remove(ip) 635 } 636 637 func (tab *Table) addReplacement(b *bucket, n *Node) { 638 for _, e := range b.replacements { 639 if e.ID == n.ID { 640 return //已列入清单 641 } 642 } 643 if !tab.addIP(b, n.IP) { 644 return 645 } 646 var removed *Node 647 b.replacements, removed = pushNode(b.replacements, n, maxReplacements) 648 if removed != nil { 649 tab.removeIP(b, removed.IP) 650 } 651 } 652 653 //replace从替换列表中删除n,如果“last”是 654 //桶中的最后一个条目。如果“last”不是最后一个条目,则它或已被替换 655 //和别人在一起或者变得活跃起来。 656 func (tab *Table) replace(b *bucket, last *Node) *Node { 657 if len(b.entries) == 0 || b.entries[len(b.entries)-1].ID != last.ID { 658 //条目已移动,不要替换它。 659 return nil 660 } 661 //还是最后一个条目。 662 if len(b.replacements) == 0 { 663 tab.deleteInBucket(b, last) 664 return nil 665 } 666 r := b.replacements[tab.rand.Intn(len(b.replacements))] 667 b.replacements = deleteNode(b.replacements, r) 668 b.entries[len(b.entries)-1] = r 669 tab.removeIP(b, last.IP) 670 return r 671 } 672 673 //bump将给定节点移动到bucket条目列表的前面 674 //如果它包含在那个列表中。 675 func (b *bucket) bump(n *Node) bool { 676 for i := range b.entries { 677 if b.entries[i].ID == n.ID { 678 //把它移到前面 679 copy(b.entries[1:], b.entries[:i]) 680 b.entries[0] = n 681 return true 682 } 683 } 684 return false 685 } 686 687 //bumporadd将n移动到bucket条目列表的前面,或者如果该列表不在,则将其添加。 688 //满的。如果n在桶中,返回值为真。 689 func (tab *Table) bumpOrAdd(b *bucket, n *Node) bool { 690 if b.bump(n) { 691 return true 692 } 693 if len(b.entries) >= bucketSize || !tab.addIP(b, n.IP) { 694 return false 695 } 696 b.entries, _ = pushNode(b.entries, n, bucketSize) 697 b.replacements = deleteNode(b.replacements, n) 698 n.addedAt = time.Now() 699 if tab.nodeAddedHook != nil { 700 tab.nodeAddedHook(n) 701 } 702 return true 703 } 704 705 func (tab *Table) deleteInBucket(b *bucket, n *Node) { 706 b.entries = deleteNode(b.entries, n) 707 tab.removeIP(b, n.IP) 708 } 709 710 //pushnode将n添加到列表的前面,最多保留max项。 711 func pushNode(list []*Node, n *Node, max int) ([]*Node, *Node) { 712 if len(list) < max { 713 list = append(list, nil) 714 } 715 removed := list[len(list)-1] 716 copy(list[1:], list) 717 list[0] = n 718 return list, removed 719 } 720 721 //删除节点从列表中删除n。 722 func deleteNode(list []*Node, n *Node) []*Node { 723 for i := range list { 724 if list[i].ID == n.ID { 725 return append(list[:i], list[i+1:]...) 726 } 727 } 728 return list 729 } 730 731 //nodesByDistance是节点列表,按 732 //距离目标。 733 type nodesByDistance struct { 734 entries []*Node 735 target common.Hash 736 } 737 738 //push将给定节点添加到列表中,使总大小保持在maxelems以下。 739 func (h *nodesByDistance) push(n *Node, maxElems int) { 740 ix := sort.Search(len(h.entries), func(i int) bool { 741 return distcmp(h.target, h.entries[i].sha, n.sha) > 0 742 }) 743 if len(h.entries) < maxElems { 744 h.entries = append(h.entries, n) 745 } 746 if ix == len(h.entries) { 747 //比我们现有的所有节点都要远。 748 //如果有空间,那么节点现在是最后一个元素。 749 } else { 750 //向下滑动现有条目以腾出空间 751 //这将覆盖我们刚刚附加的条目。 752 copy(h.entries[ix+1:], h.entries[ix:]) 753 h.entries[ix] = n 754 } 755 }