github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/eth/downloader/downloader.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 12:09:38</date> 10 //</624342633577189376> 11 12 13 //软件包下载器包含手动全链同步。 14 package downloader 15 16 import ( 17 "errors" 18 "fmt" 19 "math/big" 20 "sync" 21 "sync/atomic" 22 "time" 23 24 ethereum "github.com/ethereum/go-ethereum" 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/core/rawdb" 27 "github.com/ethereum/go-ethereum/core/types" 28 "github.com/ethereum/go-ethereum/ethdb" 29 "github.com/ethereum/go-ethereum/event" 30 "github.com/ethereum/go-ethereum/log" 31 "github.com/ethereum/go-ethereum/metrics" 32 "github.com/ethereum/go-ethereum/params" 33 ) 34 35 var ( 36 MaxHashFetch = 512 //每个检索请求要获取的哈希数 37 MaxBlockFetch = 128 //每个检索请求要获取的块的数量 38 MaxHeaderFetch = 192 //每个检索请求要获取的块头的数量 39 MaxSkeletonSize = 128 //骨架程序集所需的头提取数 40 MaxBodyFetch = 128 //每个检索请求要获取的块体数量 41 MaxReceiptFetch = 256 //允许每个请求提取的事务处理收据的数量 42 MaxStateFetch = 384 //允许每个请求提取的节点状态值的数量 43 44 MaxForkAncestry = 3 * params.EpochDuration //最大链重组 45 rttMinEstimate = 2 * time.Second //下载请求到目标的最短往返时间 46 rttMaxEstimate = 20 * time.Second //下载请求到达目标的最大往返时间 47 rttMinConfidence = 0.1 //估计的RTT值的置信系数更差 48 ttlScaling = 3 //RTT->TTL转换的恒定比例因子 49 ttlLimit = time.Minute //防止达到疯狂超时的最大TTL允许值 50 51 qosTuningPeers = 5 //要基于的对等数(最佳对等数) 52 qosConfidenceCap = 10 //不修改RTT置信度的对等数 53 qosTuningImpact = 0.25 //新的优化目标对上一个值的影响 54 55 maxQueuedHeaders = 32 * 1024 //[ETH/62]要排队导入的头的最大数目(DOS保护) 56 maxHeadersProcess = 2048 //一次导入到链中的头下载结果数 57 maxResultsProcess = 2048 //一次导入到链中的内容下载结果数 58 59 fsHeaderCheckFrequency = 100 //快速同步期间下载邮件头的验证频率 60 fsHeaderSafetyNet = 2048 //检测到链冲突时要丢弃的头数 61 fsHeaderForceVerify = 24 //要在接受透视之前和之后验证的标题数 62 fsHeaderContCheck = 3 * time.Second //状态下载期间检查头继续的时间间隔 63 fsMinFullBlocks = 64 //即使在快速同步中也要完全检索的块数 64 ) 65 66 var ( 67 errBusy = errors.New("busy") 68 errUnknownPeer = errors.New("peer is unknown or unhealthy") 69 errBadPeer = errors.New("action from bad peer ignored") 70 errStallingPeer = errors.New("peer is stalling") 71 errNoPeers = errors.New("no peers to keep download active") 72 errTimeout = errors.New("timeout") 73 errEmptyHeaderSet = errors.New("empty header set by peer") 74 errPeersUnavailable = errors.New("no peers available or all tried for download") 75 errInvalidAncestor = errors.New("retrieved ancestor is invalid") 76 errInvalidChain = errors.New("retrieved hash chain is invalid") 77 errInvalidBlock = errors.New("retrieved block is invalid") 78 errInvalidBody = errors.New("retrieved block body is invalid") 79 errInvalidReceipt = errors.New("retrieved receipt is invalid") 80 errCancelBlockFetch = errors.New("block download canceled (requested)") 81 errCancelHeaderFetch = errors.New("block header download canceled (requested)") 82 errCancelBodyFetch = errors.New("block body download canceled (requested)") 83 errCancelReceiptFetch = errors.New("receipt download canceled (requested)") 84 errCancelStateFetch = errors.New("state data download canceled (requested)") 85 errCancelHeaderProcessing = errors.New("header processing canceled (requested)") 86 errCancelContentProcessing = errors.New("content processing canceled (requested)") 87 errNoSyncActive = errors.New("no sync active") 88 errTooOld = errors.New("peer doesn't speak recent enough protocol version (need version >= 62)") 89 ) 90 91 type Downloader struct { 92 mode SyncMode //定义所用策略的同步模式(每个同步周期) 93 mux *event.TypeMux //事件同步器宣布同步操作事件 94 95 queue *queue //用于选择要下载的哈希的计划程序 96 peers *peerSet //可从中继续下载的活动对等点集 97 stateDB ethdb.Database 98 99 rttEstimate uint64 //目标下载请求的往返时间 100 rttConfidence uint64 //估计RTT的置信度(单位:百万分之一允许原子操作) 101 102 //统计 103 syncStatsChainOrigin uint64 //开始同步的起始块编号 104 syncStatsChainHeight uint64 //开始同步时已知的最高块号 105 syncStatsState stateSyncStats 106 syncStatsLock sync.RWMutex //锁定保护同步状态字段 107 108 lightchain LightChain 109 blockchain BlockChain 110 111 //回调 112 dropPeer peerDropFn //因行为不端而丢掉一个同伴 113 114 //状态 115 synchroniseMock func(id string, hash common.Hash) error //测试过程中的同步替换 116 synchronising int32 117 notified int32 118 committed int32 119 120 //渠道 121 headerCh chan dataPack //[ETH/62]接收入站数据块头的通道 122 bodyCh chan dataPack //[ETH/62]接收入站闭塞体的信道 123 receiptCh chan dataPack //[ETH/63]接收入站收据的通道 124 bodyWakeCh chan bool //[ETH/62]向新任务的块体获取器发送信号的通道 125 receiptWakeCh chan bool //[ETH/63]向接收新任务的接收者发送信号的通道 126 headerProcCh chan []*types.Header //[ETH/62]为头处理器提供新任务的通道 127 128 //用于StateFetcher 129 stateSyncStart chan *stateSync 130 trackStateReq chan *stateReq 131 stateCh chan dataPack //[ETH/63]接收入站节点状态数据的通道 132 133 //取消和终止 134 cancelPeer string //当前用作主机的对等机的标识符(删除时取消) 135 cancelCh chan struct{} //取消飞行中同步的频道 136 cancelLock sync.RWMutex //锁定以保护取消通道和对等端传递 137 cancelWg sync.WaitGroup //确保所有取出器Goroutine都已退出。 138 139 quitCh chan struct{} //退出通道至信号终止 140 quitLock sync.RWMutex //锁定以防止双重关闭 141 142 //测试钩 143 syncInitHook func(uint64, uint64) //启动新同步运行时调用的方法 144 bodyFetchHook func([]*types.Header) //启动块体提取时要调用的方法 145 receiptFetchHook func([]*types.Header) //开始获取收据时调用的方法 146 chainInsertHook func([]*fetchResult) //在插入块链时调用的方法(可能在多个调用中) 147 } 148 149 //LightChain封装了同步轻链所需的功能。 150 type LightChain interface { 151 //hasheader验证头在本地链中的存在。 152 HasHeader(common.Hash, uint64) bool 153 154 //GetHeaderByHash从本地链检索头。 155 GetHeaderByHash(common.Hash) *types.Header 156 157 //currentHeader从本地链中检索头标头。 158 CurrentHeader() *types.Header 159 160 //gettd返回本地块的总难度。 161 GetTd(common.Hash, uint64) *big.Int 162 163 //InsertHeaderChain将一批头插入本地链。 164 InsertHeaderChain([]*types.Header, int) (int, error) 165 166 //回滚从本地链中删除一些最近添加的元素。 167 Rollback([]common.Hash) 168 } 169 170 //区块链封装了同步(完整或快速)区块链所需的功能。 171 type BlockChain interface { 172 LightChain 173 174 //hasblock验证块在本地链中的存在。 175 HasBlock(common.Hash, uint64) bool 176 177 //GetBlockByHash从本地链中检索块。 178 GetBlockByHash(common.Hash) *types.Block 179 180 //currentBlock从本地链检索头块。 181 CurrentBlock() *types.Block 182 183 //currentFastBlock从本地链检索头快速块。 184 CurrentFastBlock() *types.Block 185 186 //fastsynccommithead直接将头块提交给某个实体。 187 FastSyncCommitHead(common.Hash) error 188 189 //插入链将一批块插入到本地链中。 190 InsertChain(types.Blocks) (int, error) 191 192 //InsertReceiptChain将一批收据插入本地链。 193 InsertReceiptChain(types.Blocks, []types.Receipts) (int, error) 194 } 195 196 //新建创建一个新的下载程序,从远程对等端获取哈希和块。 197 func New(mode SyncMode, stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn) *Downloader { 198 if lightchain == nil { 199 lightchain = chain 200 } 201 202 dl := &Downloader{ 203 mode: mode, 204 stateDB: stateDb, 205 mux: mux, 206 queue: newQueue(), 207 peers: newPeerSet(), 208 rttEstimate: uint64(rttMaxEstimate), 209 rttConfidence: uint64(1000000), 210 blockchain: chain, 211 lightchain: lightchain, 212 dropPeer: dropPeer, 213 headerCh: make(chan dataPack, 1), 214 bodyCh: make(chan dataPack, 1), 215 receiptCh: make(chan dataPack, 1), 216 bodyWakeCh: make(chan bool, 1), 217 receiptWakeCh: make(chan bool, 1), 218 headerProcCh: make(chan []*types.Header, 1), 219 quitCh: make(chan struct{}), 220 stateCh: make(chan dataPack), 221 stateSyncStart: make(chan *stateSync), 222 syncStatsState: stateSyncStats{ 223 processed: rawdb.ReadFastTrieProgress(stateDb), 224 }, 225 trackStateReq: make(chan *stateReq), 226 } 227 go dl.qosTuner() 228 go dl.stateFetcher() 229 return dl 230 } 231 232 //进程检索同步边界,特别是起源。 233 //同步开始于的块(可能已失败/暂停);块 234 //或头同步当前位于;以及同步目标的最新已知块。 235 // 236 //此外,在快速同步的状态下载阶段, 237 //同时返回已处理状态和已知状态总数。否则 238 //这些都是零。 239 func (d *Downloader) Progress() ethereum.SyncProgress { 240 //锁定当前状态并返回进度 241 d.syncStatsLock.RLock() 242 defer d.syncStatsLock.RUnlock() 243 244 current := uint64(0) 245 switch d.mode { 246 case FullSync: 247 current = d.blockchain.CurrentBlock().NumberU64() 248 case FastSync: 249 current = d.blockchain.CurrentFastBlock().NumberU64() 250 case LightSync: 251 current = d.lightchain.CurrentHeader().Number.Uint64() 252 } 253 return ethereum.SyncProgress{ 254 StartingBlock: d.syncStatsChainOrigin, 255 CurrentBlock: current, 256 HighestBlock: d.syncStatsChainHeight, 257 PulledStates: d.syncStatsState.processed, 258 KnownStates: d.syncStatsState.processed + d.syncStatsState.pending, 259 } 260 } 261 262 //同步返回下载程序当前是否正在检索块。 263 func (d *Downloader) Synchronising() bool { 264 return atomic.LoadInt32(&d.synchronising) > 0 265 } 266 267 //registerpeer将一个新的下载对等注入到要 268 //用于从获取哈希和块。 269 func (d *Downloader) RegisterPeer(id string, version int, peer Peer) error { 270 logger := log.New("peer", id) 271 logger.Trace("Registering sync peer") 272 if err := d.peers.Register(newPeerConnection(id, version, peer, logger)); err != nil { 273 logger.Error("Failed to register sync peer", "err", err) 274 return err 275 } 276 d.qosReduceConfidence() 277 278 return nil 279 } 280 281 //Regiterlightpeer注入一个轻量级客户端对等端,将其包装起来,使其看起来像一个普通对等端。 282 func (d *Downloader) RegisterLightPeer(id string, version int, peer LightPeer) error { 283 return d.RegisterPeer(id, version, &lightPeerWrapper{peer}) 284 } 285 286 //注销对等机从已知列表中删除对等机,以阻止 287 //指定的对等机。还将努力将任何挂起的回迁返回到 288 //排队。 289 func (d *Downloader) UnregisterPeer(id string) error { 290 //从活动对等机集中注销对等机并撤消任何获取任务 291 logger := log.New("peer", id) 292 logger.Trace("Unregistering sync peer") 293 if err := d.peers.Unregister(id); err != nil { 294 logger.Error("Failed to unregister sync peer", "err", err) 295 return err 296 } 297 d.queue.Revoke(id) 298 299 //如果此对等是主对等,则立即中止同步 300 d.cancelLock.RLock() 301 master := id == d.cancelPeer 302 d.cancelLock.RUnlock() 303 304 if master { 305 d.cancel() 306 } 307 return nil 308 } 309 310 //Synchronise尝试将本地区块链与远程对等机同步,两者都是 311 //添加各种健全性检查,并用各种日志条目包装它。 312 func (d *Downloader) Synchronise(id string, head common.Hash, td *big.Int, mode SyncMode) error { 313 err := d.synchronise(id, head, td, mode) 314 switch err { 315 case nil: 316 case errBusy: 317 318 case errTimeout, errBadPeer, errStallingPeer, 319 errEmptyHeaderSet, errPeersUnavailable, errTooOld, 320 errInvalidAncestor, errInvalidChain: 321 log.Warn("Synchronisation failed, dropping peer", "peer", id, "err", err) 322 if d.dropPeer == nil { 323 //当对本地副本使用“--copydb”时,droppeer方法为nil。 324 //如果压缩在错误的时间命中,则可能发生超时,并且可以忽略。 325 log.Warn("Downloader wants to drop peer, but peerdrop-function is not set", "peer", id) 326 } else { 327 d.dropPeer(id) 328 } 329 default: 330 log.Warn("Synchronisation failed, retrying", "err", err) 331 } 332 return err 333 } 334 335 //同步将选择对等机并使用它进行同步。如果给出空字符串 336 //如果它的td比我们自己的高,它将使用尽可能最好的对等机并进行同步。如果有 337 //检查失败,将返回错误。此方法是同步的 338 func (d *Downloader) synchronise(id string, hash common.Hash, td *big.Int, mode SyncMode) error { 339 //模拟同步如果测试 340 if d.synchroniseMock != nil { 341 return d.synchroniseMock(id, hash) 342 } 343 //确保一次只允许一个Goroutine通过此点 344 if !atomic.CompareAndSwapInt32(&d.synchronising, 0, 1) { 345 return errBusy 346 } 347 defer atomic.StoreInt32(&d.synchronising, 0) 348 349 //发布同步的用户通知(每个会话仅一次) 350 if atomic.CompareAndSwapInt32(&d.notified, 0, 1) { 351 log.Info("Block synchronisation started") 352 } 353 //重置队列、对等设置和唤醒通道以清除任何内部剩余状态 354 d.queue.Reset() 355 d.peers.Reset() 356 357 for _, ch := range []chan bool{d.bodyWakeCh, d.receiptWakeCh} { 358 select { 359 case <-ch: 360 default: 361 } 362 } 363 for _, ch := range []chan dataPack{d.headerCh, d.bodyCh, d.receiptCh} { 364 for empty := false; !empty; { 365 select { 366 case <-ch: 367 default: 368 empty = true 369 } 370 } 371 } 372 for empty := false; !empty; { 373 select { 374 case <-d.headerProcCh: 375 default: 376 empty = true 377 } 378 } 379 //为中途中止创建取消频道并标记主对等机 380 d.cancelLock.Lock() 381 d.cancelCh = make(chan struct{}) 382 d.cancelPeer = id 383 d.cancelLock.Unlock() 384 385 defer d.Cancel() //不管怎样,我们不能让取消频道一直开着 386 387 //设置请求的同步模式,除非被禁止 388 d.mode = mode 389 390 //检索源对等机并启动下载过程 391 p := d.peers.Peer(id) 392 if p == nil { 393 return errUnknownPeer 394 } 395 return d.syncWithPeer(p, hash, td) 396 } 397 398 //SyncWithPeer根据来自 399 //指定的对等和头哈希。 400 func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td *big.Int) (err error) { 401 d.mux.Post(StartEvent{}) 402 defer func() { 403 //错误重置 404 if err != nil { 405 d.mux.Post(FailedEvent{err}) 406 } else { 407 d.mux.Post(DoneEvent{}) 408 } 409 }() 410 if p.version < 62 { 411 return errTooOld 412 } 413 414 log.Debug("Synchronising with the network", "peer", p.id, "eth", p.version, "head", hash, "td", td, "mode", d.mode) 415 defer func(start time.Time) { 416 log.Debug("Synchronisation terminated", "elapsed", time.Since(start)) 417 }(time.Now()) 418 419 //查找同步边界:共同祖先和目标块 420 latest, err := d.fetchHeight(p) 421 if err != nil { 422 return err 423 } 424 height := latest.Number.Uint64() 425 426 origin, err := d.findAncestor(p, height) 427 if err != nil { 428 return err 429 } 430 d.syncStatsLock.Lock() 431 if d.syncStatsChainHeight <= origin || d.syncStatsChainOrigin > origin { 432 d.syncStatsChainOrigin = origin 433 } 434 d.syncStatsChainHeight = height 435 d.syncStatsLock.Unlock() 436 437 //确保我们的原点在任何快速同步轴点之下 438 pivot := uint64(0) 439 if d.mode == FastSync { 440 if height <= uint64(fsMinFullBlocks) { 441 origin = 0 442 } else { 443 pivot = height - uint64(fsMinFullBlocks) 444 if pivot <= origin { 445 origin = pivot - 1 446 } 447 } 448 } 449 d.committed = 1 450 if d.mode == FastSync && pivot != 0 { 451 d.committed = 0 452 } 453 //使用并发头和内容检索算法启动同步 454 d.queue.Prepare(origin+1, d.mode) 455 if d.syncInitHook != nil { 456 d.syncInitHook(origin, height) 457 } 458 459 fetchers := []func() error{ 460 func() error { return d.fetchHeaders(p, origin+1, pivot) }, //始终检索邮件头 461 func() error { return d.fetchBodies(origin + 1) }, //在正常和快速同步期间检索主体 462 func() error { return d.fetchReceipts(origin + 1) }, //在快速同步过程中检索收据 463 func() error { return d.processHeaders(origin+1, pivot, td) }, 464 } 465 if d.mode == FastSync { 466 fetchers = append(fetchers, func() error { return d.processFastSyncContent(latest) }) 467 } else if d.mode == FullSync { 468 fetchers = append(fetchers, d.processFullSyncContent) 469 } 470 return d.spawnSync(fetchers) 471 } 472 473 //产卵同步运行d.process和所有给定的提取函数以在中完成 474 //分离goroutine,返回出现的第一个错误。 475 func (d *Downloader) spawnSync(fetchers []func() error) error { 476 errc := make(chan error, len(fetchers)) 477 d.cancelWg.Add(len(fetchers)) 478 for _, fn := range fetchers { 479 fn := fn 480 go func() { defer d.cancelWg.Done(); errc <- fn() }() 481 } 482 //等待第一个错误,然后终止其他错误。 483 var err error 484 for i := 0; i < len(fetchers); i++ { 485 if i == len(fetchers)-1 { 486 //当所有提取程序退出时关闭队列。 487 //这将导致块处理器在 488 //它已经处理了队列。 489 d.queue.Close() 490 } 491 if err = <-errc; err != nil { 492 break 493 } 494 } 495 d.queue.Close() 496 d.Cancel() 497 return err 498 } 499 500 //取消中止所有操作并重置队列。但是,取消是 501 //不要等待正在运行的下载Goroutines完成。这个方法应该是 502 //从下载程序内部取消下载时使用。 503 func (d *Downloader) cancel() { 504 //关闭当前取消频道 505 d.cancelLock.Lock() 506 if d.cancelCh != nil { 507 select { 508 case <-d.cancelCh: 509 //频道已关闭 510 default: 511 close(d.cancelCh) 512 } 513 } 514 d.cancelLock.Unlock() 515 } 516 517 //取消中止所有操作,并等待所有下载Goroutines到 518 //返回前完成。 519 func (d *Downloader) Cancel() { 520 d.cancel() 521 d.cancelWg.Wait() 522 } 523 524 //终止中断下载程序,取消所有挂起的操作。 525 //调用terminate后,下载程序不能再使用。 526 func (d *Downloader) Terminate() { 527 //关闭终端通道(确保允许双重关闭) 528 d.quitLock.Lock() 529 select { 530 case <-d.quitCh: 531 default: 532 close(d.quitCh) 533 } 534 d.quitLock.Unlock() 535 536 //取消任何挂起的下载请求 537 d.Cancel() 538 } 539 540 //fetchheight检索远程对等端的头段以帮助估计 541 //等待同步所需的总时间。 542 func (d *Downloader) fetchHeight(p *peerConnection) (*types.Header, error) { 543 p.log.Debug("Retrieving remote chain height") 544 545 //请求公布的远程头块并等待响应 546 head, _ := p.peer.Head() 547 go p.peer.RequestHeadersByHash(head, 1, 0, false) 548 549 ttl := d.requestTTL() 550 timeout := time.After(ttl) 551 for { 552 select { 553 case <-d.cancelCh: 554 return nil, errCancelBlockFetch 555 556 case packet := <-d.headerCh: 557 //丢弃源对等机以外的任何内容 558 if packet.PeerId() != p.id { 559 log.Debug("Received headers from incorrect peer", "peer", packet.PeerId()) 560 break 561 } 562 //确保对方给出了有效的信息 563 headers := packet.(*headerPack).headers 564 if len(headers) != 1 { 565 p.log.Debug("Multiple headers for single request", "headers", len(headers)) 566 return nil, errBadPeer 567 } 568 head := headers[0] 569 p.log.Debug("Remote head header identified", "number", head.Number, "hash", head.Hash()) 570 return head, nil 571 572 case <-timeout: 573 p.log.Debug("Waiting for head header timed out", "elapsed", ttl) 574 return nil, errTimeout 575 576 case <-d.bodyCh: 577 case <-d.receiptCh: 578 //越界交货,忽略 579 } 580 } 581 } 582 583 //findancestor试图定位本地链的共同祖先链接,并且 584 //远程对等区块链。在一般情况下,当我们的节点处于同步状态时, 585 //在正确的链条上,检查顶部的N个链环应该已经得到了匹配。 586 //在罕见的情况下,当我们结束了长期的重组(即没有 587 //头部链接匹配),我们进行二进制搜索以找到共同的祖先。 588 func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, error) { 589 //找出有效的祖先范围以防止重写攻击 590 floor, ceil := int64(-1), d.lightchain.CurrentHeader().Number.Uint64() 591 592 if d.mode == FullSync { 593 ceil = d.blockchain.CurrentBlock().NumberU64() 594 } else if d.mode == FastSync { 595 ceil = d.blockchain.CurrentFastBlock().NumberU64() 596 } 597 if ceil >= MaxForkAncestry { 598 floor = int64(ceil - MaxForkAncestry) 599 } 600 p.log.Debug("Looking for common ancestor", "local", ceil, "remote", height) 601 602 //请求最上面的块短路二进制祖先查找 603 head := ceil 604 if head > height { 605 head = height 606 } 607 from := int64(head) - int64(MaxHeaderFetch) 608 if from < 0 { 609 from = 0 610 } 611 //跨越15个区块,以捕捉坏的头报告 612 limit := 2 * MaxHeaderFetch / 16 613 count := 1 + int((int64(ceil)-from)/16) 614 if count > limit { 615 count = limit 616 } 617 go p.peer.RequestHeadersByNumber(uint64(from), count, 15, false) 618 619 //等待对头提取的远程响应 620 number, hash := uint64(0), common.Hash{} 621 622 ttl := d.requestTTL() 623 timeout := time.After(ttl) 624 625 for finished := false; !finished; { 626 select { 627 case <-d.cancelCh: 628 return 0, errCancelHeaderFetch 629 630 case packet := <-d.headerCh: 631 //丢弃源对等机以外的任何内容 632 if packet.PeerId() != p.id { 633 log.Debug("Received headers from incorrect peer", "peer", packet.PeerId()) 634 break 635 } 636 //确保对方给出了有效的信息 637 headers := packet.(*headerPack).headers 638 if len(headers) == 0 { 639 p.log.Warn("Empty head header set") 640 return 0, errEmptyHeaderSet 641 } 642 //确保对等方的答复符合请求 643 for i := 0; i < len(headers); i++ { 644 if number := headers[i].Number.Int64(); number != from+int64(i)*16 { 645 p.log.Warn("Head headers broke chain ordering", "index", i, "requested", from+int64(i)*16, "received", number) 646 return 0, errInvalidChain 647 } 648 } 649 //检查是否找到共同祖先 650 finished = true 651 for i := len(headers) - 1; i >= 0; i-- { 652 //跳过任何下溢/溢出请求集的头 653 if headers[i].Number.Int64() < from || headers[i].Number.Uint64() > ceil { 654 continue 655 } 656 //否则检查我们是否已经知道标题 657 if (d.mode == FullSync && d.blockchain.HasBlock(headers[i].Hash(), headers[i].Number.Uint64())) || (d.mode != FullSync && d.lightchain.HasHeader(headers[i].Hash(), headers[i].Number.Uint64())) { 658 number, hash = headers[i].Number.Uint64(), headers[i].Hash() 659 660 //如果每一个标题都是已知的,甚至是未来的标题,那么同行们就会直接说谎。 661 if number > height && i == limit-1 { 662 p.log.Warn("Lied about chain head", "reported", height, "found", number) 663 return 0, errStallingPeer 664 } 665 break 666 } 667 } 668 669 case <-timeout: 670 p.log.Debug("Waiting for head header timed out", "elapsed", ttl) 671 return 0, errTimeout 672 673 case <-d.bodyCh: 674 case <-d.receiptCh: 675 //越界交货,忽略 676 } 677 } 678 //如果head fetch已经找到祖先,则返回 679 if hash != (common.Hash{}) { 680 if int64(number) <= floor { 681 p.log.Warn("Ancestor below allowance", "number", number, "hash", hash, "allowance", floor) 682 return 0, errInvalidAncestor 683 } 684 p.log.Debug("Found common ancestor", "number", number, "hash", hash) 685 return number, nil 686 } 687 //找不到祖先,我们需要在链上进行二进制搜索 688 start, end := uint64(0), head 689 if floor > 0 { 690 start = uint64(floor) 691 } 692 for start+1 < end { 693 //将链间隔拆分为两个,并请求哈希进行交叉检查 694 check := (start + end) / 2 695 696 ttl := d.requestTTL() 697 timeout := time.After(ttl) 698 699 go p.peer.RequestHeadersByNumber(check, 1, 0, false) 700 701 //等待答复到达此请求 702 for arrived := false; !arrived; { 703 select { 704 case <-d.cancelCh: 705 return 0, errCancelHeaderFetch 706 707 case packer := <-d.headerCh: 708 //丢弃源对等机以外的任何内容 709 if packer.PeerId() != p.id { 710 log.Debug("Received headers from incorrect peer", "peer", packer.PeerId()) 711 break 712 } 713 //确保对方给出了有效的信息 714 headers := packer.(*headerPack).headers 715 if len(headers) != 1 { 716 p.log.Debug("Multiple headers for single request", "headers", len(headers)) 717 return 0, errBadPeer 718 } 719 arrived = true 720 721 //根据响应修改搜索间隔 722 if (d.mode == FullSync && !d.blockchain.HasBlock(headers[0].Hash(), headers[0].Number.Uint64())) || (d.mode != FullSync && !d.lightchain.HasHeader(headers[0].Hash(), headers[0].Number.Uint64())) { 723 end = check 724 break 725 } 726 header := d.lightchain.GetHeaderByHash(headers[0].Hash()) //独立于同步模式,头文件肯定存在 727 if header.Number.Uint64() != check { 728 p.log.Debug("Received non requested header", "number", header.Number, "hash", header.Hash(), "request", check) 729 return 0, errBadPeer 730 } 731 start = check 732 733 case <-timeout: 734 p.log.Debug("Waiting for search header timed out", "elapsed", ttl) 735 return 0, errTimeout 736 737 case <-d.bodyCh: 738 case <-d.receiptCh: 739 //越界交货,忽略 740 } 741 } 742 } 743 //确保有效的祖传和回归 744 if int64(start) <= floor { 745 p.log.Warn("Ancestor below allowance", "number", start, "hash", hash, "allowance", floor) 746 return 0, errInvalidAncestor 747 } 748 p.log.Debug("Found common ancestor", "number", start, "hash", hash) 749 return start, nil 750 } 751 752 //FetchHeaders始终从数字中同时检索头 753 //请求,直到不再返回,可能会在途中限制。到 754 //方便并发,但仍能防止恶意节点发送错误 755 //headers,我们使用“origin”对等体构造一个header链骨架。 756 //正在与同步,并使用其他人填写丢失的邮件头。报头 757 //只有当其他对等点干净地映射到骨架时,才接受它们。如果没有人 758 //可以填充骨架-甚至不是源节点-它被假定为无效和 759 //原点被删除。 760 func (d *Downloader) fetchHeaders(p *peerConnection, from uint64, pivot uint64) error { 761 p.log.Debug("Directing header downloads", "origin", from) 762 defer p.log.Debug("Header download terminated") 763 764 //创建超时计时器和相关联的头提取程序 765 skeleton := true //骨架装配阶段或完成 766 request := time.Now() //最后一个骨架获取请求的时间 767 timeout := time.NewTimer(0) //转储非响应活动对等机的计时器 768 <-timeout.C //超时通道最初应为空 769 defer timeout.Stop() 770 771 var ttl time.Duration 772 getHeaders := func(from uint64) { 773 request = time.Now() 774 775 ttl = d.requestTTL() 776 timeout.Reset(ttl) 777 778 if skeleton { 779 p.log.Trace("Fetching skeleton headers", "count", MaxHeaderFetch, "from", from) 780 go p.peer.RequestHeadersByNumber(from+uint64(MaxHeaderFetch)-1, MaxSkeletonSize, MaxHeaderFetch-1, false) 781 } else { 782 p.log.Trace("Fetching full headers", "count", MaxHeaderFetch, "from", from) 783 go p.peer.RequestHeadersByNumber(from, MaxHeaderFetch, 0, false) 784 } 785 } 786 //开始拉动收割台链条骨架,直到全部完成。 787 getHeaders(from) 788 789 for { 790 select { 791 case <-d.cancelCh: 792 return errCancelHeaderFetch 793 794 case packet := <-d.headerCh: 795 //确保活动对等端正在向我们提供骨架头 796 if packet.PeerId() != p.id { 797 log.Debug("Received skeleton from incorrect peer", "peer", packet.PeerId()) 798 break 799 } 800 headerReqTimer.UpdateSince(request) 801 timeout.Stop() 802 803 //如果骨架已完成,则直接从原点拉出任何剩余的头部标题。 804 if packet.Items() == 0 && skeleton { 805 skeleton = false 806 getHeaders(from) 807 continue 808 } 809 //如果没有更多的头是入站的,通知内容提取程序并返回 810 if packet.Items() == 0 { 811 //下载数据透视时不要中止头提取 812 if atomic.LoadInt32(&d.committed) == 0 && pivot <= from { 813 p.log.Debug("No headers, waiting for pivot commit") 814 select { 815 case <-time.After(fsHeaderContCheck): 816 getHeaders(from) 817 continue 818 case <-d.cancelCh: 819 return errCancelHeaderFetch 820 } 821 } 822 //透视完成(或不快速同步)并且没有更多的头,终止进程 823 p.log.Debug("No more headers available") 824 select { 825 case d.headerProcCh <- nil: 826 return nil 827 case <-d.cancelCh: 828 return errCancelHeaderFetch 829 } 830 } 831 headers := packet.(*headerPack).headers 832 833 //如果我们接收到一个框架批处理,那么同时解析内部构件 834 if skeleton { 835 filled, proced, err := d.fillHeaderSkeleton(from, headers) 836 if err != nil { 837 p.log.Debug("Skeleton chain invalid", "err", err) 838 return errInvalidChain 839 } 840 headers = filled[proced:] 841 from += uint64(proced) 842 } 843 //插入所有新标题并获取下一批 844 if len(headers) > 0 { 845 p.log.Trace("Scheduling new headers", "count", len(headers), "from", from) 846 select { 847 case d.headerProcCh <- headers: 848 case <-d.cancelCh: 849 return errCancelHeaderFetch 850 } 851 from += uint64(len(headers)) 852 } 853 getHeaders(from) 854 855 case <-timeout.C: 856 if d.dropPeer == nil { 857 //当对本地副本使用“--copydb”时,droppeer方法为nil。 858 //如果压缩在错误的时间命中,则可能发生超时,并且可以忽略。 859 p.log.Warn("Downloader wants to drop peer, but peerdrop-function is not set", "peer", p.id) 860 break 861 } 862 //头检索超时,考虑对等机错误并丢弃 863 p.log.Debug("Header request timed out", "elapsed", ttl) 864 headerTimeoutMeter.Mark(1) 865 d.dropPeer(p.id) 866 867 //但是,请优雅地完成同步,而不是转储收集的数据 868 for _, ch := range []chan bool{d.bodyWakeCh, d.receiptWakeCh} { 869 select { 870 case ch <- false: 871 case <-d.cancelCh: 872 } 873 } 874 select { 875 case d.headerProcCh <- nil: 876 case <-d.cancelCh: 877 } 878 return errBadPeer 879 } 880 } 881 } 882 883 //FillHeaderskeleton同时从所有可用的对等端检索头 884 //并将它们映射到提供的骨架头链。 885 // 886 //从骨架开始的任何部分结果(如果可能)都将被转发 887 //立即发送到头处理器,以保持管道的其余部分保持平衡 888 //如果收割台失速。 889 // 890 //该方法返回整个填充骨架以及头的数量。 891 //已转发进行处理。 892 func (d *Downloader) fillHeaderSkeleton(from uint64, skeleton []*types.Header) ([]*types.Header, int, error) { 893 log.Debug("Filling up skeleton", "from", from) 894 d.queue.ScheduleSkeleton(from, skeleton) 895 896 var ( 897 deliver = func(packet dataPack) (int, error) { 898 pack := packet.(*headerPack) 899 return d.queue.DeliverHeaders(pack.peerID, pack.headers, d.headerProcCh) 900 } 901 expire = func() map[string]int { return d.queue.ExpireHeaders(d.requestTTL()) } 902 throttle = func() bool { return false } 903 reserve = func(p *peerConnection, count int) (*fetchRequest, bool, error) { 904 return d.queue.ReserveHeaders(p, count), false, nil 905 } 906 fetch = func(p *peerConnection, req *fetchRequest) error { return p.FetchHeaders(req.From, MaxHeaderFetch) } 907 capacity = func(p *peerConnection) int { return p.HeaderCapacity(d.requestRTT()) } 908 setIdle = func(p *peerConnection, accepted int) { p.SetHeadersIdle(accepted) } 909 ) 910 err := d.fetchParts(errCancelHeaderFetch, d.headerCh, deliver, d.queue.headerContCh, expire, 911 d.queue.PendingHeaders, d.queue.InFlightHeaders, throttle, reserve, 912 nil, fetch, d.queue.CancelHeaders, capacity, d.peers.HeaderIdlePeers, setIdle, "headers") 913 914 log.Debug("Skeleton fill terminated", "err", err) 915 916 filled, proced := d.queue.RetrieveHeaders() 917 return filled, proced, err 918 } 919 920 //fetchbodies迭代下载计划的块体,获取 921 //可用对等机,为每个对等机保留一大块数据块,等待传递 922 //并定期检查超时情况。 923 func (d *Downloader) fetchBodies(from uint64) error { 924 log.Debug("Downloading block bodies", "origin", from) 925 926 var ( 927 deliver = func(packet dataPack) (int, error) { 928 pack := packet.(*bodyPack) 929 return d.queue.DeliverBodies(pack.peerID, pack.transactions, pack.uncles) 930 } 931 expire = func() map[string]int { return d.queue.ExpireBodies(d.requestTTL()) } 932 fetch = func(p *peerConnection, req *fetchRequest) error { return p.FetchBodies(req) } 933 capacity = func(p *peerConnection) int { return p.BlockCapacity(d.requestRTT()) } 934 setIdle = func(p *peerConnection, accepted int) { p.SetBodiesIdle(accepted) } 935 ) 936 err := d.fetchParts(errCancelBodyFetch, d.bodyCh, deliver, d.bodyWakeCh, expire, 937 d.queue.PendingBlocks, d.queue.InFlightBlocks, d.queue.ShouldThrottleBlocks, d.queue.ReserveBodies, 938 d.bodyFetchHook, fetch, d.queue.CancelBodies, capacity, d.peers.BodyIdlePeers, setIdle, "bodies") 939 940 log.Debug("Block body download terminated", "err", err) 941 return err 942 } 943 944 //fetchreceipts迭代地下载计划的块接收,获取 945 //可用的对等方,为每个对等方保留一大块收据,等待传递 946 //并定期检查超时情况。 947 func (d *Downloader) fetchReceipts(from uint64) error { 948 log.Debug("Downloading transaction receipts", "origin", from) 949 950 var ( 951 deliver = func(packet dataPack) (int, error) { 952 pack := packet.(*receiptPack) 953 return d.queue.DeliverReceipts(pack.peerID, pack.receipts) 954 } 955 expire = func() map[string]int { return d.queue.ExpireReceipts(d.requestTTL()) } 956 fetch = func(p *peerConnection, req *fetchRequest) error { return p.FetchReceipts(req) } 957 capacity = func(p *peerConnection) int { return p.ReceiptCapacity(d.requestRTT()) } 958 setIdle = func(p *peerConnection, accepted int) { p.SetReceiptsIdle(accepted) } 959 ) 960 err := d.fetchParts(errCancelReceiptFetch, d.receiptCh, deliver, d.receiptWakeCh, expire, 961 d.queue.PendingReceipts, d.queue.InFlightReceipts, d.queue.ShouldThrottleReceipts, d.queue.ReserveReceipts, 962 d.receiptFetchHook, fetch, d.queue.CancelReceipts, capacity, d.peers.ReceiptIdlePeers, setIdle, "receipts") 963 964 log.Debug("Transaction receipt download terminated", "err", err) 965 return err 966 } 967 968 //fetchparts迭代地下载计划的块部件,获取任何可用的 969 //对等机,为每个对等机保留一大块获取请求,等待传递和 970 //还要定期检查超时情况。 971 // 972 //由于所有下载的数据的调度/超时逻辑基本相同 973 //类型,此方法由每个方法用于数据收集,并使用 974 //处理它们之间的细微差别的各种回调。 975 // 976 //仪器参数: 977 //-errCancel:取消提取操作时返回的错误类型(主要使日志记录更好) 978 //-deliverych:从中检索下载数据包的通道(从所有并发对等机合并) 979 //-deliver:处理回调以将数据包传递到特定于类型的下载队列(通常在“queue”内) 980 //-wakech:通知通道,用于在新任务可用(或同步完成)时唤醒提取程序。 981 //-expire:任务回调方法,用于中止耗时太长的请求并返回故障对等端(流量形成) 982 //-挂起:对仍需要下载的请求数的任务回调(检测完成/不可完成性) 983 //-机上:正在进行的请求数的任务回调(等待所有活动下载完成) 984 //-限制:任务回调以检查处理队列是否已满并激活限制(绑定内存使用) 985 //-reserve:任务回调,将新的下载任务保留给特定的对等方(也表示部分完成) 986 //-fetchhook:tester回调,通知正在启动的新任务(允许测试调度逻辑) 987 //-fetch:网络回调,实际向物理远程对等端发送特定下载请求 988 //-取消:任务回调,以中止飞行中的下载请求并允许重新安排(如果对等机丢失) 989 //-容量:网络回调以检索对等机的估计类型特定带宽容量(流量形成) 990 //-idle:网络回调以检索当前(特定类型)可分配任务的空闲对等机 991 //-set idle:网络回调,将对等机设置回空闲状态,并更新其估计容量(流量形成) 992 //-kind:下载类型的文本标签,显示在日志消息中 993 func (d *Downloader) fetchParts(errCancel error, deliveryCh chan dataPack, deliver func(dataPack) (int, error), wakeCh chan bool, 994 expire func() map[string]int, pending func() int, inFlight func() bool, throttle func() bool, reserve func(*peerConnection, int) (*fetchRequest, bool, error), 995 fetchHook func([]*types.Header), fetch func(*peerConnection, *fetchRequest) error, cancel func(*fetchRequest), capacity func(*peerConnection) int, 996 idle func() ([]*peerConnection, int), setIdle func(*peerConnection, int), kind string) error { 997 998 //创建一个标记器以检测过期的检索任务 999 ticker := time.NewTicker(100 * time.Millisecond) 1000 defer ticker.Stop() 1001 1002 update := make(chan struct{}, 1) 1003 1004 //准备队列并获取块部件,直到块头获取器完成 1005 finished := false 1006 for { 1007 select { 1008 case <-d.cancelCh: 1009 return errCancel 1010 1011 case packet := <-deliveryCh: 1012 //如果之前同伴被禁止并且未能递送包裹 1013 //在合理的时间范围内,忽略其消息。 1014 if peer := d.peers.Peer(packet.PeerId()); peer != nil { 1015 //传递接收到的数据块并检查链的有效性 1016 accepted, err := deliver(packet) 1017 if err == errInvalidChain { 1018 return err 1019 } 1020 //除非一个同伴提供了完全不需要的东西(通常 1021 //由最后通过的超时请求引起),将其设置为 1022 //空闲的如果传递已过时,则对等端应该已经空闲。 1023 if err != errStaleDelivery { 1024 setIdle(peer, accepted) 1025 } 1026 //向用户发布日志以查看发生了什么 1027 switch { 1028 case err == nil && packet.Items() == 0: 1029 peer.log.Trace("Requested data not delivered", "type", kind) 1030 case err == nil: 1031 peer.log.Trace("Delivered new batch of data", "type", kind, "count", packet.Stats()) 1032 default: 1033 peer.log.Trace("Failed to deliver retrieved data", "type", kind, "err", err) 1034 } 1035 } 1036 //组装块,尝试更新进度 1037 select { 1038 case update <- struct{}{}: 1039 default: 1040 } 1041 1042 case cont := <-wakeCh: 1043 //头提取程序发送了一个继续标志,检查是否已完成 1044 if !cont { 1045 finished = true 1046 } 1047 //邮件头到达,请尝试更新进度 1048 select { 1049 case update <- struct{}{}: 1050 default: 1051 } 1052 1053 case <-ticker.C: 1054 //健全检查更新进度 1055 select { 1056 case update <- struct{}{}: 1057 default: 1058 } 1059 1060 case <-update: 1061 //如果我们失去所有同龄人,就会短路 1062 if d.peers.Len() == 0 { 1063 return errNoPeers 1064 } 1065 //检查获取请求超时并降级负责的对等方 1066 for pid, fails := range expire() { 1067 if peer := d.peers.Peer(pid); peer != nil { 1068 //如果许多检索元素过期,我们可能高估了远程对等机,或者 1069 //我们自己。只重置为最小吞吐量,但不要立即下降。即使是最短的时间 1070 //在同步方面,我们需要摆脱同龄人。 1071 // 1072 //最小阈值为2的原因是下载程序试图估计带宽 1073 //以及对等端的延迟,这需要稍微推一下度量容量并查看 1074 //响应时间如何反应,对它总是要求一个以上的最小值(即最小2)。 1075 if fails > 2 { 1076 peer.log.Trace("Data delivery timed out", "type", kind) 1077 setIdle(peer, 0) 1078 } else { 1079 peer.log.Debug("Stalling delivery, dropping", "type", kind) 1080 if d.dropPeer == nil { 1081 //当对本地副本使用“--copydb”时,droppeer方法为nil。 1082 //如果压缩在错误的时间命中,则可能发生超时,并且可以忽略。 1083 peer.log.Warn("Downloader wants to drop peer, but peerdrop-function is not set", "peer", pid) 1084 } else { 1085 d.dropPeer(pid) 1086 } 1087 } 1088 } 1089 } 1090 //如果没有其他东西可以获取,请等待或终止 1091 if pending() == 0 { 1092 if !inFlight() && finished { 1093 log.Debug("Data fetching completed", "type", kind) 1094 return nil 1095 } 1096 break 1097 } 1098 //向所有空闲对等端发送下载请求,直到被阻止 1099 progressed, throttled, running := false, false, inFlight() 1100 idles, total := idle() 1101 1102 for _, peer := range idles { 1103 //节流启动时短路 1104 if throttle() { 1105 throttled = true 1106 break 1107 } 1108 //如果没有更多可用任务,则短路。 1109 if pending() == 0 { 1110 break 1111 } 1112 //为对等机保留一大块获取。一个零可以意味着 1113 //没有更多的头可用,或者对等端已知不可用 1114 //拥有它们。 1115 request, progress, err := reserve(peer, capacity(peer)) 1116 if err != nil { 1117 return err 1118 } 1119 if progress { 1120 progressed = true 1121 } 1122 if request == nil { 1123 continue 1124 } 1125 if request.From > 0 { 1126 peer.log.Trace("Requesting new batch of data", "type", kind, "from", request.From) 1127 } else { 1128 peer.log.Trace("Requesting new batch of data", "type", kind, "count", len(request.Headers), "from", request.Headers[0].Number) 1129 } 1130 //获取块并确保任何错误都将哈希返回到队列 1131 if fetchHook != nil { 1132 fetchHook(request.Headers) 1133 } 1134 if err := fetch(peer, request); err != nil { 1135 //虽然我们可以尝试修复此错误,但实际上 1136 //意味着我们已经将一个获取任务双重分配给了一个对等方。如果那是 1137 //案例,下载器和队列的内部状态是非常错误的,所以 1138 //更好的硬崩溃和注意错误,而不是默默地累积到 1139 //更大的问题。 1140 panic(fmt.Sprintf("%v: %s fetch assignment failed", peer, kind)) 1141 } 1142 running = true 1143 } 1144 //确保我们有可供提取的对等点。如果所有同龄人都被试过 1145 //所有的失败都会引发一个错误 1146 if !progressed && !throttled && !running && len(idles) == total && pending() > 0 { 1147 return errPeersUnavailable 1148 } 1149 } 1150 } 1151 } 1152 1153 //processHeaders从输入通道获取一批检索到的头,并且 1154 //继续处理并将它们调度到头链和下载程序中 1155 //排队直到流结束或发生故障。 1156 func (d *Downloader) processHeaders(origin uint64, pivot uint64, td *big.Int) error { 1157 //保留不确定的头数以回滚 1158 rollback := []*types.Header{} 1159 defer func() { 1160 if len(rollback) > 0 { 1161 //压平收割台并将其回滚 1162 hashes := make([]common.Hash, len(rollback)) 1163 for i, header := range rollback { 1164 hashes[i] = header.Hash() 1165 } 1166 lastHeader, lastFastBlock, lastBlock := d.lightchain.CurrentHeader().Number, common.Big0, common.Big0 1167 if d.mode != LightSync { 1168 lastFastBlock = d.blockchain.CurrentFastBlock().Number() 1169 lastBlock = d.blockchain.CurrentBlock().Number() 1170 } 1171 d.lightchain.Rollback(hashes) 1172 curFastBlock, curBlock := common.Big0, common.Big0 1173 if d.mode != LightSync { 1174 curFastBlock = d.blockchain.CurrentFastBlock().Number() 1175 curBlock = d.blockchain.CurrentBlock().Number() 1176 } 1177 log.Warn("Rolled back headers", "count", len(hashes), 1178 "header", fmt.Sprintf("%d->%d", lastHeader, d.lightchain.CurrentHeader().Number), 1179 "fast", fmt.Sprintf("%d->%d", lastFastBlock, curFastBlock), 1180 "block", fmt.Sprintf("%d->%d", lastBlock, curBlock)) 1181 } 1182 }() 1183 1184 //等待处理成批的邮件头 1185 gotHeaders := false 1186 1187 for { 1188 select { 1189 case <-d.cancelCh: 1190 return errCancelHeaderProcessing 1191 1192 case headers := <-d.headerProcCh: 1193 //如果同步,则终止头处理 1194 if len(headers) == 0 { 1195 //通知所有人邮件头已完全处理 1196 for _, ch := range []chan bool{d.bodyWakeCh, d.receiptWakeCh} { 1197 select { 1198 case ch <- false: 1199 case <-d.cancelCh: 1200 } 1201 } 1202 //如果没有检索到任何头,则对等端违反了其td承诺,即 1203 //链条比我们的好。唯一的例外是如果它承诺的块 1204 //已通过其他方式进口(如fecher): 1205 // 1206 //R<remote peer>,L<local node>:都在数据块10上 1207 //R:我的11号区,然后传播到L 1208 //L:队列块11用于导入 1209 //L:注意R的头和TD比我们的要高,开始同步。 1210 //L:11号块饰面的进口 1211 //L:Sync开始,在11找到共同祖先 1212 //L:从11点开始请求新的标题(R的td更高,它必须有一些东西) 1213 //R:没什么可以给的 1214 if d.mode != LightSync { 1215 head := d.blockchain.CurrentBlock() 1216 if !gotHeaders && td.Cmp(d.blockchain.GetTd(head.Hash(), head.NumberU64())) > 0 { 1217 return errStallingPeer 1218 } 1219 } 1220 //如果同步速度快或很轻,请确保确实交付了承诺的头文件。这是 1221 //需要检测攻击者输入错误的轴然后诱饵离开的场景 1222 //传递将标记无效内容的post-pivot块。 1223 // 1224 //由于块可能仍然是 1225 //头下载完成后排队等待处理。但是,只要 1226 //同行给了我们一些有用的东西,我们已经很高兴/进步了(上面的检查)。 1227 if d.mode == FastSync || d.mode == LightSync { 1228 head := d.lightchain.CurrentHeader() 1229 if td.Cmp(d.lightchain.GetTd(head.Hash(), head.Number.Uint64())) > 0 { 1230 return errStallingPeer 1231 } 1232 } 1233 //禁用任何回滚并返回 1234 rollback = nil 1235 return nil 1236 } 1237 //否则,将头块分割成批并处理它们 1238 gotHeaders = true 1239 1240 for len(headers) > 0 { 1241 //在处理块之间发生故障时终止 1242 select { 1243 case <-d.cancelCh: 1244 return errCancelHeaderProcessing 1245 default: 1246 } 1247 //选择要导入的下一个标题块 1248 limit := maxHeadersProcess 1249 if limit > len(headers) { 1250 limit = len(headers) 1251 } 1252 chunk := headers[:limit] 1253 1254 //如果只同步头,请立即验证块。 1255 if d.mode == FastSync || d.mode == LightSync { 1256 //收集尚未确定的邮件头,将其标记为不确定邮件头 1257 unknown := make([]*types.Header, 0, len(headers)) 1258 for _, header := range chunk { 1259 if !d.lightchain.HasHeader(header.Hash(), header.Number.Uint64()) { 1260 unknown = append(unknown, header) 1261 } 1262 } 1263 //如果我们要导入纯头,请根据它们的最近性进行验证。 1264 frequency := fsHeaderCheckFrequency 1265 if chunk[len(chunk)-1].Number.Uint64()+uint64(fsHeaderForceVerify) > pivot { 1266 frequency = 1 1267 } 1268 if n, err := d.lightchain.InsertHeaderChain(chunk, frequency); err != nil { 1269 //如果插入了一些头,请将它们也添加到回滚列表中。 1270 if n > 0 { 1271 rollback = append(rollback, chunk[:n]...) 1272 } 1273 log.Debug("Invalid header encountered", "number", chunk[n].Number, "hash", chunk[n].Hash(), "err", err) 1274 return errInvalidChain 1275 } 1276 //所有验证通过,存储新发现的不确定头 1277 rollback = append(rollback, unknown...) 1278 if len(rollback) > fsHeaderSafetyNet { 1279 rollback = append(rollback[:0], rollback[len(rollback)-fsHeaderSafetyNet:]...) 1280 } 1281 } 1282 //除非我们在做轻链,否则请为相关的内容检索安排标题。 1283 if d.mode == FullSync || d.mode == FastSync { 1284 //如果达到了允许的挂起头的数目,请暂停一点。 1285 for d.queue.PendingBlocks() >= maxQueuedHeaders || d.queue.PendingReceipts() >= maxQueuedHeaders { 1286 select { 1287 case <-d.cancelCh: 1288 return errCancelHeaderProcessing 1289 case <-time.After(time.Second): 1290 } 1291 } 1292 //否则插入标题进行内容检索 1293 inserts := d.queue.Schedule(chunk, origin) 1294 if len(inserts) != len(chunk) { 1295 log.Debug("Stale headers") 1296 return errBadPeer 1297 } 1298 } 1299 headers = headers[limit:] 1300 origin += uint64(limit) 1301 } 1302 1303 //更新我们知道的最高块号,如果找到更高的块号。 1304 d.syncStatsLock.Lock() 1305 if d.syncStatsChainHeight < origin { 1306 d.syncStatsChainHeight = origin - 1 1307 } 1308 d.syncStatsLock.Unlock() 1309 1310 //向内容下载者发出新任务可用性的信号 1311 for _, ch := range []chan bool{d.bodyWakeCh, d.receiptWakeCh} { 1312 select { 1313 case ch <- true: 1314 default: 1315 } 1316 } 1317 } 1318 } 1319 } 1320 1321 //processfullsyncContent从队列中获取结果并将其导入到链中。 1322 func (d *Downloader) processFullSyncContent() error { 1323 for { 1324 results := d.queue.Results(true) 1325 if len(results) == 0 { 1326 return nil 1327 } 1328 if d.chainInsertHook != nil { 1329 d.chainInsertHook(results) 1330 } 1331 if err := d.importBlockResults(results); err != nil { 1332 return err 1333 } 1334 } 1335 } 1336 1337 func (d *Downloader) importBlockResults(results []*fetchResult) error { 1338 //检查是否有任何提前终止请求 1339 if len(results) == 0 { 1340 return nil 1341 } 1342 select { 1343 case <-d.quitCh: 1344 return errCancelContentProcessing 1345 default: 1346 } 1347 //检索要导入的一批结果 1348 first, last := results[0].Header, results[len(results)-1].Header 1349 log.Debug("Inserting downloaded chain", "items", len(results), 1350 "firstnum", first.Number, "firsthash", first.Hash(), 1351 "lastnum", last.Number, "lasthash", last.Hash(), 1352 ) 1353 blocks := make([]*types.Block, len(results)) 1354 for i, result := range results { 1355 blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles) 1356 } 1357 if index, err := d.blockchain.InsertChain(blocks); err != nil { 1358 log.Debug("Downloaded item processing failed", "number", results[index].Header.Number, "hash", results[index].Header.Hash(), "err", err) 1359 return errInvalidChain 1360 } 1361 return nil 1362 } 1363 1364 //processFastSyncContent从队列获取结果并将其写入 1365 //数据库。它还控制枢轴块状态节点的同步。 1366 func (d *Downloader) processFastSyncContent(latest *types.Header) error { 1367 //开始同步报告的头块的状态。这应该让我们 1368 //透视图块的状态。 1369 stateSync := d.syncState(latest.Root) 1370 defer stateSync.Cancel() 1371 go func() { 1372 if err := stateSync.Wait(); err != nil && err != errCancelStateFetch { 1373 d.queue.Close() //唤醒等待结果 1374 } 1375 }() 1376 //找出理想的轴块。注意,如果 1377 //同步需要足够长的时间,链头才能显著移动。 1378 pivot := uint64(0) 1379 if height := latest.Number.Uint64(); height > uint64(fsMinFullBlocks) { 1380 pivot = height - uint64(fsMinFullBlocks) 1381 } 1382 //为了适应移动的轴点,跟踪轴块,然后 1383 //单独累计下载结果。 1384 var ( 1385 oldPivot *fetchResult //锁定在轴块中,可能最终更改 1386 oldTail []*fetchResult //在透视之后下载的内容 1387 ) 1388 for { 1389 //等待下一批下载的数据可用,如果 1390 //布洛克变僵了,移动门柱 1391 results := d.queue.Results(oldPivot == nil) //如果我们不监视数据透视过时,请阻止 1392 if len(results) == 0 { 1393 //如果透视同步完成,则停止 1394 if oldPivot == nil { 1395 return stateSync.Cancel() 1396 } 1397 //如果同步失败,请停止 1398 select { 1399 case <-d.cancelCh: 1400 return stateSync.Cancel() 1401 default: 1402 } 1403 } 1404 if d.chainInsertHook != nil { 1405 d.chainInsertHook(results) 1406 } 1407 if oldPivot != nil { 1408 results = append(append([]*fetchResult{oldPivot}, oldTail...), results...) 1409 } 1410 //围绕轴块拆分并通过快速/完全同步处理两侧 1411 if atomic.LoadInt32(&d.committed) == 0 { 1412 latest = results[len(results)-1].Header 1413 if height := latest.Number.Uint64(); height > pivot+2*uint64(fsMinFullBlocks) { 1414 log.Warn("Pivot became stale, moving", "old", pivot, "new", height-uint64(fsMinFullBlocks)) 1415 pivot = height - uint64(fsMinFullBlocks) 1416 } 1417 } 1418 P, beforeP, afterP := splitAroundPivot(pivot, results) 1419 if err := d.commitFastSyncData(beforeP, stateSync); err != nil { 1420 return err 1421 } 1422 if P != nil { 1423 //如果找到新的数据透视块,请取消旧的状态检索并重新启动 1424 if oldPivot != P { 1425 stateSync.Cancel() 1426 1427 stateSync = d.syncState(P.Header.Root) 1428 defer stateSync.Cancel() 1429 go func() { 1430 if err := stateSync.Wait(); err != nil && err != errCancelStateFetch { 1431 d.queue.Close() //唤醒等待结果 1432 } 1433 }() 1434 oldPivot = P 1435 } 1436 //等待完成,偶尔检查数据透视是否过时 1437 select { 1438 case <-stateSync.done: 1439 if stateSync.err != nil { 1440 return stateSync.err 1441 } 1442 if err := d.commitPivotBlock(P); err != nil { 1443 return err 1444 } 1445 oldPivot = nil 1446 1447 case <-time.After(time.Second): 1448 oldTail = afterP 1449 continue 1450 } 1451 } 1452 //快速同步完成,透视提交完成,完全导入 1453 if err := d.importBlockResults(afterP); err != nil { 1454 return err 1455 } 1456 } 1457 } 1458 1459 func splitAroundPivot(pivot uint64, results []*fetchResult) (p *fetchResult, before, after []*fetchResult) { 1460 for _, result := range results { 1461 num := result.Header.Number.Uint64() 1462 switch { 1463 case num < pivot: 1464 before = append(before, result) 1465 case num == pivot: 1466 p = result 1467 default: 1468 after = append(after, result) 1469 } 1470 } 1471 return p, before, after 1472 } 1473 1474 func (d *Downloader) commitFastSyncData(results []*fetchResult, stateSync *stateSync) error { 1475 //检查是否有任何提前终止请求 1476 if len(results) == 0 { 1477 return nil 1478 } 1479 select { 1480 case <-d.quitCh: 1481 return errCancelContentProcessing 1482 case <-stateSync.done: 1483 if err := stateSync.Wait(); err != nil { 1484 return err 1485 } 1486 default: 1487 } 1488 //检索要导入的一批结果 1489 first, last := results[0].Header, results[len(results)-1].Header 1490 log.Debug("Inserting fast-sync blocks", "items", len(results), 1491 "firstnum", first.Number, "firsthash", first.Hash(), 1492 "lastnumn", last.Number, "lasthash", last.Hash(), 1493 ) 1494 blocks := make([]*types.Block, len(results)) 1495 receipts := make([]types.Receipts, len(results)) 1496 for i, result := range results { 1497 blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles) 1498 receipts[i] = result.Receipts 1499 } 1500 if index, err := d.blockchain.InsertReceiptChain(blocks, receipts); err != nil { 1501 log.Debug("Downloaded item processing failed", "number", results[index].Header.Number, "hash", results[index].Header.Hash(), "err", err) 1502 return errInvalidChain 1503 } 1504 return nil 1505 } 1506 1507 func (d *Downloader) commitPivotBlock(result *fetchResult) error { 1508 block := types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles) 1509 log.Debug("Committing fast sync pivot as new head", "number", block.Number(), "hash", block.Hash()) 1510 if _, err := d.blockchain.InsertReceiptChain([]*types.Block{block}, []types.Receipts{result.Receipts}); err != nil { 1511 return err 1512 } 1513 if err := d.blockchain.FastSyncCommitHead(block.Hash()); err != nil { 1514 return err 1515 } 1516 atomic.StoreInt32(&d.committed, 1) 1517 return nil 1518 } 1519 1520 //DeliverHeaders插入从远程服务器接收的新批块头 1521 //进入下载计划。 1522 func (d *Downloader) DeliverHeaders(id string, headers []*types.Header) (err error) { 1523 return d.deliver(id, d.headerCh, &headerPack{id, headers}, headerInMeter, headerDropMeter) 1524 } 1525 1526 //deliverbodies注入从远程节点接收的新批块体。 1527 func (d *Downloader) DeliverBodies(id string, transactions [][]*types.Transaction, uncles [][]*types.Header) (err error) { 1528 return d.deliver(id, d.bodyCh, &bodyPack{id, transactions, uncles}, bodyInMeter, bodyDropMeter) 1529 } 1530 1531 //DeliverReceipts插入从远程节点接收的新一批收据。 1532 func (d *Downloader) DeliverReceipts(id string, receipts [][]*types.Receipt) (err error) { 1533 return d.deliver(id, d.receiptCh, &receiptPack{id, receipts}, receiptInMeter, receiptDropMeter) 1534 } 1535 1536 //DeliverNodeData注入从远程节点接收到的新一批节点状态数据。 1537 func (d *Downloader) DeliverNodeData(id string, data [][]byte) (err error) { 1538 return d.deliver(id, d.stateCh, &statePack{id, data}, stateInMeter, stateDropMeter) 1539 } 1540 1541 //deliver注入从远程节点接收的新批数据。 1542 func (d *Downloader) deliver(id string, destCh chan dataPack, packet dataPack, inMeter, dropMeter metrics.Meter) (err error) { 1543 //更新好交付和失败交付的交付指标 1544 inMeter.Mark(int64(packet.Items())) 1545 defer func() { 1546 if err != nil { 1547 dropMeter.Mark(int64(packet.Items())) 1548 } 1549 }() 1550 //如果在排队时取消同步,则传递或中止 1551 d.cancelLock.RLock() 1552 cancel := d.cancelCh 1553 d.cancelLock.RUnlock() 1554 if cancel == nil { 1555 return errNoSyncActive 1556 } 1557 select { 1558 case destCh <- packet: 1559 return nil 1560 case <-cancel: 1561 return errNoSyncActive 1562 } 1563 } 1564 1565 //Qostener是服务质量优化循环,偶尔收集 1566 //对等延迟统计并更新估计的请求往返时间。 1567 func (d *Downloader) qosTuner() { 1568 for { 1569 //检索当前中间RTT并集成到以前的目标RTT中 1570 rtt := time.Duration((1-qosTuningImpact)*float64(atomic.LoadUint64(&d.rttEstimate)) + qosTuningImpact*float64(d.peers.medianRTT())) 1571 atomic.StoreUint64(&d.rttEstimate, uint64(rtt)) 1572 1573 //通过了一个新的RTT周期,增加了我们对估计的RTT的信心。 1574 conf := atomic.LoadUint64(&d.rttConfidence) 1575 conf = conf + (1000000-conf)/2 1576 atomic.StoreUint64(&d.rttConfidence, conf) 1577 1578 //记录新的QoS值并休眠到下一个RTT 1579 log.Debug("Recalculated downloader QoS values", "rtt", rtt, "confidence", float64(conf)/1000000.0, "ttl", d.requestTTL()) 1580 select { 1581 case <-d.quitCh: 1582 return 1583 case <-time.After(rtt): 1584 } 1585 } 1586 } 1587 1588 //QosReduceConfidence是指当新对等加入下载程序时调用的。 1589 //对等集,需要降低我们对QoS估计的信心。 1590 func (d *Downloader) qosReduceConfidence() { 1591 //如果我们只有一个同伴,那么信心总是1 1592 peers := uint64(d.peers.Len()) 1593 if peers == 0 { 1594 //确保对等连接竞赛不会让我们措手不及 1595 return 1596 } 1597 if peers == 1 { 1598 atomic.StoreUint64(&d.rttConfidence, 1000000) 1599 return 1600 } 1601 //如果我们有很多同龄人,不要放弃信心) 1602 if peers >= uint64(qosConfidenceCap) { 1603 return 1604 } 1605 //否则,降低置信系数 1606 conf := atomic.LoadUint64(&d.rttConfidence) * (peers - 1) / peers 1607 if float64(conf)/1000000 < rttMinConfidence { 1608 conf = uint64(rttMinConfidence * 1000000) 1609 } 1610 atomic.StoreUint64(&d.rttConfidence, conf) 1611 1612 rtt := time.Duration(atomic.LoadUint64(&d.rttEstimate)) 1613 log.Debug("Relaxed downloader QoS values", "rtt", rtt, "confidence", float64(conf)/1000000.0, "ttl", d.requestTTL()) 1614 } 1615 1616 //requestrtt返回下载请求的当前目标往返时间 1617 //完成。 1618 // 1619 //注意,返回的RTT是实际估计RTT的.9。原因是 1620 //下载程序尝试使查询适应RTT,因此多个RTT值可以 1621 //适应,但较小的是首选(更稳定的下载流)。 1622 func (d *Downloader) requestRTT() time.Duration { 1623 return time.Duration(atomic.LoadUint64(&d.rttEstimate)) * 9 / 10 1624 } 1625 1626 //REQUESTTL返回单个下载请求的当前超时允许值 1627 //在…之下完成。 1628 func (d *Downloader) requestTTL() time.Duration { 1629 var ( 1630 rtt = time.Duration(atomic.LoadUint64(&d.rttEstimate)) 1631 conf = float64(atomic.LoadUint64(&d.rttConfidence)) / 1000000.0 1632 ) 1633 ttl := time.Duration(ttlScaling) * time.Duration(float64(rtt)/conf) 1634 if ttl > ttlLimit { 1635 ttl = ttlLimit 1636 } 1637 return ttl 1638 } 1639