github.com/digdeepmining/go-atheios@v1.5.13-0.20180902133602-d5687a2e6f43/les/fetcher.go (about) 1 // Copyright 2016 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 les implements the Light Ethereum Subprotocol. 18 package les 19 20 import ( 21 "math/big" 22 "sync" 23 "time" 24 25 "github.com/atheioschain/go-atheios/common" 26 "github.com/atheioschain/go-atheios/common/mclock" 27 "github.com/atheioschain/go-atheios/core" 28 "github.com/atheioschain/go-atheios/core/types" 29 "github.com/atheioschain/go-atheios/light" 30 "github.com/atheioschain/go-atheios/logger" 31 "github.com/atheioschain/go-atheios/logger/glog" 32 ) 33 34 const ( 35 blockDelayTimeout = time.Second * 10 // timeout for a peer to announce a head that has already been confirmed by others 36 maxNodeCount = 20 // maximum number of fetcherTreeNode entries remembered for each peer 37 ) 38 39 // lightFetcher 40 type lightFetcher struct { 41 pm *ProtocolManager 42 odr *LesOdr 43 chain *light.LightChain 44 45 maxConfirmedTd *big.Int 46 peers map[*peer]*fetcherPeerInfo 47 lastUpdateStats *updateStatsEntry 48 49 lock sync.Mutex // qwerqwerqwe 50 deliverChn chan fetchResponse 51 reqMu sync.RWMutex 52 requested map[uint64]fetchRequest 53 timeoutChn chan uint64 54 requestChn chan bool // true if initiated from outside 55 syncing bool 56 syncDone chan *peer 57 } 58 59 // fetcherPeerInfo holds fetcher-specific information about each active peer 60 type fetcherPeerInfo struct { 61 root, lastAnnounced *fetcherTreeNode 62 nodeCnt int 63 confirmedTd *big.Int 64 bestConfirmed *fetcherTreeNode 65 nodeByHash map[common.Hash]*fetcherTreeNode 66 firstUpdateStats *updateStatsEntry 67 } 68 69 // fetcherTreeNode is a node of a tree that holds information about blocks recently 70 // announced and confirmed by a certain peer. Each new announce message from a peer 71 // adds nodes to the tree, based on the previous announced head and the reorg depth. 72 // There are three possible states for a tree node: 73 // - announced: not downloaded (known) yet, but we know its head, number and td 74 // - intermediate: not known, hash and td are empty, they are filled out when it becomes known 75 // - known: both announced by this peer and downloaded (from any peer). 76 // This structure makes it possible to always know which peer has a certain block, 77 // which is necessary for selecting a suitable peer for ODR requests and also for 78 // canonizing new heads. It also helps to always download the minimum necessary 79 // amount of headers with a single request. 80 type fetcherTreeNode struct { 81 hash common.Hash 82 number uint64 83 td *big.Int 84 known, requested bool 85 parent *fetcherTreeNode 86 children []*fetcherTreeNode 87 } 88 89 // fetchRequest represents a header download request 90 type fetchRequest struct { 91 hash common.Hash 92 amount uint64 93 peer *peer 94 sent mclock.AbsTime 95 timeout bool 96 } 97 98 // fetchResponse represents a header download response 99 type fetchResponse struct { 100 reqID uint64 101 headers []*types.Header 102 peer *peer 103 } 104 105 // newLightFetcher creates a new light fetcher 106 func newLightFetcher(pm *ProtocolManager) *lightFetcher { 107 f := &lightFetcher{ 108 pm: pm, 109 chain: pm.blockchain.(*light.LightChain), 110 odr: pm.odr, 111 peers: make(map[*peer]*fetcherPeerInfo), 112 deliverChn: make(chan fetchResponse, 100), 113 requested: make(map[uint64]fetchRequest), 114 timeoutChn: make(chan uint64), 115 requestChn: make(chan bool, 100), 116 syncDone: make(chan *peer), 117 maxConfirmedTd: big.NewInt(0), 118 } 119 go f.syncLoop() 120 return f 121 } 122 123 // syncLoop is the main event loop of the light fetcher 124 func (f *lightFetcher) syncLoop() { 125 f.pm.wg.Add(1) 126 defer f.pm.wg.Done() 127 128 requesting := false 129 for { 130 select { 131 case <-f.pm.quitSync: 132 return 133 // when a new announce is received, request loop keeps running until 134 // no further requests are necessary or possible 135 case newAnnounce := <-f.requestChn: 136 f.lock.Lock() 137 s := requesting 138 requesting = false 139 if !f.syncing && !(newAnnounce && s) { 140 reqID := getNextReqID() 141 if peer, node, amount, retry := f.nextRequest(reqID); node != nil { 142 requesting = true 143 if reqID, ok := f.request(peer, reqID, node, amount); ok { 144 go func() { 145 time.Sleep(softRequestTimeout) 146 f.reqMu.Lock() 147 req, ok := f.requested[reqID] 148 if ok { 149 req.timeout = true 150 f.requested[reqID] = req 151 } 152 f.reqMu.Unlock() 153 // keep starting new requests while possible 154 f.requestChn <- false 155 }() 156 } 157 } else { 158 if retry { 159 requesting = true 160 go func() { 161 time.Sleep(time.Millisecond * 100) 162 f.requestChn <- false 163 }() 164 } 165 } 166 } 167 f.lock.Unlock() 168 case reqID := <-f.timeoutChn: 169 f.reqMu.Lock() 170 req, ok := f.requested[reqID] 171 if ok { 172 delete(f.requested, reqID) 173 } 174 f.reqMu.Unlock() 175 if ok { 176 f.pm.serverPool.adjustResponseTime(req.peer.poolEntry, time.Duration(mclock.Now()-req.sent), true) 177 glog.V(logger.Debug).Infof("hard timeout by peer %v", req.peer.id) 178 go f.pm.removePeer(req.peer.id) 179 } 180 case resp := <-f.deliverChn: 181 f.reqMu.Lock() 182 req, ok := f.requested[resp.reqID] 183 if ok && req.peer != resp.peer { 184 ok = false 185 } 186 if ok { 187 delete(f.requested, resp.reqID) 188 } 189 f.reqMu.Unlock() 190 if ok { 191 f.pm.serverPool.adjustResponseTime(req.peer.poolEntry, time.Duration(mclock.Now()-req.sent), req.timeout) 192 } 193 f.lock.Lock() 194 if !ok || !(f.syncing || f.processResponse(req, resp)) { 195 glog.V(logger.Debug).Infof("failed processing response by peer %v", resp.peer.id) 196 go f.pm.removePeer(resp.peer.id) 197 } 198 f.lock.Unlock() 199 case p := <-f.syncDone: 200 f.lock.Lock() 201 glog.V(logger.Debug).Infof("done synchronising with peer %v", p.id) 202 f.checkSyncedHeaders(p) 203 f.syncing = false 204 f.lock.Unlock() 205 } 206 } 207 } 208 209 // addPeer adds a new peer to the fetcher's peer set 210 func (f *lightFetcher) addPeer(p *peer) { 211 p.lock.Lock() 212 p.hasBlock = func(hash common.Hash, number uint64) bool { 213 return f.peerHasBlock(p, hash, number) 214 } 215 p.lock.Unlock() 216 217 f.lock.Lock() 218 defer f.lock.Unlock() 219 220 f.peers[p] = &fetcherPeerInfo{nodeByHash: make(map[common.Hash]*fetcherTreeNode)} 221 } 222 223 // removePeer removes a new peer from the fetcher's peer set 224 func (f *lightFetcher) removePeer(p *peer) { 225 p.lock.Lock() 226 p.hasBlock = nil 227 p.lock.Unlock() 228 229 f.lock.Lock() 230 defer f.lock.Unlock() 231 232 // check for potential timed out block delay statistics 233 f.checkUpdateStats(p, nil) 234 delete(f.peers, p) 235 } 236 237 // announce processes a new announcement message received from a peer, adding new 238 // nodes to the peer's block tree and removing old nodes if necessary 239 func (f *lightFetcher) announce(p *peer, head *announceData) { 240 f.lock.Lock() 241 defer f.lock.Unlock() 242 glog.V(logger.Debug).Infof("received announce from peer %v #%d %016x reorg: %d", p.id, head.Number, head.Hash[:8], head.ReorgDepth) 243 244 fp := f.peers[p] 245 if fp == nil { 246 glog.V(logger.Debug).Infof("announce: unknown peer") 247 return 248 } 249 250 if fp.lastAnnounced != nil && head.Td.Cmp(fp.lastAnnounced.td) <= 0 { 251 // announced tds should be strictly monotonic 252 glog.V(logger.Debug).Infof("non-monotonic Td from peer %v", p.id) 253 go f.pm.removePeer(p.id) 254 return 255 } 256 257 n := fp.lastAnnounced 258 for i := uint64(0); i < head.ReorgDepth; i++ { 259 if n == nil { 260 break 261 } 262 n = n.parent 263 } 264 if n != nil { 265 // n is now the reorg common ancestor, add a new branch of nodes 266 // check if the node count is too high to add new nodes 267 locked := false 268 for uint64(fp.nodeCnt)+head.Number-n.number > maxNodeCount && fp.root != nil { 269 if !locked { 270 f.chain.LockChain() 271 defer f.chain.UnlockChain() 272 locked = true 273 } 274 // if one of root's children is canonical, keep it, delete other branches and root itself 275 var newRoot *fetcherTreeNode 276 for i, nn := range fp.root.children { 277 if core.GetCanonicalHash(f.pm.chainDb, nn.number) == nn.hash { 278 fp.root.children = append(fp.root.children[:i], fp.root.children[i+1:]...) 279 nn.parent = nil 280 newRoot = nn 281 break 282 } 283 } 284 fp.deleteNode(fp.root) 285 if n == fp.root { 286 n = newRoot 287 } 288 fp.root = newRoot 289 if newRoot == nil || !f.checkKnownNode(p, newRoot) { 290 fp.bestConfirmed = nil 291 fp.confirmedTd = nil 292 } 293 294 if n == nil { 295 break 296 } 297 } 298 if n != nil { 299 for n.number < head.Number { 300 nn := &fetcherTreeNode{number: n.number + 1, parent: n} 301 n.children = append(n.children, nn) 302 n = nn 303 fp.nodeCnt++ 304 } 305 n.hash = head.Hash 306 n.td = head.Td 307 fp.nodeByHash[n.hash] = n 308 } 309 } 310 if n == nil { 311 // could not find reorg common ancestor or had to delete entire tree, a new root and a resync is needed 312 if fp.root != nil { 313 fp.deleteNode(fp.root) 314 } 315 n = &fetcherTreeNode{hash: head.Hash, number: head.Number, td: head.Td} 316 fp.root = n 317 fp.nodeCnt++ 318 fp.nodeByHash[n.hash] = n 319 fp.bestConfirmed = nil 320 fp.confirmedTd = nil 321 } 322 323 f.checkKnownNode(p, n) 324 p.lock.Lock() 325 p.headInfo = head 326 fp.lastAnnounced = n 327 p.lock.Unlock() 328 f.checkUpdateStats(p, nil) 329 f.requestChn <- true 330 } 331 332 // peerHasBlock returns true if we can assume the peer knows the given block 333 // based on its announcements 334 func (f *lightFetcher) peerHasBlock(p *peer, hash common.Hash, number uint64) bool { 335 f.lock.Lock() 336 defer f.lock.Unlock() 337 338 fp := f.peers[p] 339 if fp == nil || fp.root == nil { 340 return false 341 } 342 343 if number >= fp.root.number { 344 // it is recent enough that if it is known, is should be in the peer's block tree 345 return fp.nodeByHash[hash] != nil 346 } 347 f.chain.LockChain() 348 defer f.chain.UnlockChain() 349 // if it's older than the peer's block tree root but it's in the same canonical chain 350 // than the root, we can still be sure the peer knows it 351 return core.GetCanonicalHash(f.pm.chainDb, fp.root.number) == fp.root.hash && core.GetCanonicalHash(f.pm.chainDb, number) == hash 352 } 353 354 // request initiates a header download request from a certain peer 355 func (f *lightFetcher) request(p *peer, reqID uint64, n *fetcherTreeNode, amount uint64) (uint64, bool) { 356 fp := f.peers[p] 357 if fp == nil { 358 glog.V(logger.Debug).Infof("request: unknown peer") 359 p.fcServer.DeassignRequest(reqID) 360 return 0, false 361 } 362 if fp.bestConfirmed == nil || fp.root == nil || !f.checkKnownNode(p, fp.root) { 363 f.syncing = true 364 go func() { 365 glog.V(logger.Debug).Infof("synchronising with peer %v", p.id) 366 f.pm.synchronise(p) 367 f.syncDone <- p 368 }() 369 p.fcServer.DeassignRequest(reqID) 370 return 0, false 371 } 372 373 n.requested = true 374 cost := p.GetRequestCost(GetBlockHeadersMsg, int(amount)) 375 p.fcServer.SendRequest(reqID, cost) 376 f.reqMu.Lock() 377 f.requested[reqID] = fetchRequest{hash: n.hash, amount: amount, peer: p, sent: mclock.Now()} 378 f.reqMu.Unlock() 379 go p.RequestHeadersByHash(reqID, cost, n.hash, int(amount), 0, true) 380 go func() { 381 time.Sleep(hardRequestTimeout) 382 f.timeoutChn <- reqID 383 }() 384 return reqID, true 385 } 386 387 // requestAmount calculates the amount of headers to be downloaded starting 388 // from a certain head backwards 389 func (f *lightFetcher) requestAmount(p *peer, n *fetcherTreeNode) uint64 { 390 amount := uint64(0) 391 nn := n 392 for nn != nil && !f.checkKnownNode(p, nn) { 393 nn = nn.parent 394 amount++ 395 } 396 if nn == nil { 397 amount = n.number 398 } 399 return amount 400 } 401 402 // requestedID tells if a certain reqID has been requested by the fetcher 403 func (f *lightFetcher) requestedID(reqID uint64) bool { 404 f.reqMu.RLock() 405 _, ok := f.requested[reqID] 406 f.reqMu.RUnlock() 407 return ok 408 } 409 410 // nextRequest selects the peer and announced head to be requested next, amount 411 // to be downloaded starting from the head backwards is also returned 412 func (f *lightFetcher) nextRequest(reqID uint64) (*peer, *fetcherTreeNode, uint64, bool) { 413 var ( 414 bestHash common.Hash 415 bestAmount uint64 416 ) 417 bestTd := f.maxConfirmedTd 418 419 for p, fp := range f.peers { 420 for hash, n := range fp.nodeByHash { 421 if !f.checkKnownNode(p, n) && !n.requested && (bestTd == nil || n.td.Cmp(bestTd) >= 0) { 422 amount := f.requestAmount(p, n) 423 if bestTd == nil || n.td.Cmp(bestTd) > 0 || amount < bestAmount { 424 bestHash = hash 425 bestAmount = amount 426 bestTd = n.td 427 } 428 } 429 } 430 } 431 if bestTd == f.maxConfirmedTd { 432 return nil, nil, 0, false 433 } 434 435 peer, _, locked := f.pm.serverPool.selectPeer(reqID, func(p *peer) (bool, time.Duration) { 436 fp := f.peers[p] 437 if fp == nil || fp.nodeByHash[bestHash] == nil { 438 return false, 0 439 } 440 return true, p.fcServer.CanSend(p.GetRequestCost(GetBlockHeadersMsg, int(bestAmount))) 441 }) 442 if !locked { 443 return nil, nil, 0, true 444 } 445 var node *fetcherTreeNode 446 if peer != nil { 447 node = f.peers[peer].nodeByHash[bestHash] 448 } 449 return peer, node, bestAmount, false 450 } 451 452 // deliverHeaders delivers header download request responses for processing 453 func (f *lightFetcher) deliverHeaders(peer *peer, reqID uint64, headers []*types.Header) { 454 f.deliverChn <- fetchResponse{reqID: reqID, headers: headers, peer: peer} 455 } 456 457 // processResponse processes header download request responses, returns true if successful 458 func (f *lightFetcher) processResponse(req fetchRequest, resp fetchResponse) bool { 459 if uint64(len(resp.headers)) != req.amount || resp.headers[0].Hash() != req.hash { 460 glog.V(logger.Debug).Infof("response mismatch %v %016x != %v %016x", len(resp.headers), resp.headers[0].Hash().Bytes()[:8], req.amount, req.hash[:8]) 461 return false 462 } 463 headers := make([]*types.Header, req.amount) 464 for i, header := range resp.headers { 465 headers[int(req.amount)-1-i] = header 466 } 467 if _, err := f.chain.InsertHeaderChain(headers, 1); err != nil { 468 if err == core.BlockFutureErr { 469 return true 470 } 471 glog.V(logger.Debug).Infof("InsertHeaderChain error: %v", err) 472 return false 473 } 474 tds := make([]*big.Int, len(headers)) 475 for i, header := range headers { 476 td := f.chain.GetTd(header.Hash(), header.Number.Uint64()) 477 if td == nil { 478 glog.V(logger.Debug).Infof("TD not found for header %v of %v", i+1, len(headers)) 479 return false 480 } 481 tds[i] = td 482 } 483 f.newHeaders(headers, tds) 484 return true 485 } 486 487 // newHeaders updates the block trees of all active peers according to a newly 488 // downloaded and validated batch or headers 489 func (f *lightFetcher) newHeaders(headers []*types.Header, tds []*big.Int) { 490 var maxTd *big.Int 491 for p, fp := range f.peers { 492 if !f.checkAnnouncedHeaders(fp, headers, tds) { 493 glog.V(logger.Debug).Infof("announce inconsistency by peer %v", p.id) 494 go f.pm.removePeer(p.id) 495 } 496 if fp.confirmedTd != nil && (maxTd == nil || maxTd.Cmp(fp.confirmedTd) > 0) { 497 maxTd = fp.confirmedTd 498 } 499 } 500 if maxTd != nil { 501 f.updateMaxConfirmedTd(maxTd) 502 } 503 } 504 505 // checkAnnouncedHeaders updates peer's block tree if necessary after validating 506 // a batch of headers. It searches for the latest header in the batch that has a 507 // matching tree node (if any), and if it has not been marked as known already, 508 // sets it and its parents to known (even those which are older than the currently 509 // validated ones). Return value shows if all hashes, numbers and Tds matched 510 // correctly to the announced values (otherwise the peer should be dropped). 511 func (f *lightFetcher) checkAnnouncedHeaders(fp *fetcherPeerInfo, headers []*types.Header, tds []*big.Int) bool { 512 var ( 513 n *fetcherTreeNode 514 header *types.Header 515 td *big.Int 516 ) 517 518 for i := len(headers) - 1; ; i-- { 519 if i < 0 { 520 if n == nil { 521 // no more headers and nothing to match 522 return true 523 } 524 // we ran out of recently delivered headers but have not reached a node known by this peer yet, continue matching 525 td = f.chain.GetTd(header.ParentHash, header.Number.Uint64()-1) 526 header = f.chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) 527 } else { 528 header = headers[i] 529 td = tds[i] 530 } 531 hash := header.Hash() 532 number := header.Number.Uint64() 533 if n == nil { 534 n = fp.nodeByHash[hash] 535 } 536 if n != nil { 537 if n.td == nil { 538 // node was unannounced 539 if nn := fp.nodeByHash[hash]; nn != nil { 540 // if there was already a node with the same hash, continue there and drop this one 541 nn.children = append(nn.children, n.children...) 542 n.children = nil 543 fp.deleteNode(n) 544 n = nn 545 } else { 546 n.hash = hash 547 n.td = td 548 fp.nodeByHash[hash] = n 549 } 550 } 551 // check if it matches the header 552 if n.hash != hash || n.number != number || n.td.Cmp(td) != 0 { 553 // peer has previously made an invalid announcement 554 return false 555 } 556 if n.known { 557 // we reached a known node that matched our expectations, return with success 558 return true 559 } 560 n.known = true 561 if fp.confirmedTd == nil || td.Cmp(fp.confirmedTd) > 0 { 562 fp.confirmedTd = td 563 fp.bestConfirmed = n 564 } 565 n = n.parent 566 if n == nil { 567 return true 568 } 569 } 570 } 571 } 572 573 // checkSyncedHeaders updates peer's block tree after synchronisation by marking 574 // downloaded headers as known. If none of the announced headers are found after 575 // syncing, the peer is dropped. 576 func (f *lightFetcher) checkSyncedHeaders(p *peer) { 577 fp := f.peers[p] 578 if fp == nil { 579 glog.V(logger.Debug).Infof("checkSyncedHeaders: unknown peer") 580 return 581 } 582 n := fp.lastAnnounced 583 var td *big.Int 584 for n != nil { 585 if td = f.chain.GetTd(n.hash, n.number); td != nil { 586 break 587 } 588 n = n.parent 589 } 590 // now n is the latest downloaded header after syncing 591 if n == nil { 592 glog.V(logger.Debug).Infof("synchronisation failed with peer %v", p.id) 593 go f.pm.removePeer(p.id) 594 } else { 595 header := f.chain.GetHeader(n.hash, n.number) 596 f.newHeaders([]*types.Header{header}, []*big.Int{td}) 597 } 598 } 599 600 // checkKnownNode checks if a block tree node is known (downloaded and validated) 601 // If it was not known previously but found in the database, sets its known flag 602 func (f *lightFetcher) checkKnownNode(p *peer, n *fetcherTreeNode) bool { 603 if n.known { 604 return true 605 } 606 td := f.chain.GetTd(n.hash, n.number) 607 if td == nil { 608 return false 609 } 610 611 fp := f.peers[p] 612 if fp == nil { 613 glog.V(logger.Debug).Infof("checkKnownNode: unknown peer") 614 return false 615 } 616 header := f.chain.GetHeader(n.hash, n.number) 617 if !f.checkAnnouncedHeaders(fp, []*types.Header{header}, []*big.Int{td}) { 618 glog.V(logger.Debug).Infof("announce inconsistency by peer %v", p.id) 619 go f.pm.removePeer(p.id) 620 } 621 if fp.confirmedTd != nil { 622 f.updateMaxConfirmedTd(fp.confirmedTd) 623 } 624 return n.known 625 } 626 627 // deleteNode deletes a node and its child subtrees from a peer's block tree 628 func (fp *fetcherPeerInfo) deleteNode(n *fetcherTreeNode) { 629 if n.parent != nil { 630 for i, nn := range n.parent.children { 631 if nn == n { 632 n.parent.children = append(n.parent.children[:i], n.parent.children[i+1:]...) 633 break 634 } 635 } 636 } 637 for { 638 if n.td != nil { 639 delete(fp.nodeByHash, n.hash) 640 } 641 fp.nodeCnt-- 642 if len(n.children) == 0 { 643 return 644 } 645 for i, nn := range n.children { 646 if i == 0 { 647 n = nn 648 } else { 649 fp.deleteNode(nn) 650 } 651 } 652 } 653 } 654 655 // updateStatsEntry items form a linked list that is expanded with a new item every time a new head with a higher Td 656 // than the previous one has been downloaded and validated. The list contains a series of maximum confirmed Td values 657 // and the time these values have been confirmed, both increasing monotonically. A maximum confirmed Td is calculated 658 // both globally for all peers and also for each individual peer (meaning that the given peer has announced the head 659 // and it has also been downloaded from any peer, either before or after the given announcement). 660 // The linked list has a global tail where new confirmed Td entries are added and a separate head for each peer, 661 // pointing to the next Td entry that is higher than the peer's max confirmed Td (nil if it has already confirmed 662 // the current global head). 663 type updateStatsEntry struct { 664 time mclock.AbsTime 665 td *big.Int 666 next *updateStatsEntry 667 } 668 669 // updateMaxConfirmedTd updates the block delay statistics of active peers. Whenever a new highest Td is confirmed, 670 // adds it to the end of a linked list together with the time it has been confirmed. Then checks which peers have 671 // already confirmed a head with the same or higher Td (which counts as zero block delay) and updates their statistics. 672 // Those who have not confirmed such a head by now will be updated by a subsequent checkUpdateStats call with a 673 // positive block delay value. 674 func (f *lightFetcher) updateMaxConfirmedTd(td *big.Int) { 675 if f.maxConfirmedTd == nil || td.Cmp(f.maxConfirmedTd) > 0 { 676 f.maxConfirmedTd = td 677 newEntry := &updateStatsEntry{ 678 time: mclock.Now(), 679 td: td, 680 } 681 if f.lastUpdateStats != nil { 682 f.lastUpdateStats.next = newEntry 683 } 684 f.lastUpdateStats = newEntry 685 for p := range f.peers { 686 f.checkUpdateStats(p, newEntry) 687 } 688 } 689 } 690 691 // checkUpdateStats checks those peers who have not confirmed a certain highest Td (or a larger one) by the time it 692 // has been confirmed by another peer. If they have confirmed such a head by now, their stats are updated with the 693 // block delay which is (this peer's confirmation time)-(first confirmation time). After blockDelayTimeout has passed, 694 // the stats are updated with blockDelayTimeout value. In either case, the confirmed or timed out updateStatsEntry 695 // items are removed from the head of the linked list. 696 // If a new entry has been added to the global tail, it is passed as a parameter here even though this function 697 // assumes that it has already been added, so that if the peer's list is empty (all heads confirmed, head is nil), 698 // it can set the new head to newEntry. 699 func (f *lightFetcher) checkUpdateStats(p *peer, newEntry *updateStatsEntry) { 700 now := mclock.Now() 701 fp := f.peers[p] 702 if fp == nil { 703 glog.V(logger.Debug).Infof("checkUpdateStats: unknown peer") 704 return 705 } 706 if newEntry != nil && fp.firstUpdateStats == nil { 707 fp.firstUpdateStats = newEntry 708 } 709 for fp.firstUpdateStats != nil && fp.firstUpdateStats.time <= now-mclock.AbsTime(blockDelayTimeout) { 710 f.pm.serverPool.adjustBlockDelay(p.poolEntry, blockDelayTimeout) 711 fp.firstUpdateStats = fp.firstUpdateStats.next 712 } 713 if fp.confirmedTd != nil { 714 for fp.firstUpdateStats != nil && fp.firstUpdateStats.td.Cmp(fp.confirmedTd) <= 0 { 715 f.pm.serverPool.adjustBlockDelay(p.poolEntry, time.Duration(now-fp.firstUpdateStats.time)) 716 fp.firstUpdateStats = fp.firstUpdateStats.next 717 } 718 } 719 }