github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/les/fetcher.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:38</date> 10 //</624450093579243520> 11 12 13 //包les实现轻以太坊子协议。 14 package les 15 16 import ( 17 "math/big" 18 "sync" 19 "time" 20 21 "github.com/ethereum/go-ethereum/common" 22 "github.com/ethereum/go-ethereum/common/mclock" 23 "github.com/ethereum/go-ethereum/consensus" 24 "github.com/ethereum/go-ethereum/core/rawdb" 25 "github.com/ethereum/go-ethereum/core/types" 26 "github.com/ethereum/go-ethereum/light" 27 "github.com/ethereum/go-ethereum/log" 28 ) 29 30 const ( 31 blockDelayTimeout = time.Second * 10 //对等机宣布已被其他人确认的头的超时 32 maxNodeCount = 20 //为每个对等机记住的最大fetchertreenode条目数 33 serverStateAvailable = 100 //假定状态可用性的最近块数 34 ) 35 36 //LightFetcher实现对新公布的头的检索。它还为 37 //ODR系统确保我们只向已经处理过的对等方请求与某个块相关的数据 38 //并宣布封锁。 39 type lightFetcher struct { 40 pm *ProtocolManager 41 odr *LesOdr 42 chain *light.LightChain 43 44 lock sync.Mutex //锁保护对提取程序内部状态变量(发送的请求除外)的访问 45 maxConfirmedTd *big.Int 46 peers map[*peer]*fetcherPeerInfo 47 lastUpdateStats *updateStatsEntry 48 syncing bool 49 syncDone chan *peer 50 51 reqMu sync.RWMutex //reqmu保护对发送的头提取请求的访问 52 requested map[uint64]fetchRequest 53 deliverChn chan fetchResponse 54 timeoutChn chan uint64 55 requestChn chan bool //如果从外部启动,则为真 56 } 57 58 //FETCHEPERIVENT保存关于每个活动对等点的特定的信息 59 type fetcherPeerInfo struct { 60 root, lastAnnounced *fetcherTreeNode 61 nodeCnt int 62 confirmedTd *big.Int 63 bestConfirmed *fetcherTreeNode 64 nodeByHash map[common.Hash]*fetcherTreeNode 65 firstUpdateStats *updateStatsEntry 66 } 67 68 //fetchergreenode是树的一个节点,最近保存了关于块的信息。 69 //announced and confirmed by a certain peer. Each new announce message from a peer 70 //将节点添加到树中,基于先前公布的头部和重新排列深度。 71 //树节点有三种可能的状态: 72 //-已宣布:尚未下载(已知),但我们知道它的头、编号和td 73 //-中间:不知道,散列和td为空,当已知时填写。 74 //-已知:由该对等方宣布并下载(从任何对等方)。 75 //这种结构可以始终知道哪个对等机具有某个块, 76 //这对于为ODR请求以及 77 //将新的头封为圣徒。它也有助于始终下载所需的最少数量 78 //具有单个请求的头的数量。 79 type fetcherTreeNode struct { 80 hash common.Hash 81 number uint64 82 td *big.Int 83 known, requested bool 84 parent *fetcherTreeNode 85 children []*fetcherTreeNode 86 } 87 88 //fetchRequest表示头下载请求 89 type fetchRequest struct { 90 hash common.Hash 91 amount uint64 92 peer *peer 93 sent mclock.AbsTime 94 timeout bool 95 } 96 97 //fetchResponse表示头下载响应 98 type fetchResponse struct { 99 reqID uint64 100 headers []*types.Header 101 peer *peer 102 } 103 104 //new light fetcher创建新的light fetcher 105 func newLightFetcher(pm *ProtocolManager) *lightFetcher { 106 f := &lightFetcher{ 107 pm: pm, 108 chain: pm.blockchain.(*light.LightChain), 109 odr: pm.odr, 110 peers: make(map[*peer]*fetcherPeerInfo), 111 deliverChn: make(chan fetchResponse, 100), 112 requested: make(map[uint64]fetchRequest), 113 timeoutChn: make(chan uint64), 114 requestChn: make(chan bool, 100), 115 syncDone: make(chan *peer), 116 maxConfirmedTd: big.NewInt(0), 117 } 118 pm.peers.notify(f) 119 120 f.pm.wg.Add(1) 121 go f.syncLoop() 122 return f 123 } 124 125 //同步循环是取光器的主事件循环 126 func (f *lightFetcher) syncLoop() { 127 requesting := false 128 defer f.pm.wg.Done() 129 for { 130 select { 131 case <-f.pm.quitSync: 132 return 133 //当接收到新的公告时,请求循环将一直运行,直到 134 //无需或可能进一步请求 135 case newAnnounce := <-f.requestChn: 136 f.lock.Lock() 137 s := requesting 138 requesting = false 139 var ( 140 rq *distReq 141 reqID uint64 142 syncing bool 143 ) 144 if !f.syncing && !(newAnnounce && s) { 145 rq, reqID, syncing = f.nextRequest() 146 } 147 f.lock.Unlock() 148 149 if rq != nil { 150 requesting = true 151 if _, ok := <-f.pm.reqDist.queue(rq); ok { 152 if syncing { 153 f.lock.Lock() 154 f.syncing = true 155 f.lock.Unlock() 156 } else { 157 go func() { 158 time.Sleep(softRequestTimeout) 159 f.reqMu.Lock() 160 req, ok := f.requested[reqID] 161 if ok { 162 req.timeout = true 163 f.requested[reqID] = req 164 } 165 f.reqMu.Unlock() 166 //尽可能继续启动新请求 167 f.requestChn <- false 168 }() 169 } 170 } else { 171 f.requestChn <- false 172 } 173 } 174 case reqID := <-f.timeoutChn: 175 f.reqMu.Lock() 176 req, ok := f.requested[reqID] 177 if ok { 178 delete(f.requested, reqID) 179 } 180 f.reqMu.Unlock() 181 if ok { 182 f.pm.serverPool.adjustResponseTime(req.peer.poolEntry, time.Duration(mclock.Now()-req.sent), true) 183 req.peer.Log().Debug("Fetching data timed out hard") 184 go f.pm.removePeer(req.peer.id) 185 } 186 case resp := <-f.deliverChn: 187 f.reqMu.Lock() 188 req, ok := f.requested[resp.reqID] 189 if ok && req.peer != resp.peer { 190 ok = false 191 } 192 if ok { 193 delete(f.requested, resp.reqID) 194 } 195 f.reqMu.Unlock() 196 if ok { 197 f.pm.serverPool.adjustResponseTime(req.peer.poolEntry, time.Duration(mclock.Now()-req.sent), req.timeout) 198 } 199 f.lock.Lock() 200 if !ok || !(f.syncing || f.processResponse(req, resp)) { 201 resp.peer.Log().Debug("Failed processing response") 202 go f.pm.removePeer(resp.peer.id) 203 } 204 f.lock.Unlock() 205 case p := <-f.syncDone: 206 f.lock.Lock() 207 p.Log().Debug("Done synchronising with peer") 208 f.checkSyncedHeaders(p) 209 f.syncing = false 210 f.lock.Unlock() 211 f.requestChn <- false 212 } 213 } 214 } 215 216 //registerpeer将新的对等添加到提取程序的对等集 217 func (f *lightFetcher) registerPeer(p *peer) { 218 p.lock.Lock() 219 p.hasBlock = func(hash common.Hash, number uint64, hasState bool) bool { 220 return f.peerHasBlock(p, hash, number, hasState) 221 } 222 p.lock.Unlock() 223 224 f.lock.Lock() 225 defer f.lock.Unlock() 226 227 f.peers[p] = &fetcherPeerInfo{nodeByHash: make(map[common.Hash]*fetcherTreeNode)} 228 } 229 230 //UnregisterPeer从提取程序的对等集中删除一个新对等。 231 func (f *lightFetcher) unregisterPeer(p *peer) { 232 p.lock.Lock() 233 p.hasBlock = nil 234 p.lock.Unlock() 235 236 f.lock.Lock() 237 defer f.lock.Unlock() 238 239 //检查潜在的超时块延迟统计信息 240 f.checkUpdateStats(p, nil) 241 delete(f.peers, p) 242 } 243 244 //公告处理从对等端接收的新公告消息,添加新的 245 //节点到对等机的块树,并在必要时删除旧节点 246 func (f *lightFetcher) announce(p *peer, head *announceData) { 247 f.lock.Lock() 248 defer f.lock.Unlock() 249 p.Log().Debug("Received new announcement", "number", head.Number, "hash", head.Hash, "reorg", head.ReorgDepth) 250 251 fp := f.peers[p] 252 if fp == nil { 253 p.Log().Debug("Announcement from unknown peer") 254 return 255 } 256 257 if fp.lastAnnounced != nil && head.Td.Cmp(fp.lastAnnounced.td) <= 0 { 258 //公布的技术数据应该严格单调 259 p.Log().Debug("Received non-monotonic td", "current", head.Td, "previous", fp.lastAnnounced.td) 260 go f.pm.removePeer(p.id) 261 return 262 } 263 264 n := fp.lastAnnounced 265 for i := uint64(0); i < head.ReorgDepth; i++ { 266 if n == nil { 267 break 268 } 269 n = n.parent 270 } 271 //n现在是reorg的共同祖先,添加一个新的节点分支 272 if n != nil && (head.Number >= n.number+maxNodeCount || head.Number <= n.number) { 273 //如果公布的头块高度低于或等于N或太远无法添加 274 //中间节点然后放弃先前的通知信息并触发重新同步 275 n = nil 276 fp.nodeCnt = 0 277 fp.nodeByHash = make(map[common.Hash]*fetcherTreeNode) 278 } 279 if n != nil { 280 //检查节点计数是否太高,无法添加新节点,必要时丢弃最旧的节点 281 locked := false 282 for uint64(fp.nodeCnt)+head.Number-n.number > maxNodeCount && fp.root != nil { 283 if !locked { 284 f.chain.LockChain() 285 defer f.chain.UnlockChain() 286 locked = true 287 } 288 //如果根的一个子级是规范的,请保留它,删除其他分支和根本身。 289 var newRoot *fetcherTreeNode 290 for i, nn := range fp.root.children { 291 if rawdb.ReadCanonicalHash(f.pm.chainDb, nn.number) == nn.hash { 292 fp.root.children = append(fp.root.children[:i], fp.root.children[i+1:]...) 293 nn.parent = nil 294 newRoot = nn 295 break 296 } 297 } 298 fp.deleteNode(fp.root) 299 if n == fp.root { 300 n = newRoot 301 } 302 fp.root = newRoot 303 if newRoot == nil || !f.checkKnownNode(p, newRoot) { 304 fp.bestConfirmed = nil 305 fp.confirmedTd = nil 306 } 307 308 if n == nil { 309 break 310 } 311 } 312 if n != nil { 313 for n.number < head.Number { 314 nn := &fetcherTreeNode{number: n.number + 1, parent: n} 315 n.children = append(n.children, nn) 316 n = nn 317 fp.nodeCnt++ 318 } 319 n.hash = head.Hash 320 n.td = head.Td 321 fp.nodeByHash[n.hash] = n 322 } 323 } 324 if n == nil { 325 //找不到REORG公共祖先或必须删除整个树,需要新的根目录和重新同步 326 if fp.root != nil { 327 fp.deleteNode(fp.root) 328 } 329 n = &fetcherTreeNode{hash: head.Hash, number: head.Number, td: head.Td} 330 fp.root = n 331 fp.nodeCnt++ 332 fp.nodeByHash[n.hash] = n 333 fp.bestConfirmed = nil 334 fp.confirmedTd = nil 335 } 336 337 f.checkKnownNode(p, n) 338 p.lock.Lock() 339 p.headInfo = head 340 fp.lastAnnounced = n 341 p.lock.Unlock() 342 f.checkUpdateStats(p, nil) 343 f.requestChn <- true 344 } 345 346 //如果我们可以假设对等方知道给定的块,那么peerhassblock返回true。 347 //根据它的公告 348 func (f *lightFetcher) peerHasBlock(p *peer, hash common.Hash, number uint64, hasState bool) bool { 349 f.lock.Lock() 350 defer f.lock.Unlock() 351 352 fp := f.peers[p] 353 if fp == nil || fp.root == nil { 354 return false 355 } 356 357 if hasState { 358 if fp.lastAnnounced == nil || fp.lastAnnounced.number > number+serverStateAvailable { 359 return false 360 } 361 } 362 363 if f.syncing { 364 //同步时始终返回true 365 //误报是可以接受的,一个更复杂的条件可以稍后实现。 366 return true 367 } 368 369 if number >= fp.root.number { 370 //如果知道它,它应该在对等机的块树中,这已经足够新了。 371 return fp.nodeByHash[hash] != nil 372 } 373 f.chain.LockChain() 374 defer f.chain.UnlockChain() 375 //如果它比对等的块树根还老,但它在同一个规范链中 376 //作为根,我们仍然可以确定同伴知道它。 377 // 378 //同步时,只要检查它是否是已知链的一部分,就没有比我们更好的了 379 //可以,因为我们还不知道最新的块哈希 380 return rawdb.ReadCanonicalHash(f.pm.chainDb, fp.root.number) == fp.root.hash && rawdb.ReadCanonicalHash(f.pm.chainDb, number) == hash 381 } 382 383 //RequestAmount从开始计算要下载的头的数量 384 //从某个头向后 385 func (f *lightFetcher) requestAmount(p *peer, n *fetcherTreeNode) uint64 { 386 amount := uint64(0) 387 nn := n 388 for nn != nil && !f.checkKnownNode(p, nn) { 389 nn = nn.parent 390 amount++ 391 } 392 if nn == nil { 393 amount = n.number 394 } 395 return amount 396 } 397 398 //REQUESTEDID指示获取程序是否已请求某个REQID 399 func (f *lightFetcher) requestedID(reqID uint64) bool { 400 f.reqMu.RLock() 401 _, ok := f.requested[reqID] 402 f.reqMu.RUnlock() 403 return ok 404 } 405 406 //nextrequest选择要请求的对等端和公告头,下一个,amount 407 //从头部开始向后下载也会返回 408 func (f *lightFetcher) nextRequest() (*distReq, uint64, bool) { 409 var ( 410 bestHash common.Hash 411 bestAmount uint64 412 ) 413 bestTd := f.maxConfirmedTd 414 bestSyncing := false 415 416 for p, fp := range f.peers { 417 for hash, n := range fp.nodeByHash { 418 if !f.checkKnownNode(p, n) && !n.requested && (bestTd == nil || n.td.Cmp(bestTd) >= 0) { 419 amount := f.requestAmount(p, n) 420 if bestTd == nil || n.td.Cmp(bestTd) > 0 || amount < bestAmount { 421 bestHash = hash 422 bestAmount = amount 423 bestTd = n.td 424 bestSyncing = fp.bestConfirmed == nil || fp.root == nil || !f.checkKnownNode(p, fp.root) 425 } 426 } 427 } 428 } 429 if bestTd == f.maxConfirmedTd { 430 return nil, 0, false 431 } 432 433 var rq *distReq 434 reqID := genReqID() 435 if bestSyncing { 436 rq = &distReq{ 437 getCost: func(dp distPeer) uint64 { 438 return 0 439 }, 440 canSend: func(dp distPeer) bool { 441 p := dp.(*peer) 442 f.lock.Lock() 443 defer f.lock.Unlock() 444 445 fp := f.peers[p] 446 return fp != nil && fp.nodeByHash[bestHash] != nil 447 }, 448 request: func(dp distPeer) func() { 449 go func() { 450 p := dp.(*peer) 451 p.Log().Debug("Synchronisation started") 452 f.pm.synchronise(p) 453 f.syncDone <- p 454 }() 455 return nil 456 }, 457 } 458 } else { 459 rq = &distReq{ 460 getCost: func(dp distPeer) uint64 { 461 p := dp.(*peer) 462 return p.GetRequestCost(GetBlockHeadersMsg, int(bestAmount)) 463 }, 464 canSend: func(dp distPeer) bool { 465 p := dp.(*peer) 466 f.lock.Lock() 467 defer f.lock.Unlock() 468 469 fp := f.peers[p] 470 if fp == nil { 471 return false 472 } 473 n := fp.nodeByHash[bestHash] 474 return n != nil && !n.requested 475 }, 476 request: func(dp distPeer) func() { 477 p := dp.(*peer) 478 f.lock.Lock() 479 fp := f.peers[p] 480 if fp != nil { 481 n := fp.nodeByHash[bestHash] 482 if n != nil { 483 n.requested = true 484 } 485 } 486 f.lock.Unlock() 487 488 cost := p.GetRequestCost(GetBlockHeadersMsg, int(bestAmount)) 489 p.fcServer.QueueRequest(reqID, cost) 490 f.reqMu.Lock() 491 f.requested[reqID] = fetchRequest{hash: bestHash, amount: bestAmount, peer: p, sent: mclock.Now()} 492 f.reqMu.Unlock() 493 go func() { 494 time.Sleep(hardRequestTimeout) 495 f.timeoutChn <- reqID 496 }() 497 return func() { p.RequestHeadersByHash(reqID, cost, bestHash, int(bestAmount), 0, true) } 498 }, 499 } 500 } 501 return rq, reqID, bestSyncing 502 } 503 504 //DeliverHeaders传递要处理的头下载请求响应 505 func (f *lightFetcher) deliverHeaders(peer *peer, reqID uint64, headers []*types.Header) { 506 f.deliverChn <- fetchResponse{reqID: reqID, headers: headers, peer: peer} 507 } 508 509 //processResponse处理头下载请求响应,如果成功,则返回true 510 func (f *lightFetcher) processResponse(req fetchRequest, resp fetchResponse) bool { 511 if uint64(len(resp.headers)) != req.amount || resp.headers[0].Hash() != req.hash { 512 req.peer.Log().Debug("Response content mismatch", "requested", len(resp.headers), "reqfrom", resp.headers[0], "delivered", req.amount, "delfrom", req.hash) 513 return false 514 } 515 headers := make([]*types.Header, req.amount) 516 for i, header := range resp.headers { 517 headers[int(req.amount)-1-i] = header 518 } 519 if _, err := f.chain.InsertHeaderChain(headers, 1); err != nil { 520 if err == consensus.ErrFutureBlock { 521 return true 522 } 523 log.Debug("Failed to insert header chain", "err", err) 524 return false 525 } 526 tds := make([]*big.Int, len(headers)) 527 for i, header := range headers { 528 td := f.chain.GetTd(header.Hash(), header.Number.Uint64()) 529 if td == nil { 530 log.Debug("Total difficulty not found for header", "index", i+1, "number", header.Number, "hash", header.Hash()) 531 return false 532 } 533 tds[i] = td 534 } 535 f.newHeaders(headers, tds) 536 return true 537 } 538 539 //newheaders根据 540 //下载并验证批或头 541 func (f *lightFetcher) newHeaders(headers []*types.Header, tds []*big.Int) { 542 var maxTd *big.Int 543 for p, fp := range f.peers { 544 if !f.checkAnnouncedHeaders(fp, headers, tds) { 545 p.Log().Debug("Inconsistent announcement") 546 go f.pm.removePeer(p.id) 547 } 548 if fp.confirmedTd != nil && (maxTd == nil || maxTd.Cmp(fp.confirmedTd) > 0) { 549 maxTd = fp.confirmedTd 550 } 551 } 552 if maxTd != nil { 553 f.updateMaxConfirmedTd(maxTd) 554 } 555 } 556 557 //如果验证后需要,checkAnnouncedHeaders会更新对等方的块树 558 //一批头文件。它搜索具有 559 //matching tree node (if any), and if it has not been marked as known already, 560 //将其及其父级设置为已知(甚至那些比当前 561 //已验证)。返回值显示所有哈希、数字和TDS是否匹配 562 //正确到公布的值(否则应删除对等机)。 563 func (f *lightFetcher) checkAnnouncedHeaders(fp *fetcherPeerInfo, headers []*types.Header, tds []*big.Int) bool { 564 var ( 565 n *fetcherTreeNode 566 header *types.Header 567 td *big.Int 568 ) 569 570 for i := len(headers) - 1; ; i-- { 571 if i < 0 { 572 if n == nil { 573 //没有更多的标题,也没有要匹配的内容 574 return true 575 } 576 //最近传递的头已用完,但尚未到达此对等方已知的节点,请继续匹配 577 hash, number := header.ParentHash, header.Number.Uint64()-1 578 td = f.chain.GetTd(hash, number) 579 header = f.chain.GetHeader(hash, number) 580 if header == nil || td == nil { 581 log.Error("Missing parent of validated header", "hash", hash, "number", number) 582 return false 583 } 584 } else { 585 header = headers[i] 586 td = tds[i] 587 } 588 hash := header.Hash() 589 number := header.Number.Uint64() 590 if n == nil { 591 n = fp.nodeByHash[hash] 592 } 593 if n != nil { 594 if n.td == nil { 595 //节点未通知 596 if nn := fp.nodeByHash[hash]; nn != nil { 597 //如果已经有一个具有相同哈希的节点,请继续执行该操作并删除该节点。 598 nn.children = append(nn.children, n.children...) 599 n.children = nil 600 fp.deleteNode(n) 601 n = nn 602 } else { 603 n.hash = hash 604 n.td = td 605 fp.nodeByHash[hash] = n 606 } 607 } 608 //检查它是否与标题匹配 609 if n.hash != hash || n.number != number || n.td.Cmp(td) != 0 { 610 //对等机以前发出了无效的通知 611 return false 612 } 613 if n.known { 614 //我们到达了一个与我们的期望相符的已知节点,成功地返回 615 return true 616 } 617 n.known = true 618 if fp.confirmedTd == nil || td.Cmp(fp.confirmedTd) > 0 { 619 fp.confirmedTd = td 620 fp.bestConfirmed = n 621 } 622 n = n.parent 623 if n == nil { 624 return true 625 } 626 } 627 } 628 } 629 630 //checkSyncedHeaders通过标记在同步后更新对等方的块树 631 //下载了已知的邮件头。如果在 632 //syncing, the peer is dropped. 633 func (f *lightFetcher) checkSyncedHeaders(p *peer) { 634 fp := f.peers[p] 635 if fp == nil { 636 p.Log().Debug("Unknown peer to check sync headers") 637 return 638 } 639 n := fp.lastAnnounced 640 var td *big.Int 641 for n != nil { 642 if td = f.chain.GetTd(n.hash, n.number); td != nil { 643 break 644 } 645 n = n.parent 646 } 647 //现在n是同步后最新下载的头文件 648 if n == nil { 649 p.Log().Debug("Synchronisation failed") 650 go f.pm.removePeer(p.id) 651 } else { 652 header := f.chain.GetHeader(n.hash, n.number) 653 f.newHeaders([]*types.Header{header}, []*big.Int{td}) 654 } 655 } 656 657 //checkknownnode检查是否已知块树节点(已下载并验证) 658 //如果以前不知道,但在数据库中找到,则设置其已知标志 659 func (f *lightFetcher) checkKnownNode(p *peer, n *fetcherTreeNode) bool { 660 if n.known { 661 return true 662 } 663 td := f.chain.GetTd(n.hash, n.number) 664 if td == nil { 665 return false 666 } 667 header := f.chain.GetHeader(n.hash, n.number) 668 //检查header和td的可用性,因为chain db mutex不保护读操作 669 //注意:返回false在这里总是安全的 670 if header == nil { 671 return false 672 } 673 674 fp := f.peers[p] 675 if fp == nil { 676 p.Log().Debug("Unknown peer to check known nodes") 677 return false 678 } 679 if !f.checkAnnouncedHeaders(fp, []*types.Header{header}, []*big.Int{td}) { 680 p.Log().Debug("Inconsistent announcement") 681 go f.pm.removePeer(p.id) 682 } 683 if fp.confirmedTd != nil { 684 f.updateMaxConfirmedTd(fp.confirmedTd) 685 } 686 return n.known 687 } 688 689 //删除节点从对等块树中删除节点及其子树 690 func (fp *fetcherPeerInfo) deleteNode(n *fetcherTreeNode) { 691 if n.parent != nil { 692 for i, nn := range n.parent.children { 693 if nn == n { 694 n.parent.children = append(n.parent.children[:i], n.parent.children[i+1:]...) 695 break 696 } 697 } 698 } 699 for { 700 if n.td != nil { 701 delete(fp.nodeByHash, n.hash) 702 } 703 fp.nodeCnt-- 704 if len(n.children) == 0 { 705 return 706 } 707 for i, nn := range n.children { 708 if i == 0 { 709 n = nn 710 } else { 711 fp.deleteNode(nn) 712 } 713 } 714 } 715 } 716 717 //updateStatentEntry项形成一个链接列表,每次具有更高TD的新头时,都会使用新项展开该列表。 718 //已下载并验证。该列表包含一系列已确认的最大td值 719 //这些值被确认的时间,都是单调增加的。计算最大确认td 720 //无论是全球范围内的所有同行,还是每个单独的同行(也就是说,给定的同行已经宣布了领导 721 //它也已经从任何一个对等机上下载,无论是在发布之前还是之后)。 722 //链接列表有一个全局尾部,其中添加了新的已确认TD条目,并为每个对等端分别添加了一个头部, 723 //pointing to the next Td entry that is higher than the peer's max confirmed Td (nil if it has already confirmed 724 //目前的全球负责人)。 725 type updateStatsEntry struct { 726 time mclock.AbsTime 727 td *big.Int 728 next *updateStatsEntry 729 } 730 731 //updateMaxConfirmedtd更新活动对等机的块延迟统计信息。一旦确定了新的最高TD, 732 //将其与确认时间一起添加到链接列表的末尾。然后检查哪些同行 733 //已经确认了一个具有相同或更高TD(计算为零块延迟)的头,并更新了他们的统计数据。 734 //现在还没有确认该头的人将通过随后的checkupdatestats调用更新 735 //positive block delay value. 736 func (f *lightFetcher) updateMaxConfirmedTd(td *big.Int) { 737 if f.maxConfirmedTd == nil || td.Cmp(f.maxConfirmedTd) > 0 { 738 f.maxConfirmedTd = td 739 newEntry := &updateStatsEntry{ 740 time: mclock.Now(), 741 td: td, 742 } 743 if f.lastUpdateStats != nil { 744 f.lastUpdateStats.next = newEntry 745 } 746 f.lastUpdateStats = newEntry 747 for p := range f.peers { 748 f.checkUpdateStats(p, newEntry) 749 } 750 } 751 } 752 753 //CheckUpdateStats检查那些在确认某个最高TD(或更大TD)时还没有确认的同行。 754 //已被另一个对等方确认。如果他们现在已经确认了这样一个头部,他们的统计数据将更新为 755 //阻塞延迟,即(此对等方的确认时间)-(第一次确认时间)。BlockDelayTimeout通过后, 756 //统计信息将用BlockDelayTimeout值更新。在这两种情况下,已确认或超时的更新StatsEntry 757 //项目将从链接列表的标题中删除。 758 //如果新条目已添加到全局尾部,则在此处作为参数传递,即使此函数 759 //假设它已经被添加,这样如果对等方的列表是空的(所有头都已确认,头为零)。 760 //它可以将新头设置为newentry。 761 func (f *lightFetcher) checkUpdateStats(p *peer, newEntry *updateStatsEntry) { 762 now := mclock.Now() 763 fp := f.peers[p] 764 if fp == nil { 765 p.Log().Debug("Unknown peer to check update stats") 766 return 767 } 768 if newEntry != nil && fp.firstUpdateStats == nil { 769 fp.firstUpdateStats = newEntry 770 } 771 for fp.firstUpdateStats != nil && fp.firstUpdateStats.time <= now-mclock.AbsTime(blockDelayTimeout) { 772 f.pm.serverPool.adjustBlockDelay(p.poolEntry, blockDelayTimeout) 773 fp.firstUpdateStats = fp.firstUpdateStats.next 774 } 775 if fp.confirmedTd != nil { 776 for fp.firstUpdateStats != nil && fp.firstUpdateStats.td.Cmp(fp.confirmedTd) <= 0 { 777 f.pm.serverPool.adjustBlockDelay(p.poolEntry, time.Duration(now-fp.firstUpdateStats.time)) 778 fp.firstUpdateStats = fp.firstUpdateStats.next 779 } 780 } 781 } 782