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