github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/eth/fetcher/fetcher.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //版权所有2015 Go Ethereum作者
    10  //此文件是Go以太坊库的一部分。
    11  //
    12  //Go-Ethereum库是免费软件:您可以重新分发它和/或修改
    13  //根据GNU发布的较低通用公共许可证的条款
    14  //自由软件基金会,或者许可证的第3版,或者
    15  //(由您选择)任何更高版本。
    16  //
    17  //Go以太坊图书馆的发行目的是希望它会有用,
    18  //但没有任何保证;甚至没有
    19  //适销性或特定用途的适用性。见
    20  //GNU较低的通用公共许可证,了解更多详细信息。
    21  //
    22  //你应该收到一份GNU较低级别的公共许可证副本
    23  //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。
    24  
    25  //包获取器包含基于块通知的同步。
    26  package fetcher
    27  
    28  import (
    29  	"errors"
    30  	"math/rand"
    31  	"time"
    32  
    33  	"github.com/ethereum/go-ethereum/common"
    34  	"github.com/ethereum/go-ethereum/consensus"
    35  	"github.com/ethereum/go-ethereum/core/types"
    36  	"github.com/ethereum/go-ethereum/log"
    37  	"gopkg.in/karalabe/cookiejar.v2/collections/prque"
    38  )
    39  
    40  
    41  const (
    42  arriveTimeout = 500 * time.Millisecond //明确请求公告块之前的时间裕度
    43  gatherSlack   = 100 * time.Millisecond //用于整理带有回迁的几乎过期的公告的间隔
    44  fetchTimeout  = 5 * time.Second        //返回显式请求块的最长分配时间
    45  maxUncleDist  = 7                      //距链头的最大允许后退距离
    46  maxQueueDist  = 32                     //链头到队列的最大允许距离
    47  hashLimit     = 256                    //对等机可能已宣布的唯一块的最大数目
    48  blockLimit    = 64                     //对等端传递的唯一块的最大数目
    49  )
    50  
    51  var (
    52  	errTerminated = errors.New("terminated")
    53  )
    54  
    55  //blockretrievalfn是用于从本地链检索块的回调类型。
    56  type blockRetrievalFn func(common.Hash) *types.Block
    57  
    58  //HeaderRequesterFn是用于发送头检索请求的回调类型。
    59  type headerRequesterFn func(common.Hash) error
    60  
    61  //BodyRequesterFn是用于发送正文检索请求的回调类型。
    62  type bodyRequesterFn func([]common.Hash) error
    63  
    64  //headerverifierfn是一种回调类型,用于验证块头的快速传播。
    65  type headerVerifierFn func(header *types.Header) error
    66  
    67  //BlockBroadcasterFn是一种回调类型,用于向连接的对等端广播块。
    68  type blockBroadcasterFn func(block *types.Block, propagate bool)
    69  
    70  //chainheightfn是用于检索当前链高度的回调类型。
    71  type chainHeightFn func() uint64
    72  
    73  //chaininsertfn是一种回调类型,用于将一批块插入本地链。
    74  type chainInsertFn func(types.Blocks) (int, error)
    75  
    76  //peerDropFn是一种回调类型,用于删除被检测为恶意的对等机。
    77  type peerDropFn func(id string)
    78  
    79  //Announce是哈希通知,通知中新块的可用性
    80  //网络。
    81  type announce struct {
    82  hash   common.Hash   //正在公布的块的哈希值
    83  number uint64        //正在公布的块的数目(0=未知旧协议)
    84  header *types.Header //部分重新组装的块头(新协议)
    85  time   time.Time     //公告的时间戳
    86  
    87  origin string //发出通知的对等方的标识符
    88  
    89  fetchHeader headerRequesterFn //获取函数以检索已公告块的头
    90  fetchBodies bodyRequesterFn   //获取函数以检索已公告块的主体
    91  }
    92  
    93  //HeaderFilterTask表示需要获取器筛选的一批头。
    94  type headerFilterTask struct {
    95  peer    string          //块头的源对等
    96  headers []*types.Header //要筛选的标题集合
    97  time    time.Time       //收割台到达时间
    98  }
    99  
   100  //BodyFilterTask表示一批块体(事务和叔叔)
   101  //需要回迁过滤。
   102  type bodyFilterTask struct {
   103  peer         string                 //阻塞体的源对等体
   104  transactions [][]*types.Transaction //每个块体事务的集合
   105  uncles       [][]*types.Header      //每个区块主体的叔叔集合
   106  time         time.Time              //块内容物到达时间
   107  }
   108  
   109  //Inject表示计划导入操作。
   110  type inject struct {
   111  	origin string
   112  	block  *types.Block
   113  }
   114  
   115  //Fetcher负责从不同的对等方收集块通知
   116  //并安排它们进行检索。
   117  type Fetcher struct {
   118  //各种事件通道
   119  	notify chan *announce
   120  	inject chan *inject
   121  
   122  	blockFilter  chan chan []*types.Block
   123  	headerFilter chan chan *headerFilterTask
   124  	bodyFilter   chan chan *bodyFilterTask
   125  
   126  	done chan common.Hash
   127  	quit chan struct{}
   128  
   129  //宣布国
   130  announces  map[string]int              //每对等端宣布计数以防止内存耗尽
   131  announced  map[common.Hash][]*announce //已通知块,计划获取
   132  fetching   map[common.Hash]*announce   //公告块,当前正在获取
   133  fetched    map[common.Hash][]*announce //已提取头的块,计划用于正文检索
   134  completing map[common.Hash]*announce   //带有标题的块,当前主体正在完成
   135  
   136  //块缓存
   137  queue  *prque.Prque            //包含导入操作的队列(已排序块号)
   138  queues map[string]int          //每对等块计数以防止内存耗尽
   139  queued map[common.Hash]*inject //已排队的块集(用于消除导入的重复数据)
   140  
   141  //回调
   142  getBlock       blockRetrievalFn   //从本地链中检索块
   143  verifyHeader   headerVerifierFn   //检查块的头是否具有有效的工作证明
   144  broadcastBlock blockBroadcasterFn //向连接的对等端广播块
   145  chainHeight    chainHeightFn      //检索当前链的高度
   146  insertChain    chainInsertFn      //向链中注入一批块
   147  dropPeer       peerDropFn         //因行为不端而丢掉一个同伴
   148  
   149  //测试钩
   150  announceChangeHook func(common.Hash, bool) //方法在从公告列表中添加或删除哈希时调用
   151  queueChangeHook    func(common.Hash, bool) //从导入队列添加或删除块时要调用的方法
   152  fetchingHook       func([]common.Hash)     //启动块(eth/61)或头(eth/62)提取时调用的方法
   153  completingHook     func([]common.Hash)     //启动块体提取时调用的方法(eth/62)
   154  importedHook       func(*types.Block)      //成功块导入时调用的方法(ETH/61和ETH/62)
   155  }
   156  
   157  //新建创建一个块获取器,以基于哈希通知检索块。
   158  func New(getBlock blockRetrievalFn, verifyHeader headerVerifierFn, broadcastBlock blockBroadcasterFn, chainHeight chainHeightFn, insertChain chainInsertFn, dropPeer peerDropFn) *Fetcher {
   159  	return &Fetcher{
   160  		notify:         make(chan *announce),
   161  		inject:         make(chan *inject),
   162  		blockFilter:    make(chan chan []*types.Block),
   163  		headerFilter:   make(chan chan *headerFilterTask),
   164  		bodyFilter:     make(chan chan *bodyFilterTask),
   165  		done:           make(chan common.Hash),
   166  		quit:           make(chan struct{}),
   167  		announces:      make(map[string]int),
   168  		announced:      make(map[common.Hash][]*announce),
   169  		fetching:       make(map[common.Hash]*announce),
   170  		fetched:        make(map[common.Hash][]*announce),
   171  		completing:     make(map[common.Hash]*announce),
   172  		queue:          prque.New(),
   173  		queues:         make(map[string]int),
   174  		queued:         make(map[common.Hash]*inject),
   175  		getBlock:       getBlock,
   176  		verifyHeader:   verifyHeader,
   177  		broadcastBlock: broadcastBlock,
   178  		chainHeight:    chainHeight,
   179  		insertChain:    insertChain,
   180  		dropPeer:       dropPeer,
   181  	}
   182  }
   183  
   184  //启动基于公告的同步器,接受和处理
   185  //哈希通知和块提取,直到请求终止。
   186  func (f *Fetcher) Start() {
   187  	go f.loop()
   188  }
   189  
   190  //停止终止基于公告的同步器,取消所有挂起
   191  //操作。
   192  func (f *Fetcher) Stop() {
   193  	close(f.quit)
   194  }
   195  
   196  //通知将通知获取程序新块的潜在可用性
   197  //网络。
   198  func (f *Fetcher) Notify(peer string, hash common.Hash, number uint64, time time.Time,
   199  	headerFetcher headerRequesterFn, bodyFetcher bodyRequesterFn) error {
   200  	block := &announce{
   201  		hash:        hash,
   202  		number:      number,
   203  		time:        time,
   204  		origin:      peer,
   205  		fetchHeader: headerFetcher,
   206  		fetchBodies: bodyFetcher,
   207  	}
   208  	select {
   209  	case f.notify <- block:
   210  		return nil
   211  	case <-f.quit:
   212  		return errTerminated
   213  	}
   214  }
   215  
   216  //排队试图填补获取程序未来导入队列的空白。
   217  func (f *Fetcher) Enqueue(peer string, block *types.Block) error {
   218  	op := &inject{
   219  		origin: peer,
   220  		block:  block,
   221  	}
   222  	select {
   223  	case f.inject <- op:
   224  		return nil
   225  	case <-f.quit:
   226  		return errTerminated
   227  	}
   228  }
   229  
   230  //filterheaders提取提取提取程序显式请求的所有头,
   231  //退回那些应该以不同方式处理的。
   232  func (f *Fetcher) FilterHeaders(peer string, headers []*types.Header, time time.Time) []*types.Header {
   233  	log.Trace("Filtering headers", "peer", peer, "headers", len(headers))
   234  
   235  //将过滤通道发送到获取器
   236  	filter := make(chan *headerFilterTask)
   237  
   238  	select {
   239  	case f.headerFilter <- filter:
   240  	case <-f.quit:
   241  		return nil
   242  	}
   243  //请求筛选头列表
   244  	select {
   245  	case filter <- &headerFilterTask{peer: peer, headers: headers, time: time}:
   246  	case <-f.quit:
   247  		return nil
   248  	}
   249  //检索筛选后剩余的邮件头
   250  	select {
   251  	case task := <-filter:
   252  		return task.headers
   253  	case <-f.quit:
   254  		return nil
   255  	}
   256  }
   257  
   258  //filterbody提取由
   259  //回迁者,返回那些应该以不同方式处理的。
   260  func (f *Fetcher) FilterBodies(peer string, transactions [][]*types.Transaction, uncles [][]*types.Header, time time.Time) ([][]*types.Transaction, [][]*types.Header) {
   261  	log.Trace("Filtering bodies", "peer", peer, "txs", len(transactions), "uncles", len(uncles))
   262  
   263  //将过滤通道发送到获取器
   264  	filter := make(chan *bodyFilterTask)
   265  
   266  	select {
   267  	case f.bodyFilter <- filter:
   268  	case <-f.quit:
   269  		return nil, nil
   270  	}
   271  //请求对身体清单的过滤
   272  	select {
   273  	case filter <- &bodyFilterTask{peer: peer, transactions: transactions, uncles: uncles, time: time}:
   274  	case <-f.quit:
   275  		return nil, nil
   276  	}
   277  //检索过滤后剩余的主体
   278  	select {
   279  	case task := <-filter:
   280  		return task.transactions, task.uncles
   281  	case <-f.quit:
   282  		return nil, nil
   283  	}
   284  }
   285  
   286  //循环是主获取循环,检查和处理各种通知
   287  //事件。
   288  func (f *Fetcher) loop() {
   289  //迭代块提取,直到请求退出
   290  	fetchTimer := time.NewTimer(0)
   291  	completeTimer := time.NewTimer(0)
   292  
   293  	for {
   294  //清除所有过期的块提取
   295  		for hash, announce := range f.fetching {
   296  			if time.Since(announce.time) > fetchTimeout {
   297  				f.forgetHash(hash)
   298  			}
   299  		}
   300  //导入任何可能适合的排队块
   301  		height := f.chainHeight()
   302  		for !f.queue.Empty() {
   303  			op := f.queue.PopItem().(*inject)
   304  			hash := op.block.Hash()
   305  			if f.queueChangeHook != nil {
   306  				f.queueChangeHook(hash, false)
   307  			}
   308  //如果链条或相位过高,请稍后继续
   309  			number := op.block.NumberU64()
   310  			if number > height+1 {
   311  				f.queue.Push(op, -float32(number))
   312  				if f.queueChangeHook != nil {
   313  					f.queueChangeHook(hash, true)
   314  				}
   315  				break
   316  			}
   317  //否则,如果是新鲜的,还是未知的,请尝试导入
   318  			if number+maxUncleDist < height || f.getBlock(hash) != nil {
   319  				f.forgetBlock(hash)
   320  				continue
   321  			}
   322  			f.insert(op.origin, op.block)
   323  		}
   324  //等待外部事件发生
   325  		select {
   326  		case <-f.quit:
   327  //取数器终止,中止所有操作
   328  			return
   329  
   330  		case notification := <-f.notify:
   331  //宣布封锁,确保同伴没有给我们注射药物。
   332  			propAnnounceInMeter.Mark(1)
   333  
   334  			count := f.announces[notification.origin] + 1
   335  			if count > hashLimit {
   336  				log.Debug("Peer exceeded outstanding announces", "peer", notification.origin, "limit", hashLimit)
   337  				propAnnounceDOSMeter.Mark(1)
   338  				break
   339  			}
   340  //如果我们有一个有效的块号,检查它是否有潜在的用处
   341  			if notification.number > 0 {
   342  				if dist := int64(notification.number) - int64(f.chainHeight()); dist < -maxUncleDist || dist > maxQueueDist {
   343  					log.Debug("Peer discarded announcement", "peer", notification.origin, "number", notification.number, "hash", notification.hash, "distance", dist)
   344  					propAnnounceDropMeter.Mark(1)
   345  					break
   346  				}
   347  			}
   348  //一切都很好,如果块尚未下载,请安排公告
   349  			if _, ok := f.fetching[notification.hash]; ok {
   350  				break
   351  			}
   352  			if _, ok := f.completing[notification.hash]; ok {
   353  				break
   354  			}
   355  			f.announces[notification.origin] = count
   356  			f.announced[notification.hash] = append(f.announced[notification.hash], notification)
   357  			if f.announceChangeHook != nil && len(f.announced[notification.hash]) == 1 {
   358  				f.announceChangeHook(notification.hash, true)
   359  			}
   360  			if len(f.announced) == 1 {
   361  				f.rescheduleFetch(fetchTimer)
   362  			}
   363  
   364  		case op := <-f.inject:
   365  //已请求直接插入块,请尝试填充所有挂起的空白。
   366  			propBroadcastInMeter.Mark(1)
   367  			f.enqueue(op.origin, op.block)
   368  
   369  		case hash := <-f.done:
   370  //挂起的导入已完成,请删除通知的所有跟踪
   371  			f.forgetHash(hash)
   372  			f.forgetBlock(hash)
   373  
   374  		case <-fetchTimer.C:
   375  //至少一个块的计时器用完,检查是否需要检索
   376  			request := make(map[string][]common.Hash)
   377  
   378  			for hash, announces := range f.announced {
   379  				if time.Since(announces[0].time) > arriveTimeout-gatherSlack {
   380  //选择要检索的随机对等机,重置所有其他对等机
   381  					announce := announces[rand.Intn(len(announces))]
   382  					f.forgetHash(hash)
   383  
   384  //如果块仍未到达,请排队取件
   385  					if f.getBlock(hash) == nil {
   386  						request[announce.origin] = append(request[announce.origin], hash)
   387  						f.fetching[hash] = announce
   388  					}
   389  				}
   390  			}
   391  //发送所有块头请求
   392  			for peer, hashes := range request {
   393  				log.Trace("Fetching scheduled headers", "peer", peer, "list", hashes)
   394  
   395  //在新线程上创建fetch和schedule的闭包
   396  				fetchHeader, hashes := f.fetching[hashes[0]].fetchHeader, hashes
   397  				go func() {
   398  					if f.fetchingHook != nil {
   399  						f.fetchingHook(hashes)
   400  					}
   401  					for _, hash := range hashes {
   402  						headerFetchMeter.Mark(1)
   403  fetchHeader(hash) //次优,但协议不允许批头检索
   404  					}
   405  				}()
   406  			}
   407  //如果块仍处于挂起状态,则计划下一次提取
   408  			f.rescheduleFetch(fetchTimer)
   409  
   410  		case <-completeTimer.C:
   411  //至少有一个头的计时器用完了,检索所有内容
   412  			request := make(map[string][]common.Hash)
   413  
   414  			for hash, announces := range f.fetched {
   415  //选择要检索的随机对等机,重置所有其他对等机
   416  				announce := announces[rand.Intn(len(announces))]
   417  				f.forgetHash(hash)
   418  
   419  //如果块仍未到达,请排队等待完成
   420  				if f.getBlock(hash) == nil {
   421  					request[announce.origin] = append(request[announce.origin], hash)
   422  					f.completing[hash] = announce
   423  				}
   424  			}
   425  //发送所有块体请求
   426  			for peer, hashes := range request {
   427  				log.Trace("Fetching scheduled bodies", "peer", peer, "list", hashes)
   428  
   429  //在新线程上创建fetch和schedule的闭包
   430  				if f.completingHook != nil {
   431  					f.completingHook(hashes)
   432  				}
   433  				bodyFetchMeter.Mark(int64(len(hashes)))
   434  				go f.completing[hashes[0]].fetchBodies(hashes)
   435  			}
   436  //如果块仍处于挂起状态,则计划下一次提取
   437  			f.rescheduleComplete(completeTimer)
   438  
   439  		case filter := <-f.headerFilter:
   440  //头从远程对等机到达。提取那些明确的
   441  //由提取者请求,并返回所有其他内容,以便交付
   442  //系统的其他部分。
   443  			var task *headerFilterTask
   444  			select {
   445  			case task = <-filter:
   446  			case <-f.quit:
   447  				return
   448  			}
   449  			headerFilterInMeter.Mark(int64(len(task.headers)))
   450  
   451  //将一批报头拆分为未知的报文(返回给呼叫者),
   452  //已知的不完整块(需要检索主体)和完整块。
   453  			unknown, incomplete, complete := []*types.Header{}, []*announce{}, []*types.Block{}
   454  			for _, header := range task.headers {
   455  				hash := header.Hash()
   456  
   457  //过滤器从其他同步算法中获取请求的头
   458  				if announce := f.fetching[hash]; announce != nil && announce.origin == task.peer && f.fetched[hash] == nil && f.completing[hash] == nil && f.queued[hash] == nil {
   459  //如果交付的报头与承诺的号码不匹配,请删除播音员
   460  					if header.Number.Uint64() != announce.number {
   461  						log.Trace("Invalid block number fetched", "peer", announce.origin, "hash", header.Hash(), "announced", announce.number, "provided", header.Number)
   462  						f.dropPeer(announce.origin)
   463  						f.forgetHash(hash)
   464  						continue
   465  					}
   466  //仅在不通过其他方式进口时保留
   467  					if f.getBlock(hash) == nil {
   468  						announce.header = header
   469  						announce.time = task.time
   470  
   471  //如果块为空(仅限头段),则对最终导入队列短路
   472  						if header.TxHash == types.DeriveSha(types.Transactions{}) && header.UncleHash == types.CalcUncleHash([]*types.Header{}) {
   473  							log.Trace("Block empty, skipping body retrieval", "peer", announce.origin, "number", header.Number, "hash", header.Hash())
   474  
   475  							block := types.NewBlockWithHeader(header)
   476  							block.ReceivedAt = task.time
   477  
   478  							complete = append(complete, block)
   479  							f.completing[hash] = announce
   480  							continue
   481  						}
   482  //否则添加到需要完成的块列表中
   483  						incomplete = append(incomplete, announce)
   484  					} else {
   485  						log.Trace("Block already imported, discarding header", "peer", announce.origin, "number", header.Number, "hash", header.Hash())
   486  						f.forgetHash(hash)
   487  					}
   488  				} else {
   489  //Fetcher不知道这一点,添加到返回列表
   490  					unknown = append(unknown, header)
   491  				}
   492  			}
   493  			headerFilterOutMeter.Mark(int64(len(unknown)))
   494  			select {
   495  			case filter <- &headerFilterTask{headers: unknown, time: task.time}:
   496  			case <-f.quit:
   497  				return
   498  			}
   499  //安排检索到的邮件头的正文完成时间
   500  			for _, announce := range incomplete {
   501  				hash := announce.header.Hash()
   502  				if _, ok := f.completing[hash]; ok {
   503  					continue
   504  				}
   505  				f.fetched[hash] = append(f.fetched[hash], announce)
   506  				if len(f.fetched) == 1 {
   507  					f.rescheduleComplete(completeTimer)
   508  				}
   509  			}
   510  //为导入计划仅标题块
   511  			for _, block := range complete {
   512  				if announce := f.completing[block.Hash()]; announce != nil {
   513  					f.enqueue(announce.origin, block)
   514  				}
   515  			}
   516  
   517  		case filter := <-f.bodyFilter:
   518  //块体到达,提取任何显式请求的块,返回其余的
   519  			var task *bodyFilterTask
   520  			select {
   521  			case task = <-filter:
   522  			case <-f.quit:
   523  				return
   524  			}
   525  			bodyFilterInMeter.Mark(int64(len(task.transactions)))
   526  
   527  			blocks := []*types.Block{}
   528  			for i := 0; i < len(task.transactions) && i < len(task.uncles); i++ {
   529  //将主体与任何可能的完成请求匹配
   530  				matched := false
   531  
   532  				for hash, announce := range f.completing {
   533  					if f.queued[hash] == nil {
   534  						txnHash := types.DeriveSha(types.Transactions(task.transactions[i]))
   535  						uncleHash := types.CalcUncleHash(task.uncles[i])
   536  
   537  						if txnHash == announce.header.TxHash && uncleHash == announce.header.UncleHash && announce.origin == task.peer {
   538  //标记匹配的车身,如果仍然未知,则重新装配
   539  							matched = true
   540  
   541  							if f.getBlock(hash) == nil {
   542  								block := types.NewBlockWithHeader(announce.header).WithBody(task.transactions[i], task.uncles[i])
   543  								block.ReceivedAt = task.time
   544  
   545  								blocks = append(blocks, block)
   546  							} else {
   547  								f.forgetHash(hash)
   548  							}
   549  						}
   550  					}
   551  				}
   552  				if matched {
   553  					task.transactions = append(task.transactions[:i], task.transactions[i+1:]...)
   554  					task.uncles = append(task.uncles[:i], task.uncles[i+1:]...)
   555  					i--
   556  					continue
   557  				}
   558  			}
   559  
   560  			bodyFilterOutMeter.Mark(int64(len(task.transactions)))
   561  			select {
   562  			case filter <- task:
   563  			case <-f.quit:
   564  				return
   565  			}
   566  //为有序导入计划检索的块
   567  			for _, block := range blocks {
   568  				if announce := f.completing[block.Hash()]; announce != nil {
   569  					f.enqueue(announce.origin, block)
   570  				}
   571  			}
   572  		}
   573  	}
   574  }
   575  
   576  //RescheduleFetch将指定的Fetch计时器重置为下一个公告超时。
   577  func (f *Fetcher) rescheduleFetch(fetch *time.Timer) {
   578  //如果没有公告块,则短路
   579  	if len(f.announced) == 0 {
   580  		return
   581  	}
   582  //否则查找最早的过期通知
   583  	earliest := time.Now()
   584  	for _, announces := range f.announced {
   585  		if earliest.After(announces[0].time) {
   586  			earliest = announces[0].time
   587  		}
   588  	}
   589  	fetch.Reset(arriveTimeout - time.Since(earliest))
   590  }
   591  
   592  //重新安排完成将指定的完成计时器重置为下一个提取超时。
   593  func (f *Fetcher) rescheduleComplete(complete *time.Timer) {
   594  //如果未提取收割台,则短路
   595  	if len(f.fetched) == 0 {
   596  		return
   597  	}
   598  //否则查找最早的过期通知
   599  	earliest := time.Now()
   600  	for _, announces := range f.fetched {
   601  		if earliest.After(announces[0].time) {
   602  			earliest = announces[0].time
   603  		}
   604  	}
   605  	complete.Reset(gatherSlack - time.Since(earliest))
   606  }
   607  
   608  //如果要导入的块
   609  //还没有看到。
   610  func (f *Fetcher) enqueue(peer string, block *types.Block) {
   611  	hash := block.Hash()
   612  
   613  //确保同伴没有给我们剂量
   614  	count := f.queues[peer] + 1
   615  	if count > blockLimit {
   616  		log.Debug("Discarded propagated block, exceeded allowance", "peer", peer, "number", block.Number(), "hash", hash, "limit", blockLimit)
   617  		propBroadcastDOSMeter.Mark(1)
   618  		f.forgetHash(hash)
   619  		return
   620  	}
   621  //丢弃任何过去或太远的块
   622  	if dist := int64(block.NumberU64()) - int64(f.chainHeight()); dist < -maxUncleDist || dist > maxQueueDist {
   623  		log.Debug("Discarded propagated block, too far away", "peer", peer, "number", block.Number(), "hash", hash, "distance", dist)
   624  		propBroadcastDropMeter.Mark(1)
   625  		f.forgetHash(hash)
   626  		return
   627  	}
   628  //为以后的导入计划块
   629  	if _, ok := f.queued[hash]; !ok {
   630  		op := &inject{
   631  			origin: peer,
   632  			block:  block,
   633  		}
   634  		f.queues[peer] = count
   635  		f.queued[hash] = op
   636  		f.queue.Push(op, -float32(block.NumberU64()))
   637  		if f.queueChangeHook != nil {
   638  			f.queueChangeHook(op.block.Hash(), true)
   639  		}
   640  		log.Debug("Queued propagated block", "peer", peer, "number", block.Number(), "hash", hash, "queued", f.queue.Size())
   641  	}
   642  }
   643  
   644  //insert生成新的goroutine以在链中执行块插入。如果
   645  //块的编号与当前导入阶段的高度相同,它将更新
   646  //相应地,相位状态。
   647  func (f *Fetcher) insert(peer string, block *types.Block) {
   648  	hash := block.Hash()
   649  
   650  //在新线程上运行导入
   651  	log.Debug("Importing propagated block", "peer", peer, "number", block.Number(), "hash", hash)
   652  	go func() {
   653  		defer func() { f.done <- hash }()
   654  
   655  //如果父级未知,则中止插入
   656  		parent := f.getBlock(block.ParentHash())
   657  		if parent == nil {
   658  			log.Debug("Unknown parent of propagated block", "peer", peer, "number", block.Number(), "hash", hash, "parent", block.ParentHash())
   659  			return
   660  		}
   661  //快速验证头并在块通过时传播该块
   662  		switch err := f.verifyHeader(block.Header()); err {
   663  		case nil:
   664  //一切正常,迅速传播给我们的同行
   665  			propBroadcastOutTimer.UpdateSince(block.ReceivedAt)
   666  			go f.broadcastBlock(block, true)
   667  
   668  		case consensus.ErrFutureBlock:
   669  //奇怪的未来块,不要失败,但都不会传播
   670  
   671  		default:
   672  //出了点问题,丢掉同伴
   673  			log.Debug("Propagated block verification failed", "peer", peer, "number", block.Number(), "hash", hash, "err", err)
   674  			f.dropPeer(peer)
   675  			return
   676  		}
   677  //运行实际导入并记录所有问题
   678  		if _, err := f.insertChain(types.Blocks{block}); err != nil {
   679  			log.Debug("Propagated block import failed", "peer", peer, "number", block.Number(), "hash", hash, "err", err)
   680  			return
   681  		}
   682  //如果导入成功,则广播块
   683  		propAnnounceOutTimer.UpdateSince(block.ReceivedAt)
   684  		go f.broadcastBlock(block, false)
   685  
   686  //如果需要,调用测试挂钩
   687  		if f.importedHook != nil {
   688  			f.importedHook(block)
   689  		}
   690  	}()
   691  }
   692  
   693  //遗忘哈希从提取程序中删除块通知的所有跟踪
   694  //内部状态。
   695  func (f *Fetcher) forgetHash(hash common.Hash) {
   696  //删除所有挂起的公告和递减DOS计数器
   697  	for _, announce := range f.announced[hash] {
   698  		f.announces[announce.origin]--
   699  		if f.announces[announce.origin] == 0 {
   700  			delete(f.announces, announce.origin)
   701  		}
   702  	}
   703  	delete(f.announced, hash)
   704  	if f.announceChangeHook != nil {
   705  		f.announceChangeHook(hash, false)
   706  	}
   707  //删除所有挂起的提取并减少DOS计数器
   708  	if announce := f.fetching[hash]; announce != nil {
   709  		f.announces[announce.origin]--
   710  		if f.announces[announce.origin] == 0 {
   711  			delete(f.announces, announce.origin)
   712  		}
   713  		delete(f.fetching, hash)
   714  	}
   715  
   716  //删除所有挂起的完成请求并减少DOS计数器
   717  	for _, announce := range f.fetched[hash] {
   718  		f.announces[announce.origin]--
   719  		if f.announces[announce.origin] == 0 {
   720  			delete(f.announces, announce.origin)
   721  		}
   722  	}
   723  	delete(f.fetched, hash)
   724  
   725  //删除所有挂起的完成并减少DOS计数器
   726  	if announce := f.completing[hash]; announce != nil {
   727  		f.announces[announce.origin]--
   728  		if f.announces[announce.origin] == 0 {
   729  			delete(f.announces, announce.origin)
   730  		}
   731  		delete(f.completing, hash)
   732  	}
   733  }
   734  
   735  //CISTION块从取回器的内部移除队列块的所有踪迹。
   736  //状态。
   737  func (f *Fetcher) forgetBlock(hash common.Hash) {
   738  	if insert := f.queued[hash]; insert != nil {
   739  		f.queues[insert.origin]--
   740  		if f.queues[insert.origin] == 0 {
   741  			delete(f.queues, insert.origin)
   742  		}
   743  		delete(f.queued, hash)
   744  	}
   745  }