github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/miner/worker.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 19:16:40</date> 10 //</624450100676005888> 11 12 13 package miner 14 15 import ( 16 "bytes" 17 "errors" 18 "math/big" 19 "sync" 20 "sync/atomic" 21 "time" 22 23 mapset "github.com/deckarep/golang-set" 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/consensus" 26 "github.com/ethereum/go-ethereum/consensus/misc" 27 "github.com/ethereum/go-ethereum/core" 28 "github.com/ethereum/go-ethereum/core/state" 29 "github.com/ethereum/go-ethereum/core/types" 30 "github.com/ethereum/go-ethereum/event" 31 "github.com/ethereum/go-ethereum/log" 32 "github.com/ethereum/go-ethereum/params" 33 ) 34 35 const ( 36 //结果QueueSize为监听密封结果的通道大小。 37 resultQueueSize = 10 38 39 //txchanSize是侦听newtxSevent的频道的大小。 40 //该数字是根据Tx池的大小引用的。 41 txChanSize = 4096 42 43 //ChainHeadChansize是侦听ChainHeadEvent的通道的大小。 44 chainHeadChanSize = 10 45 46 //ChainsideChansize是侦听ChainsideEvent的通道的大小。 47 chainSideChanSize = 10 48 49 //SubmitadjustChansize是重新提交间隔调整通道的大小。 50 resubmitAdjustChanSize = 10 51 52 //MiningLogAtDepth是记录成功挖掘之前的确认数。 53 miningLogAtDepth = 7 54 55 //MinRecommitInterval是重新创建挖掘块所用的最小时间间隔。 56 //任何新到的交易。 57 minRecommitInterval = 1 * time.Second 58 59 //MaxRecommitInterval是重新创建挖掘块所用的最大时间间隔 60 //任何新到的交易。 61 maxRecommitInterval = 15 * time.Second 62 63 //间隙调整是单个间隙调整对密封工作的影响。 64 //重新提交间隔。 65 intervalAdjustRatio = 0.1 66 67 //在新的重新提交间隔计算期间应用IntervalAdjustBias,有利于 68 //增大上限或减小下限,以便可以达到上限。 69 intervalAdjustBias = 200 * 1000.0 * 1000.0 70 71 //StaleThreshold是可接受的Stale块的最大深度。 72 staleThreshold = 7 73 ) 74 75 //环境是工作人员的当前环境,保存所有当前状态信息。 76 type environment struct { 77 signer types.Signer 78 79 state *state.StateDB //在此应用状态更改 80 ancestors mapset.Set //祖先集(用于检查叔叔父级有效性) 81 family mapset.Set //家庭设置(用于检查叔叔的无效性) 82 uncles mapset.Set //叔叔集 83 tcount int //周期中的Tx计数 84 gasPool *core.GasPool //用于包装交易的可用气体 85 86 header *types.Header 87 txs []*types.Transaction 88 receipts []*types.Receipt 89 } 90 91 //任务包含共识引擎密封和结果提交的所有信息。 92 type task struct { 93 receipts []*types.Receipt 94 state *state.StateDB 95 block *types.Block 96 createdAt time.Time 97 } 98 99 const ( 100 commitInterruptNone int32 = iota 101 commitInterruptNewHead 102 commitInterruptResubmit 103 ) 104 105 //newworkreq表示使用相关中断通知程序提交新密封工作的请求。 106 type newWorkReq struct { 107 interrupt *int32 108 noempty bool 109 timestamp int64 110 } 111 112 //IntervalAdjust表示重新提交的间隔调整。 113 type intervalAdjust struct { 114 ratio float64 115 inc bool 116 } 117 118 //工作人员是负责向共识引擎提交新工作的主要对象。 119 //收集密封结果。 120 type worker struct { 121 config *params.ChainConfig 122 engine consensus.Engine 123 eth Backend 124 chain *core.BlockChain 125 126 gasFloor uint64 127 gasCeil uint64 128 129 //订阅 130 mux *event.TypeMux 131 txsCh chan core.NewTxsEvent 132 txsSub event.Subscription 133 chainHeadCh chan core.ChainHeadEvent 134 chainHeadSub event.Subscription 135 chainSideCh chan core.ChainSideEvent 136 chainSideSub event.Subscription 137 138 //渠道 139 newWorkCh chan *newWorkReq 140 taskCh chan *task 141 resultCh chan *types.Block 142 startCh chan struct{} 143 exitCh chan struct{} 144 resubmitIntervalCh chan time.Duration 145 resubmitAdjustCh chan *intervalAdjust 146 147 current *environment //当前运行周期的环境。 148 localUncles map[common.Hash]*types.Block //局部生成的一组边块,作为可能的叔叔块。 149 remoteUncles map[common.Hash]*types.Block //一组侧块作为可能的叔叔块。 150 unconfirmed *unconfirmedBlocks //一组本地挖掘的块,等待规范性确认。 151 152 mu sync.RWMutex //用于保护coinbase和额外字段的锁 153 coinbase common.Address 154 extra []byte 155 156 pendingMu sync.RWMutex 157 pendingTasks map[common.Hash]*task 158 159 snapshotMu sync.RWMutex //用于保护块快照和状态快照的锁 160 snapshotBlock *types.Block 161 snapshotState *state.StateDB 162 163 //原子状态计数器 164 running int32 //共识引擎是否运行的指示器。 165 newTxs int32 //自上次密封工作提交以来的新到达交易记录计数。 166 167 //外部功能 168 isLocalBlock func(block *types.Block) bool //用于确定指定块是否由本地矿工挖掘的函数。 169 170 //测试钩 171 newTaskHook func(*task) //方法在收到新的密封任务时调用。 172 skipSealHook func(*task) bool //方法来决定是否跳过密封。 173 fullTaskHook func() //方法在执行完全密封任务之前调用。 174 resubmitHook func(time.Duration, time.Duration) //更新重新提交间隔时调用的方法。 175 } 176 177 func newWorker(config *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux, recommit time.Duration, gasFloor, gasCeil uint64, isLocalBlock func(*types.Block) bool) *worker { 178 worker := &worker{ 179 config: config, 180 engine: engine, 181 eth: eth, 182 mux: mux, 183 chain: eth.BlockChain(), 184 gasFloor: gasFloor, 185 gasCeil: gasCeil, 186 isLocalBlock: isLocalBlock, 187 localUncles: make(map[common.Hash]*types.Block), 188 remoteUncles: make(map[common.Hash]*types.Block), 189 unconfirmed: newUnconfirmedBlocks(eth.BlockChain(), miningLogAtDepth), 190 pendingTasks: make(map[common.Hash]*task), 191 txsCh: make(chan core.NewTxsEvent, txChanSize), 192 chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), 193 chainSideCh: make(chan core.ChainSideEvent, chainSideChanSize), 194 newWorkCh: make(chan *newWorkReq), 195 taskCh: make(chan *task), 196 resultCh: make(chan *types.Block, resultQueueSize), 197 exitCh: make(chan struct{}), 198 startCh: make(chan struct{}, 1), 199 resubmitIntervalCh: make(chan time.Duration), 200 resubmitAdjustCh: make(chan *intervalAdjust, resubmitAdjustChanSize), 201 } 202 //订阅Tx池的NewTxSevent 203 worker.txsSub = eth.TxPool().SubscribeNewTxsEvent(worker.txsCh) 204 //为区块链订阅事件 205 worker.chainHeadSub = eth.BlockChain().SubscribeChainHeadEvent(worker.chainHeadCh) 206 worker.chainSideSub = eth.BlockChain().SubscribeChainSideEvent(worker.chainSideCh) 207 208 //如果用户指定的重新提交间隔太短,则清除重新提交间隔。 209 if recommit < minRecommitInterval { 210 log.Warn("Sanitizing miner recommit interval", "provided", recommit, "updated", minRecommitInterval) 211 recommit = minRecommitInterval 212 } 213 214 go worker.mainLoop() 215 go worker.newWorkLoop(recommit) 216 go worker.resultLoop() 217 go worker.taskLoop() 218 219 //提交第一个工作以初始化挂起状态。 220 worker.startCh <- struct{}{} 221 222 return worker 223 } 224 225 //setetherbase设置用于初始化块coinbase字段的etherbase。 226 func (w *worker) setEtherbase(addr common.Address) { 227 w.mu.Lock() 228 defer w.mu.Unlock() 229 w.coinbase = addr 230 } 231 232 //setextra设置用于初始化块额外字段的内容。 233 func (w *worker) setExtra(extra []byte) { 234 w.mu.Lock() 235 defer w.mu.Unlock() 236 w.extra = extra 237 } 238 239 //setrecommittinterval更新矿工密封工作重新投入的时间间隔。 240 func (w *worker) setRecommitInterval(interval time.Duration) { 241 w.resubmitIntervalCh <- interval 242 } 243 244 //Pending返回Pending状态和相应的块。 245 func (w *worker) pending() (*types.Block, *state.StateDB) { 246 //返回快照以避免对当前mutex的争用 247 w.snapshotMu.RLock() 248 defer w.snapshotMu.RUnlock() 249 if w.snapshotState == nil { 250 return nil, nil 251 } 252 return w.snapshotBlock, w.snapshotState.Copy() 253 } 254 255 //PendingBlock返回PendingBlock。 256 func (w *worker) pendingBlock() *types.Block { 257 //返回快照以避免对当前mutex的争用 258 w.snapshotMu.RLock() 259 defer w.snapshotMu.RUnlock() 260 return w.snapshotBlock 261 } 262 263 //Start将运行状态设置为1并触发新工作提交。 264 func (w *worker) start() { 265 atomic.StoreInt32(&w.running, 1) 266 w.startCh <- struct{}{} 267 } 268 269 //stop将运行状态设置为0。 270 func (w *worker) stop() { 271 atomic.StoreInt32(&w.running, 0) 272 } 273 274 //is running返回一个指示工作者是否正在运行的指示器。 275 func (w *worker) isRunning() bool { 276 return atomic.LoadInt32(&w.running) == 1 277 } 278 279 //CLOSE终止工作线程维护的所有后台线程。 280 //注意工人不支持多次关闭。 281 func (w *worker) close() { 282 close(w.exitCh) 283 } 284 285 //newworkoop是一个独立的goroutine,用于在收到事件时提交新的挖掘工作。 286 func (w *worker) newWorkLoop(recommit time.Duration) { 287 var ( 288 interrupt *int32 289 minRecommit = recommit //用户指定的最小重新提交间隔。 290 timestamp int64 //每轮挖掘的时间戳。 291 ) 292 293 timer := time.NewTimer(0) 294 <-timer.C //放弃初始勾号 295 296 //commit使用给定的信号中止正在执行的事务,并重新提交一个新的事务。 297 commit := func(noempty bool, s int32) { 298 if interrupt != nil { 299 atomic.StoreInt32(interrupt, s) 300 } 301 interrupt = new(int32) 302 w.newWorkCh <- &newWorkReq{interrupt: interrupt, noempty: noempty, timestamp: timestamp} 303 timer.Reset(recommit) 304 atomic.StoreInt32(&w.newTxs, 0) 305 } 306 //重新计算提交根据反馈重新计算重新提交间隔。 307 recalcRecommit := func(target float64, inc bool) { 308 var ( 309 prev = float64(recommit.Nanoseconds()) 310 next float64 311 ) 312 if inc { 313 next = prev*(1-intervalAdjustRatio) + intervalAdjustRatio*(target+intervalAdjustBias) 314 //回顾间隔是否大于最大时间间隔 315 if next > float64(maxRecommitInterval.Nanoseconds()) { 316 next = float64(maxRecommitInterval.Nanoseconds()) 317 } 318 } else { 319 next = prev*(1-intervalAdjustRatio) + intervalAdjustRatio*(target-intervalAdjustBias) 320 //如果间隔小于用户指定的最小值,则重述 321 if next < float64(minRecommit.Nanoseconds()) { 322 next = float64(minRecommit.Nanoseconds()) 323 } 324 } 325 recommit = time.Duration(int64(next)) 326 } 327 //ClearPending清除过时的挂起任务。 328 clearPending := func(number uint64) { 329 w.pendingMu.Lock() 330 for h, t := range w.pendingTasks { 331 if t.block.NumberU64()+staleThreshold <= number { 332 delete(w.pendingTasks, h) 333 } 334 } 335 w.pendingMu.Unlock() 336 } 337 338 for { 339 select { 340 case <-w.startCh: 341 clearPending(w.chain.CurrentBlock().NumberU64()) 342 timestamp = time.Now().Unix() 343 commit(false, commitInterruptNewHead) 344 345 case head := <-w.chainHeadCh: 346 clearPending(head.Block.NumberU64()) 347 timestamp = time.Now().Unix() 348 commit(false, commitInterruptNewHead) 349 350 case <-timer.C: 351 //如果正在运行挖掘,请定期重新提交新的工作周期以拉入 352 //高价交易。对挂起的块禁用此开销。 353 if w.isRunning() && (w.config.Clique == nil || w.config.Clique.Period > 0) { 354 //如果没有新交易到达,则短路。 355 if atomic.LoadInt32(&w.newTxs) == 0 { 356 timer.Reset(recommit) 357 continue 358 } 359 commit(true, commitInterruptResubmit) 360 } 361 362 case interval := <-w.resubmitIntervalCh: 363 //按用户明确调整重新提交间隔。 364 if interval < minRecommitInterval { 365 log.Warn("Sanitizing miner recommit interval", "provided", interval, "updated", minRecommitInterval) 366 interval = minRecommitInterval 367 } 368 log.Info("Miner recommit interval update", "from", minRecommit, "to", interval) 369 minRecommit, recommit = interval, interval 370 371 if w.resubmitHook != nil { 372 w.resubmitHook(minRecommit, recommit) 373 } 374 375 case adjust := <-w.resubmitAdjustCh: 376 //通过反馈调整重新提交间隔。 377 if adjust.inc { 378 before := recommit 379 recalcRecommit(float64(recommit.Nanoseconds())/adjust.ratio, true) 380 log.Trace("Increase miner recommit interval", "from", before, "to", recommit) 381 } else { 382 before := recommit 383 recalcRecommit(float64(minRecommit.Nanoseconds()), false) 384 log.Trace("Decrease miner recommit interval", "from", before, "to", recommit) 385 } 386 387 if w.resubmitHook != nil { 388 w.resubmitHook(minRecommit, recommit) 389 } 390 391 case <-w.exitCh: 392 return 393 } 394 } 395 } 396 397 //mainLoop是一个独立的goroutine,用于根据接收到的事件重新生成密封任务。 398 func (w *worker) mainLoop() { 399 defer w.txsSub.Unsubscribe() 400 defer w.chainHeadSub.Unsubscribe() 401 defer w.chainSideSub.Unsubscribe() 402 403 for { 404 select { 405 case req := <-w.newWorkCh: 406 w.commitNewWork(req.interrupt, req.noempty, req.timestamp) 407 408 case ev := <-w.chainSideCh: 409 //重复侧块短路 410 if _, exist := w.localUncles[ev.Block.Hash()]; exist { 411 continue 412 } 413 if _, exist := w.remoteUncles[ev.Block.Hash()]; exist { 414 continue 415 } 416 //根据作者,将侧块添加到可能的叔叔块集。 417 if w.isLocalBlock != nil && w.isLocalBlock(ev.Block) { 418 w.localUncles[ev.Block.Hash()] = ev.Block 419 } else { 420 w.remoteUncles[ev.Block.Hash()] = ev.Block 421 } 422 //如果我们的采矿区块少于2个叔叔区块, 423 //添加新的叔叔块(如果有效)并重新生成挖掘块。 424 if w.isRunning() && w.current != nil && w.current.uncles.Cardinality() < 2 { 425 start := time.Now() 426 if err := w.commitUncle(w.current, ev.Block.Header()); err == nil { 427 var uncles []*types.Header 428 w.current.uncles.Each(func(item interface{}) bool { 429 hash, ok := item.(common.Hash) 430 if !ok { 431 return false 432 } 433 uncle, exist := w.localUncles[hash] 434 if !exist { 435 uncle, exist = w.remoteUncles[hash] 436 } 437 if !exist { 438 return false 439 } 440 uncles = append(uncles, uncle.Header()) 441 return false 442 }) 443 w.commit(uncles, nil, true, start) 444 } 445 } 446 447 case ev := <-w.txsCh: 448 //如果不挖掘,将事务应用于挂起状态。 449 // 450 //注意:收到的所有交易可能与交易不连续。 451 //已包含在当前挖掘块中。这些交易将 452 //自动消除。 453 if !w.isRunning() && w.current != nil { 454 w.mu.RLock() 455 coinbase := w.coinbase 456 w.mu.RUnlock() 457 458 txs := make(map[common.Address]types.Transactions) 459 for _, tx := range ev.Txs { 460 acc, _ := types.Sender(w.current.signer, tx) 461 txs[acc] = append(txs[acc], tx) 462 } 463 txset := types.NewTransactionsByPriceAndNonce(w.current.signer, txs) 464 w.commitTransactions(txset, coinbase, nil) 465 w.updateSnapshot() 466 } else { 467 //如果我们正在挖掘,但没有处理任何事务,请唤醒新事务 468 if w.config.Clique != nil && w.config.Clique.Period == 0 { 469 w.commitNewWork(nil, false, time.Now().Unix()) 470 } 471 } 472 atomic.AddInt32(&w.newTxs, int32(len(ev.Txs))) 473 474 //系统停止 475 case <-w.exitCh: 476 return 477 case <-w.txsSub.Err(): 478 return 479 case <-w.chainHeadSub.Err(): 480 return 481 case <-w.chainSideSub.Err(): 482 return 483 } 484 } 485 } 486 487 //taskloop是一个独立的goroutine,用于从生成器获取密封任务,并且 488 //把他们推到共识引擎。 489 func (w *worker) taskLoop() { 490 var ( 491 stopCh chan struct{} 492 prev common.Hash 493 ) 494 495 //中断中止飞行中的密封任务。 496 interrupt := func() { 497 if stopCh != nil { 498 close(stopCh) 499 stopCh = nil 500 } 501 } 502 for { 503 select { 504 case task := <-w.taskCh: 505 if w.newTaskHook != nil { 506 w.newTaskHook(task) 507 } 508 //因重新提交而拒绝重复密封工作。 509 sealHash := w.engine.SealHash(task.block.Header()) 510 if sealHash == prev { 511 continue 512 } 513 //中断之前的密封操作 514 interrupt() 515 stopCh, prev = make(chan struct{}), sealHash 516 517 if w.skipSealHook != nil && w.skipSealHook(task) { 518 continue 519 } 520 w.pendingMu.Lock() 521 w.pendingTasks[w.engine.SealHash(task.block.Header())] = task 522 w.pendingMu.Unlock() 523 524 if err := w.engine.Seal(w.chain, task.block, w.resultCh, stopCh); err != nil { 525 log.Warn("Block sealing failed", "err", err) 526 } 527 case <-w.exitCh: 528 interrupt() 529 return 530 } 531 } 532 } 533 534 //resultLoop是一个独立的goroutine,用于处理密封结果提交 535 //并将相关数据刷新到数据库。 536 func (w *worker) resultLoop() { 537 for { 538 select { 539 case block := <-w.resultCh: 540 //收到空结果时短路。 541 if block == nil { 542 continue 543 } 544 //由于重新提交而收到重复结果时短路。 545 if w.chain.HasBlock(block.Hash(), block.NumberU64()) { 546 continue 547 } 548 var ( 549 sealhash = w.engine.SealHash(block.Header()) 550 hash = block.Hash() 551 ) 552 w.pendingMu.RLock() 553 task, exist := w.pendingTasks[sealhash] 554 w.pendingMu.RUnlock() 555 if !exist { 556 log.Error("Block found but no relative pending task", "number", block.Number(), "sealhash", sealhash, "hash", hash) 557 continue 558 } 559 //不同的块可以共享相同的sealhash,在这里进行深度复制以防止写写冲突。 560 var ( 561 receipts = make([]*types.Receipt, len(task.receipts)) 562 logs []*types.Log 563 ) 564 for i, receipt := range task.receipts { 565 receipts[i] = new(types.Receipt) 566 *receipts[i] = *receipt 567 //更新所有日志中的块哈希,因为它现在可用,而不是 568 //已创建单个交易的收据/日志。 569 for _, log := range receipt.Logs { 570 log.BlockHash = hash 571 } 572 logs = append(logs, receipt.Logs...) 573 } 574 //将块和状态提交到数据库。 575 stat, err := w.chain.WriteBlockWithState(block, receipts, task.state) 576 if err != nil { 577 log.Error("Failed writing block to chain", "err", err) 578 continue 579 } 580 log.Info("Successfully sealed new block", "number", block.Number(), "sealhash", sealhash, "hash", hash, 581 "elapsed", common.PrettyDuration(time.Since(task.createdAt))) 582 583 //广播块并宣布链插入事件 584 w.mux.Post(core.NewMinedBlockEvent{Block: block}) 585 586 var events []interface{} 587 switch stat { 588 case core.CanonStatTy: 589 events = append(events, core.ChainEvent{Block: block, Hash: block.Hash(), Logs: logs}) 590 events = append(events, core.ChainHeadEvent{Block: block}) 591 case core.SideStatTy: 592 events = append(events, core.ChainSideEvent{Block: block}) 593 } 594 w.chain.PostChainEvents(events, logs) 595 596 //将块插入一组挂起的结果循环以进行确认 597 w.unconfirmed.Insert(block.NumberU64(), block.Hash()) 598 599 case <-w.exitCh: 600 return 601 } 602 } 603 } 604 605 //makecurrent为当前循环创建新环境。 606 func (w *worker) makeCurrent(parent *types.Block, header *types.Header) error { 607 state, err := w.chain.StateAt(parent.Root()) 608 if err != nil { 609 return err 610 } 611 env := &environment{ 612 signer: types.NewEIP155Signer(w.config.ChainID), 613 state: state, 614 ancestors: mapset.NewSet(), 615 family: mapset.NewSet(), 616 uncles: mapset.NewSet(), 617 header: header, 618 } 619 620 //处理08时,祖先包含07(快速块) 621 for _, ancestor := range w.chain.GetBlocksFromHash(parent.Hash(), 7) { 622 for _, uncle := range ancestor.Uncles() { 623 env.family.Add(uncle.Hash()) 624 } 625 env.family.Add(ancestor.Hash()) 626 env.ancestors.Add(ancestor.Hash()) 627 } 628 629 //跟踪返回错误的事务,以便删除它们 630 env.tcount = 0 631 w.current = env 632 return nil 633 } 634 635 //commituncle将给定的块添加到叔叔块集,如果添加失败则返回错误。 636 func (w *worker) commitUncle(env *environment, uncle *types.Header) error { 637 hash := uncle.Hash() 638 if env.uncles.Contains(hash) { 639 return errors.New("uncle not unique") 640 } 641 if env.header.ParentHash == uncle.ParentHash { 642 return errors.New("uncle is sibling") 643 } 644 if !env.ancestors.Contains(uncle.ParentHash) { 645 return errors.New("uncle's parent unknown") 646 } 647 if env.family.Contains(hash) { 648 return errors.New("uncle already included") 649 } 650 env.uncles.Add(uncle.Hash()) 651 return nil 652 } 653 654 //更新快照更新挂起的快照块和状态。 655 //注意:此函数假定当前变量是线程安全的。 656 func (w *worker) updateSnapshot() { 657 w.snapshotMu.Lock() 658 defer w.snapshotMu.Unlock() 659 660 var uncles []*types.Header 661 w.current.uncles.Each(func(item interface{}) bool { 662 hash, ok := item.(common.Hash) 663 if !ok { 664 return false 665 } 666 uncle, exist := w.localUncles[hash] 667 if !exist { 668 uncle, exist = w.remoteUncles[hash] 669 } 670 if !exist { 671 return false 672 } 673 uncles = append(uncles, uncle.Header()) 674 return false 675 }) 676 677 w.snapshotBlock = types.NewBlock( 678 w.current.header, 679 w.current.txs, 680 uncles, 681 w.current.receipts, 682 ) 683 684 w.snapshotState = w.current.state.Copy() 685 } 686 687 func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) { 688 snap := w.current.state.Snapshot() 689 690 receipt, _, err := core.ApplyTransaction(w.config, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, *w.chain.GetVMConfig()) 691 if err != nil { 692 w.current.state.RevertToSnapshot(snap) 693 return nil, err 694 } 695 w.current.txs = append(w.current.txs, tx) 696 w.current.receipts = append(w.current.receipts, receipt) 697 698 return receipt.Logs, nil 699 } 700 701 func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coinbase common.Address, interrupt *int32) bool { 702 //电流为零时短路 703 if w.current == nil { 704 return true 705 } 706 707 if w.current.gasPool == nil { 708 w.current.gasPool = new(core.GasPool).AddGas(w.current.header.GasLimit) 709 } 710 711 var coalescedLogs []*types.Log 712 713 for { 714 //在以下三种情况下,我们将中断事务的执行。 715 //(1)新的头块事件到达,中断信号为1 716 //(2)工人启动或重启,中断信号为1 717 //(3)工人用任何新到达的事务重新创建挖掘块,中断信号为2。 718 //前两种情况下,半成品将被丢弃。 719 //对于第三种情况,半成品将提交给共识引擎。 720 if interrupt != nil && atomic.LoadInt32(interrupt) != commitInterruptNone { 721 //由于提交太频繁,通知重新提交循环以增加重新提交间隔。 722 if atomic.LoadInt32(interrupt) == commitInterruptResubmit { 723 ratio := float64(w.current.header.GasLimit-w.current.gasPool.Gas()) / float64(w.current.header.GasLimit) 724 if ratio < 0.1 { 725 ratio = 0.1 726 } 727 w.resubmitAdjustCh <- &intervalAdjust{ 728 ratio: ratio, 729 inc: true, 730 } 731 } 732 return atomic.LoadInt32(interrupt) == commitInterruptNewHead 733 } 734 //如果我们没有足够的汽油进行进一步的交易,那么我们就完成了 735 if w.current.gasPool.Gas() < params.TxGas { 736 log.Trace("Not enough gas for further transactions", "have", w.current.gasPool, "want", params.TxGas) 737 break 738 } 739 //检索下一个事务,完成后中止 740 tx := txs.Peek() 741 if tx == nil { 742 break 743 } 744 //此处可以忽略错误。已检查错误 745 //在事务接受期间是事务池。 746 // 747 //我们使用EIP155签名者,不管当前的高频。 748 from, _ := types.Sender(w.current.signer, tx) 749 //检查Tx是否受重播保护。如果我们不在EIP155高频 750 //阶段,开始忽略发送者,直到我们这样做。 751 if tx.Protected() && !w.config.IsEIP155(w.current.header.Number) { 752 log.Trace("Ignoring reply protected transaction", "hash", tx.Hash(), "eip155", w.config.EIP155Block) 753 754 txs.Pop() 755 continue 756 } 757 //开始执行事务 758 w.current.state.Prepare(tx.Hash(), common.Hash{}, w.current.tcount) 759 760 logs, err := w.commitTransaction(tx, coinbase) 761 switch err { 762 case core.ErrGasLimitReached: 763 //从账户中弹出当前的天然气外交易,而不在下一个账户中移动。 764 log.Trace("Gas limit exceeded for current block", "sender", from) 765 txs.Pop() 766 767 case core.ErrNonceTooLow: 768 //事务池和矿工之间的新头通知数据竞赛,shift 769 log.Trace("Skipping transaction with low nonce", "sender", from, "nonce", tx.Nonce()) 770 txs.Shift() 771 772 case core.ErrNonceTooHigh: 773 //交易池和矿工之间的REORG通知数据竞赛,跳过帐户= 774 log.Trace("Skipping account with hight nonce", "sender", from, "nonce", tx.Nonce()) 775 txs.Pop() 776 777 case nil: 778 //一切正常,收集日志并从同一帐户转入下一个事务 779 coalescedLogs = append(coalescedLogs, logs...) 780 w.current.tcount++ 781 txs.Shift() 782 783 default: 784 //奇怪的错误,丢弃事务并将下一个事务处理到行中(注意, 785 //nonce-too-high子句将阻止我们无效执行)。 786 log.Debug("Transaction failed, account skipped", "hash", tx.Hash(), "err", err) 787 txs.Shift() 788 } 789 } 790 791 if !w.isRunning() && len(coalescedLogs) > 0 { 792 //我们在采矿时不会推悬垂的日志。原因是 793 //当我们进行挖掘时,工人将每3秒重新生成一个挖掘块。 794 //为了避免推送重复的挂起日志,我们禁用挂起日志推送。 795 796 //复制,状态缓存日志,这些日志从挂起升级到挖掘。 797 //当块由当地矿工开采时,通过填充块散列进行记录。这个罐头 798 //如果在处理PendingLogSevent之前日志已“升级”,则会导致竞争条件。 799 cpy := make([]*types.Log, len(coalescedLogs)) 800 for i, l := range coalescedLogs { 801 cpy[i] = new(types.Log) 802 *cpy[i] = *l 803 } 804 go w.mux.Post(core.PendingLogsEvent{Logs: cpy}) 805 } 806 //如果当前间隔较大,通知重新提交循环以减少重新提交间隔 807 //而不是用户指定的。 808 if interrupt != nil { 809 w.resubmitAdjustCh <- &intervalAdjust{inc: false} 810 } 811 return false 812 } 813 814 //CommitnewWork基于父块生成几个新的密封任务。 815 func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) { 816 w.mu.RLock() 817 defer w.mu.RUnlock() 818 819 tstart := time.Now() 820 parent := w.chain.CurrentBlock() 821 822 if parent.Time().Cmp(new(big.Int).SetInt64(timestamp)) >= 0 { 823 timestamp = parent.Time().Int64() + 1 824 } 825 //这将确保我们今后不会走得太远。 826 if now := time.Now().Unix(); timestamp > now+1 { 827 wait := time.Duration(timestamp-now) * time.Second 828 log.Info("Mining too far in the future", "wait", common.PrettyDuration(wait)) 829 time.Sleep(wait) 830 } 831 832 num := parent.Number() 833 header := &types.Header{ 834 ParentHash: parent.Hash(), 835 Number: num.Add(num, common.Big1), 836 GasLimit: core.CalcGasLimit(parent, w.gasFloor, w.gasCeil), 837 Extra: w.extra, 838 Time: big.NewInt(timestamp), 839 } 840 //只有在我们的共识引擎运行时才设置coinbase(避免虚假的块奖励) 841 if w.isRunning() { 842 if w.coinbase == (common.Address{}) { 843 log.Error("Refusing to mine without etherbase") 844 return 845 } 846 header.Coinbase = w.coinbase 847 } 848 if err := w.engine.Prepare(w.chain, header); err != nil { 849 log.Error("Failed to prepare header for mining", "err", err) 850 return 851 } 852 //如果我们关心DAO硬分叉,请检查是否覆盖额外的数据 853 if daoBlock := w.config.DAOForkBlock; daoBlock != nil { 854 //检查块是否在fork额外覆盖范围内 855 limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange) 856 if header.Number.Cmp(daoBlock) >= 0 && header.Number.Cmp(limit) < 0 { 857 //根据我们是支持还是反对叉子,以不同的方式超越 858 if w.config.DAOForkSupport { 859 header.Extra = common.CopyBytes(params.DAOForkBlockExtra) 860 } else if bytes.Equal(header.Extra, params.DAOForkBlockExtra) { 861 header.Extra = []byte{} //如果Miner反对,不要让它使用保留的额外数据 862 } 863 } 864 } 865 //如果在一个奇怪的状态下开始挖掘,可能会发生这种情况。 866 err := w.makeCurrent(parent, header) 867 if err != nil { 868 log.Error("Failed to create mining context", "err", err) 869 return 870 } 871 //创建当前工作任务并检查所需的任何分叉转换 872 env := w.current 873 if w.config.DAOForkSupport && w.config.DAOForkBlock != nil && w.config.DAOForkBlock.Cmp(header.Number) == 0 { 874 misc.ApplyDAOHardFork(env.state) 875 } 876 //累积当前块的叔叔 877 uncles := make([]*types.Header, 0, 2) 878 commitUncles := func(blocks map[common.Hash]*types.Block) { 879 //先清理陈旧的叔叔街区 880 for hash, uncle := range blocks { 881 if uncle.NumberU64()+staleThreshold <= header.Number.Uint64() { 882 delete(blocks, hash) 883 } 884 } 885 for hash, uncle := range blocks { 886 if len(uncles) == 2 { 887 break 888 } 889 if err := w.commitUncle(env, uncle.Header()); err != nil { 890 log.Trace("Possible uncle rejected", "hash", hash, "reason", err) 891 } else { 892 log.Debug("Committing new uncle to block", "hash", hash) 893 uncles = append(uncles, uncle.Header()) 894 } 895 } 896 } 897 //更喜欢本地生成的叔叔 898 commitUncles(w.localUncles) 899 commitUncles(w.remoteUncles) 900 901 if !noempty { 902 //基于临时复制状态创建一个空块,在不等待块的情况下提前密封 903 //执行完成。 904 w.commit(uncles, nil, false, tstart) 905 } 906 907 //用所有可用的挂起事务填充块。 908 pending, err := w.eth.TxPool().Pending() 909 if err != nil { 910 log.Error("Failed to fetch pending transactions", "err", err) 911 return 912 } 913 //如果没有可用的挂起事务,则短路 914 if len(pending) == 0 { 915 w.updateSnapshot() 916 return 917 } 918 //将挂起的事务拆分为本地和远程 919 localTxs, remoteTxs := make(map[common.Address]types.Transactions), pending 920 for _, account := range w.eth.TxPool().Locals() { 921 if txs := remoteTxs[account]; len(txs) > 0 { 922 delete(remoteTxs, account) 923 localTxs[account] = txs 924 } 925 } 926 if len(localTxs) > 0 { 927 txs := types.NewTransactionsByPriceAndNonce(w.current.signer, localTxs) 928 if w.commitTransactions(txs, w.coinbase, interrupt) { 929 return 930 } 931 } 932 if len(remoteTxs) > 0 { 933 txs := types.NewTransactionsByPriceAndNonce(w.current.signer, remoteTxs) 934 if w.commitTransactions(txs, w.coinbase, interrupt) { 935 return 936 } 937 } 938 w.commit(uncles, w.fullTaskHook, true, tstart) 939 } 940 941 //commit运行任何事务后状态修改,组装最终块 942 //如果共识引擎正在运行,则提交新的工作。 943 func (w *worker) commit(uncles []*types.Header, interval func(), update bool, start time.Time) error { 944 //在此深度复制收据以避免不同任务之间的交互。 945 receipts := make([]*types.Receipt, len(w.current.receipts)) 946 for i, l := range w.current.receipts { 947 receipts[i] = new(types.Receipt) 948 *receipts[i] = *l 949 } 950 s := w.current.state.Copy() 951 block, err := w.engine.Finalize(w.chain, w.current.header, s, w.current.txs, uncles, w.current.receipts) 952 if err != nil { 953 return err 954 } 955 if w.isRunning() { 956 if interval != nil { 957 interval() 958 } 959 select { 960 case w.taskCh <- &task{receipts: receipts, state: s, block: block, createdAt: time.Now()}: 961 w.unconfirmed.Shift(block.NumberU64() - 1) 962 963 feesWei := new(big.Int) 964 for i, tx := range block.Transactions() { 965 feesWei.Add(feesWei, new(big.Int).Mul(new(big.Int).SetUint64(receipts[i].GasUsed), tx.GasPrice())) 966 } 967 feesEth := new(big.Float).Quo(new(big.Float).SetInt(feesWei), new(big.Float).SetInt(big.NewInt(params.Ether))) 968 969 log.Info("Commit new mining work", "number", block.Number(), "sealhash", w.engine.SealHash(block.Header()), 970 "uncles", len(uncles), "txs", w.current.tcount, "gas", block.GasUsed(), "fees", feesEth, "elapsed", common.PrettyDuration(time.Since(start))) 971 972 case <-w.exitCh: 973 log.Info("Worker has exited") 974 } 975 } 976 if update { 977 w.updateSnapshot() 978 } 979 return nil 980 } 981