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