github.com/Ethersocial/go-esn@v0.3.7/miner/worker.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package miner 18 19 import ( 20 "bytes" 21 "errors" 22 "math/big" 23 "sync" 24 "sync/atomic" 25 "time" 26 27 mapset "github.com/deckarep/golang-set" 28 "github.com/ethersocial/go-esn/common" 29 "github.com/ethersocial/go-esn/consensus" 30 "github.com/ethersocial/go-esn/consensus/misc" 31 "github.com/ethersocial/go-esn/core" 32 "github.com/ethersocial/go-esn/core/state" 33 "github.com/ethersocial/go-esn/core/types" 34 "github.com/ethersocial/go-esn/core/vm" 35 "github.com/ethersocial/go-esn/event" 36 "github.com/ethersocial/go-esn/log" 37 "github.com/ethersocial/go-esn/params" 38 ) 39 40 const ( 41 // resultQueueSize is the size of channel listening to sealing result. 42 resultQueueSize = 10 43 44 // txChanSize is the size of channel listening to NewTxsEvent. 45 // The number is referenced from the size of tx pool. 46 txChanSize = 4096 47 48 // chainHeadChanSize is the size of channel listening to ChainHeadEvent. 49 chainHeadChanSize = 10 50 51 // chainSideChanSize is the size of channel listening to ChainSideEvent. 52 chainSideChanSize = 10 53 54 // resubmitAdjustChanSize is the size of resubmitting interval adjustment channel. 55 resubmitAdjustChanSize = 10 56 57 // miningLogAtDepth is the number of confirmations before logging successful mining. 58 miningLogAtDepth = 7 59 60 // minRecommitInterval is the minimal time interval to recreate the mining block with 61 // any newly arrived transactions. 62 minRecommitInterval = 1 * time.Second 63 64 // maxRecommitInterval is the maximum time interval to recreate the mining block with 65 // any newly arrived transactions. 66 maxRecommitInterval = 15 * time.Second 67 68 // intervalAdjustRatio is the impact a single interval adjustment has on sealing work 69 // resubmitting interval. 70 intervalAdjustRatio = 0.1 71 72 // intervalAdjustBias is applied during the new resubmit interval calculation in favor of 73 // increasing upper limit or decreasing lower limit so that the limit can be reachable. 74 intervalAdjustBias = 200 * 1000.0 * 1000.0 75 76 // staleThreshold is the maximum depth of the acceptable stale block. 77 staleThreshold = 7 78 ) 79 80 // environment is the worker's current environment and holds all of the current state information. 81 type environment struct { 82 signer types.Signer 83 84 state *state.StateDB // apply state changes here 85 ancestors mapset.Set // ancestor set (used for checking uncle parent validity) 86 family mapset.Set // family set (used for checking uncle invalidity) 87 uncles mapset.Set // uncle set 88 tcount int // tx count in cycle 89 gasPool *core.GasPool // available gas used to pack transactions 90 91 header *types.Header 92 txs []*types.Transaction 93 receipts []*types.Receipt 94 } 95 96 // task contains all information for consensus engine sealing and result submitting. 97 type task struct { 98 receipts []*types.Receipt 99 state *state.StateDB 100 block *types.Block 101 createdAt time.Time 102 } 103 104 const ( 105 commitInterruptNone int32 = iota 106 commitInterruptNewHead 107 commitInterruptResubmit 108 ) 109 110 // newWorkReq represents a request for new sealing work submitting with relative interrupt notifier. 111 type newWorkReq struct { 112 interrupt *int32 113 noempty bool 114 timestamp int64 115 } 116 117 // intervalAdjust represents a resubmitting interval adjustment. 118 type intervalAdjust struct { 119 ratio float64 120 inc bool 121 } 122 123 // worker is the main object which takes care of submitting new work to consensus engine 124 // and gathering the sealing result. 125 type worker struct { 126 config *params.ChainConfig 127 engine consensus.Engine 128 eth Backend 129 chain *core.BlockChain 130 131 gasFloor uint64 132 gasCeil uint64 133 134 // Subscriptions 135 mux *event.TypeMux 136 txsCh chan core.NewTxsEvent 137 txsSub event.Subscription 138 chainHeadCh chan core.ChainHeadEvent 139 chainHeadSub event.Subscription 140 chainSideCh chan core.ChainSideEvent 141 chainSideSub event.Subscription 142 143 // Channels 144 newWorkCh chan *newWorkReq 145 taskCh chan *task 146 resultCh chan *types.Block 147 startCh chan struct{} 148 exitCh chan struct{} 149 resubmitIntervalCh chan time.Duration 150 resubmitAdjustCh chan *intervalAdjust 151 152 current *environment // An environment for current running cycle. 153 localUncles map[common.Hash]*types.Block // A set of side blocks generated locally as the possible uncle blocks. 154 remoteUncles map[common.Hash]*types.Block // A set of side blocks as the possible uncle blocks. 155 unconfirmed *unconfirmedBlocks // A set of locally mined blocks pending canonicalness confirmations. 156 157 mu sync.RWMutex // The lock used to protect the coinbase and extra fields 158 coinbase common.Address 159 extra []byte 160 161 pendingMu sync.RWMutex 162 pendingTasks map[common.Hash]*task 163 164 snapshotMu sync.RWMutex // The lock used to protect the block snapshot and state snapshot 165 snapshotBlock *types.Block 166 snapshotState *state.StateDB 167 168 // atomic status counters 169 running int32 // The indicator whether the consensus engine is running or not. 170 newTxs int32 // New arrival transaction count since last sealing work submitting. 171 172 // External functions 173 isLocalBlock func(block *types.Block) bool // Function used to determine whether the specified block is mined by local miner. 174 175 // Test hooks 176 newTaskHook func(*task) // Method to call upon receiving a new sealing task. 177 skipSealHook func(*task) bool // Method to decide whether skipping the sealing. 178 fullTaskHook func() // Method to call before pushing the full sealing task. 179 resubmitHook func(time.Duration, time.Duration) // Method to call upon updating resubmitting interval. 180 } 181 182 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 { 183 worker := &worker{ 184 config: config, 185 engine: engine, 186 eth: eth, 187 mux: mux, 188 chain: eth.BlockChain(), 189 gasFloor: gasFloor, 190 gasCeil: gasCeil, 191 isLocalBlock: isLocalBlock, 192 localUncles: make(map[common.Hash]*types.Block), 193 remoteUncles: make(map[common.Hash]*types.Block), 194 unconfirmed: newUnconfirmedBlocks(eth.BlockChain(), miningLogAtDepth), 195 pendingTasks: make(map[common.Hash]*task), 196 txsCh: make(chan core.NewTxsEvent, txChanSize), 197 chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), 198 chainSideCh: make(chan core.ChainSideEvent, chainSideChanSize), 199 newWorkCh: make(chan *newWorkReq), 200 taskCh: make(chan *task), 201 resultCh: make(chan *types.Block, resultQueueSize), 202 exitCh: make(chan struct{}), 203 startCh: make(chan struct{}, 1), 204 resubmitIntervalCh: make(chan time.Duration), 205 resubmitAdjustCh: make(chan *intervalAdjust, resubmitAdjustChanSize), 206 } 207 // Subscribe NewTxsEvent for tx pool 208 worker.txsSub = eth.TxPool().SubscribeNewTxsEvent(worker.txsCh) 209 // Subscribe events for blockchain 210 worker.chainHeadSub = eth.BlockChain().SubscribeChainHeadEvent(worker.chainHeadCh) 211 worker.chainSideSub = eth.BlockChain().SubscribeChainSideEvent(worker.chainSideCh) 212 213 // Sanitize recommit interval if the user-specified one is too short. 214 if recommit < minRecommitInterval { 215 log.Warn("Sanitizing miner recommit interval", "provided", recommit, "updated", minRecommitInterval) 216 recommit = minRecommitInterval 217 } 218 219 go worker.mainLoop() 220 go worker.newWorkLoop(recommit) 221 go worker.resultLoop() 222 go worker.taskLoop() 223 224 // Submit first work to initialize pending state. 225 worker.startCh <- struct{}{} 226 227 return worker 228 } 229 230 // setEtherbase sets the etherbase used to initialize the block coinbase field. 231 func (w *worker) setEtherbase(addr common.Address) { 232 w.mu.Lock() 233 defer w.mu.Unlock() 234 w.coinbase = addr 235 } 236 237 // setExtra sets the content used to initialize the block extra field. 238 func (w *worker) setExtra(extra []byte) { 239 w.mu.Lock() 240 defer w.mu.Unlock() 241 w.extra = extra 242 } 243 244 // setRecommitInterval updates the interval for miner sealing work recommitting. 245 func (w *worker) setRecommitInterval(interval time.Duration) { 246 w.resubmitIntervalCh <- interval 247 } 248 249 // pending returns the pending state and corresponding block. 250 func (w *worker) pending() (*types.Block, *state.StateDB) { 251 // return a snapshot to avoid contention on currentMu mutex 252 w.snapshotMu.RLock() 253 defer w.snapshotMu.RUnlock() 254 if w.snapshotState == nil { 255 return nil, nil 256 } 257 return w.snapshotBlock, w.snapshotState.Copy() 258 } 259 260 // pendingBlock returns pending block. 261 func (w *worker) pendingBlock() *types.Block { 262 // return a snapshot to avoid contention on currentMu mutex 263 w.snapshotMu.RLock() 264 defer w.snapshotMu.RUnlock() 265 return w.snapshotBlock 266 } 267 268 // start sets the running status as 1 and triggers new work submitting. 269 func (w *worker) start() { 270 atomic.StoreInt32(&w.running, 1) 271 w.startCh <- struct{}{} 272 } 273 274 // stop sets the running status as 0. 275 func (w *worker) stop() { 276 atomic.StoreInt32(&w.running, 0) 277 } 278 279 // isRunning returns an indicator whether worker is running or not. 280 func (w *worker) isRunning() bool { 281 return atomic.LoadInt32(&w.running) == 1 282 } 283 284 // close terminates all background threads maintained by the worker. 285 // Note the worker does not support being closed multiple times. 286 func (w *worker) close() { 287 close(w.exitCh) 288 } 289 290 // newWorkLoop is a standalone goroutine to submit new mining work upon received events. 291 func (w *worker) newWorkLoop(recommit time.Duration) { 292 var ( 293 interrupt *int32 294 minRecommit = recommit // minimal resubmit interval specified by user. 295 timestamp int64 // timestamp for each round of mining. 296 ) 297 298 timer := time.NewTimer(0) 299 <-timer.C // discard the initial tick 300 301 // commit aborts in-flight transaction execution with given signal and resubmits a new one. 302 commit := func(noempty bool, s int32) { 303 if interrupt != nil { 304 atomic.StoreInt32(interrupt, s) 305 } 306 interrupt = new(int32) 307 w.newWorkCh <- &newWorkReq{interrupt: interrupt, noempty: noempty, timestamp: timestamp} 308 timer.Reset(recommit) 309 atomic.StoreInt32(&w.newTxs, 0) 310 } 311 // recalcRecommit recalculates the resubmitting interval upon feedback. 312 recalcRecommit := func(target float64, inc bool) { 313 var ( 314 prev = float64(recommit.Nanoseconds()) 315 next float64 316 ) 317 if inc { 318 next = prev*(1-intervalAdjustRatio) + intervalAdjustRatio*(target+intervalAdjustBias) 319 // Recap if interval is larger than the maximum time interval 320 if next > float64(maxRecommitInterval.Nanoseconds()) { 321 next = float64(maxRecommitInterval.Nanoseconds()) 322 } 323 } else { 324 next = prev*(1-intervalAdjustRatio) + intervalAdjustRatio*(target-intervalAdjustBias) 325 // Recap if interval is less than the user specified minimum 326 if next < float64(minRecommit.Nanoseconds()) { 327 next = float64(minRecommit.Nanoseconds()) 328 } 329 } 330 recommit = time.Duration(int64(next)) 331 } 332 // clearPending cleans the stale pending tasks. 333 clearPending := func(number uint64) { 334 w.pendingMu.Lock() 335 for h, t := range w.pendingTasks { 336 if t.block.NumberU64()+staleThreshold <= number { 337 delete(w.pendingTasks, h) 338 } 339 } 340 w.pendingMu.Unlock() 341 } 342 343 for { 344 select { 345 case <-w.startCh: 346 clearPending(w.chain.CurrentBlock().NumberU64()) 347 timestamp = time.Now().Unix() 348 commit(false, commitInterruptNewHead) 349 350 case head := <-w.chainHeadCh: 351 clearPending(head.Block.NumberU64()) 352 timestamp = time.Now().Unix() 353 commit(false, commitInterruptNewHead) 354 355 case <-timer.C: 356 // If mining is running resubmit a new work cycle periodically to pull in 357 // higher priced transactions. Disable this overhead for pending blocks. 358 if w.isRunning() && (w.config.Clique == nil || w.config.Clique.Period > 0) { 359 // Short circuit if no new transaction arrives. 360 if atomic.LoadInt32(&w.newTxs) == 0 { 361 timer.Reset(recommit) 362 continue 363 } 364 commit(true, commitInterruptResubmit) 365 } 366 367 case interval := <-w.resubmitIntervalCh: 368 // Adjust resubmit interval explicitly by user. 369 if interval < minRecommitInterval { 370 log.Warn("Sanitizing miner recommit interval", "provided", interval, "updated", minRecommitInterval) 371 interval = minRecommitInterval 372 } 373 log.Info("Miner recommit interval update", "from", minRecommit, "to", interval) 374 minRecommit, recommit = interval, interval 375 376 if w.resubmitHook != nil { 377 w.resubmitHook(minRecommit, recommit) 378 } 379 380 case adjust := <-w.resubmitAdjustCh: 381 // Adjust resubmit interval by feedback. 382 if adjust.inc { 383 before := recommit 384 recalcRecommit(float64(recommit.Nanoseconds())/adjust.ratio, true) 385 log.Trace("Increase miner recommit interval", "from", before, "to", recommit) 386 } else { 387 before := recommit 388 recalcRecommit(float64(minRecommit.Nanoseconds()), false) 389 log.Trace("Decrease miner recommit interval", "from", before, "to", recommit) 390 } 391 392 if w.resubmitHook != nil { 393 w.resubmitHook(minRecommit, recommit) 394 } 395 396 case <-w.exitCh: 397 return 398 } 399 } 400 } 401 402 // mainLoop is a standalone goroutine to regenerate the sealing task based on the received event. 403 func (w *worker) mainLoop() { 404 defer w.txsSub.Unsubscribe() 405 defer w.chainHeadSub.Unsubscribe() 406 defer w.chainSideSub.Unsubscribe() 407 408 for { 409 select { 410 case req := <-w.newWorkCh: 411 w.commitNewWork(req.interrupt, req.noempty, req.timestamp) 412 413 case ev := <-w.chainSideCh: 414 // Short circuit for duplicate side blocks 415 if _, exist := w.localUncles[ev.Block.Hash()]; exist { 416 continue 417 } 418 if _, exist := w.remoteUncles[ev.Block.Hash()]; exist { 419 continue 420 } 421 // Add side block to possible uncle block set depending on the author. 422 if w.isLocalBlock != nil && w.isLocalBlock(ev.Block) { 423 w.localUncles[ev.Block.Hash()] = ev.Block 424 } else { 425 w.remoteUncles[ev.Block.Hash()] = ev.Block 426 } 427 // If our mining block contains less than 2 uncle blocks, 428 // add the new uncle block if valid and regenerate a mining block. 429 if w.isRunning() && w.current != nil && w.current.uncles.Cardinality() < 2 { 430 start := time.Now() 431 if err := w.commitUncle(w.current, ev.Block.Header()); err == nil { 432 var uncles []*types.Header 433 w.current.uncles.Each(func(item interface{}) bool { 434 hash, ok := item.(common.Hash) 435 if !ok { 436 return false 437 } 438 uncle, exist := w.localUncles[hash] 439 if !exist { 440 uncle, exist = w.remoteUncles[hash] 441 } 442 if !exist { 443 return false 444 } 445 uncles = append(uncles, uncle.Header()) 446 return false 447 }) 448 w.commit(uncles, nil, true, start) 449 } 450 } 451 452 case ev := <-w.txsCh: 453 // Apply transactions to the pending state if we're not mining. 454 // 455 // Note all transactions received may not be continuous with transactions 456 // already included in the current mining block. These transactions will 457 // be automatically eliminated. 458 if !w.isRunning() && w.current != nil { 459 w.mu.RLock() 460 coinbase := w.coinbase 461 w.mu.RUnlock() 462 463 txs := make(map[common.Address]types.Transactions) 464 for _, tx := range ev.Txs { 465 acc, _ := types.Sender(w.current.signer, tx) 466 txs[acc] = append(txs[acc], tx) 467 } 468 txset := types.NewTransactionsByPriceAndNonce(w.current.signer, txs) 469 w.commitTransactions(txset, coinbase, nil) 470 w.updateSnapshot() 471 } else { 472 // If we're mining, but nothing is being processed, wake on new transactions 473 if w.config.Clique != nil && w.config.Clique.Period == 0 { 474 w.commitNewWork(nil, false, time.Now().Unix()) 475 } 476 } 477 atomic.AddInt32(&w.newTxs, int32(len(ev.Txs))) 478 479 // System stopped 480 case <-w.exitCh: 481 return 482 case <-w.txsSub.Err(): 483 return 484 case <-w.chainHeadSub.Err(): 485 return 486 case <-w.chainSideSub.Err(): 487 return 488 } 489 } 490 } 491 492 // taskLoop is a standalone goroutine to fetch sealing task from the generator and 493 // push them to consensus engine. 494 func (w *worker) taskLoop() { 495 var ( 496 stopCh chan struct{} 497 prev common.Hash 498 ) 499 500 // interrupt aborts the in-flight sealing task. 501 interrupt := func() { 502 if stopCh != nil { 503 close(stopCh) 504 stopCh = nil 505 } 506 } 507 for { 508 select { 509 case task := <-w.taskCh: 510 if w.newTaskHook != nil { 511 w.newTaskHook(task) 512 } 513 // Reject duplicate sealing work due to resubmitting. 514 sealHash := w.engine.SealHash(task.block.Header()) 515 if sealHash == prev { 516 continue 517 } 518 // Interrupt previous sealing operation 519 interrupt() 520 stopCh, prev = make(chan struct{}), sealHash 521 522 if w.skipSealHook != nil && w.skipSealHook(task) { 523 continue 524 } 525 w.pendingMu.Lock() 526 w.pendingTasks[w.engine.SealHash(task.block.Header())] = task 527 w.pendingMu.Unlock() 528 529 if err := w.engine.Seal(w.chain, task.block, w.resultCh, stopCh); err != nil { 530 log.Warn("Block sealing failed", "err", err) 531 } 532 case <-w.exitCh: 533 interrupt() 534 return 535 } 536 } 537 } 538 539 // resultLoop is a standalone goroutine to handle sealing result submitting 540 // and flush relative data to the database. 541 func (w *worker) resultLoop() { 542 for { 543 select { 544 case block := <-w.resultCh: 545 // Short circuit when receiving empty result. 546 if block == nil { 547 continue 548 } 549 // Short circuit when receiving duplicate result caused by resubmitting. 550 if w.chain.HasBlock(block.Hash(), block.NumberU64()) { 551 continue 552 } 553 var ( 554 sealhash = w.engine.SealHash(block.Header()) 555 hash = block.Hash() 556 ) 557 w.pendingMu.RLock() 558 task, exist := w.pendingTasks[sealhash] 559 w.pendingMu.RUnlock() 560 if !exist { 561 log.Error("Block found but no relative pending task", "number", block.Number(), "sealhash", sealhash, "hash", hash) 562 continue 563 } 564 // Different block could share same sealhash, deep copy here to prevent write-write conflict. 565 var ( 566 receipts = make([]*types.Receipt, len(task.receipts)) 567 logs []*types.Log 568 ) 569 for i, receipt := range task.receipts { 570 receipts[i] = new(types.Receipt) 571 *receipts[i] = *receipt 572 // Update the block hash in all logs since it is now available and not when the 573 // receipt/log of individual transactions were created. 574 for _, log := range receipt.Logs { 575 log.BlockHash = hash 576 } 577 logs = append(logs, receipt.Logs...) 578 } 579 // Commit block and state to database. 580 stat, err := w.chain.WriteBlockWithState(block, receipts, task.state) 581 if err != nil { 582 log.Error("Failed writing block to chain", "err", err) 583 continue 584 } 585 log.Info("Successfully sealed new block", "number", block.Number(), "sealhash", sealhash, "hash", hash, 586 "elapsed", common.PrettyDuration(time.Since(task.createdAt))) 587 588 // Broadcast the block and announce chain insertion event 589 w.mux.Post(core.NewMinedBlockEvent{Block: block}) 590 591 var events []interface{} 592 switch stat { 593 case core.CanonStatTy: 594 events = append(events, core.ChainEvent{Block: block, Hash: block.Hash(), Logs: logs}) 595 events = append(events, core.ChainHeadEvent{Block: block}) 596 case core.SideStatTy: 597 events = append(events, core.ChainSideEvent{Block: block}) 598 } 599 w.chain.PostChainEvents(events, logs) 600 601 // Insert the block into the set of pending ones to resultLoop for confirmations 602 w.unconfirmed.Insert(block.NumberU64(), block.Hash()) 603 604 case <-w.exitCh: 605 return 606 } 607 } 608 } 609 610 // makeCurrent creates a new environment for the current cycle. 611 func (w *worker) makeCurrent(parent *types.Block, header *types.Header) error { 612 state, err := w.chain.StateAt(parent.Root()) 613 if err != nil { 614 return err 615 } 616 env := &environment{ 617 signer: types.NewEIP155Signer(w.config.ChainID), 618 state: state, 619 ancestors: mapset.NewSet(), 620 family: mapset.NewSet(), 621 uncles: mapset.NewSet(), 622 header: header, 623 } 624 625 // when 08 is processed ancestors contain 07 (quick block) 626 for _, ancestor := range w.chain.GetBlocksFromHash(parent.Hash(), 7) { 627 for _, uncle := range ancestor.Uncles() { 628 env.family.Add(uncle.Hash()) 629 } 630 env.family.Add(ancestor.Hash()) 631 env.ancestors.Add(ancestor.Hash()) 632 } 633 634 // Keep track of transactions which return errors so they can be removed 635 env.tcount = 0 636 w.current = env 637 return nil 638 } 639 640 // commitUncle adds the given block to uncle block set, returns error if failed to add. 641 func (w *worker) commitUncle(env *environment, uncle *types.Header) error { 642 hash := uncle.Hash() 643 if env.uncles.Contains(hash) { 644 return errors.New("uncle not unique") 645 } 646 if env.header.ParentHash == uncle.ParentHash { 647 return errors.New("uncle is sibling") 648 } 649 if !env.ancestors.Contains(uncle.ParentHash) { 650 return errors.New("uncle's parent unknown") 651 } 652 if env.family.Contains(hash) { 653 return errors.New("uncle already included") 654 } 655 env.uncles.Add(uncle.Hash()) 656 return nil 657 } 658 659 // updateSnapshot updates pending snapshot block and state. 660 // Note this function assumes the current variable is thread safe. 661 func (w *worker) updateSnapshot() { 662 w.snapshotMu.Lock() 663 defer w.snapshotMu.Unlock() 664 665 var uncles []*types.Header 666 w.current.uncles.Each(func(item interface{}) bool { 667 hash, ok := item.(common.Hash) 668 if !ok { 669 return false 670 } 671 uncle, exist := w.localUncles[hash] 672 if !exist { 673 uncle, exist = w.remoteUncles[hash] 674 } 675 if !exist { 676 return false 677 } 678 uncles = append(uncles, uncle.Header()) 679 return false 680 }) 681 682 w.snapshotBlock = types.NewBlock( 683 w.current.header, 684 w.current.txs, 685 uncles, 686 w.current.receipts, 687 ) 688 689 w.snapshotState = w.current.state.Copy() 690 } 691 692 func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) { 693 snap := w.current.state.Snapshot() 694 695 receipt, _, err := core.ApplyTransaction(w.config, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.GasUsed, vm.Config{}) 696 if err != nil { 697 w.current.state.RevertToSnapshot(snap) 698 return nil, err 699 } 700 w.current.txs = append(w.current.txs, tx) 701 w.current.receipts = append(w.current.receipts, receipt) 702 703 return receipt.Logs, nil 704 } 705 706 func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coinbase common.Address, interrupt *int32) bool { 707 // Short circuit if current is nil 708 if w.current == nil { 709 return true 710 } 711 712 if w.current.gasPool == nil { 713 w.current.gasPool = new(core.GasPool).AddGas(w.current.header.GasLimit) 714 } 715 716 var coalescedLogs []*types.Log 717 718 for { 719 // In the following three cases, we will interrupt the execution of the transaction. 720 // (1) new head block event arrival, the interrupt signal is 1 721 // (2) worker start or restart, the interrupt signal is 1 722 // (3) worker recreate the mining block with any newly arrived transactions, the interrupt signal is 2. 723 // For the first two cases, the semi-finished work will be discarded. 724 // For the third case, the semi-finished work will be submitted to the consensus engine. 725 if interrupt != nil && atomic.LoadInt32(interrupt) != commitInterruptNone { 726 // Notify resubmit loop to increase resubmitting interval due to too frequent commits. 727 if atomic.LoadInt32(interrupt) == commitInterruptResubmit { 728 ratio := float64(w.current.header.GasLimit-w.current.gasPool.Gas()) / float64(w.current.header.GasLimit) 729 if ratio < 0.1 { 730 ratio = 0.1 731 } 732 w.resubmitAdjustCh <- &intervalAdjust{ 733 ratio: ratio, 734 inc: true, 735 } 736 } 737 return atomic.LoadInt32(interrupt) == commitInterruptNewHead 738 } 739 // If we don't have enough gas for any further transactions then we're done 740 if w.current.gasPool.Gas() < params.TxGas { 741 log.Trace("Not enough gas for further transactions", "have", w.current.gasPool, "want", params.TxGas) 742 break 743 } 744 // Retrieve the next transaction and abort if all done 745 tx := txs.Peek() 746 if tx == nil { 747 break 748 } 749 // Error may be ignored here. The error has already been checked 750 // during transaction acceptance is the transaction pool. 751 // 752 // We use the eip155 signer regardless of the current hf. 753 from, _ := types.Sender(w.current.signer, tx) 754 // Check whether the tx is replay protected. If we're not in the EIP155 hf 755 // phase, start ignoring the sender until we do. 756 if tx.Protected() && !w.config.IsEIP155(w.current.header.Number) { 757 log.Trace("Ignoring reply protected transaction", "hash", tx.Hash(), "eip155", w.config.EIP155Block) 758 759 txs.Pop() 760 continue 761 } 762 // Start executing the transaction 763 w.current.state.Prepare(tx.Hash(), common.Hash{}, w.current.tcount) 764 765 logs, err := w.commitTransaction(tx, coinbase) 766 switch err { 767 case core.ErrGasLimitReached: 768 // Pop the current out-of-gas transaction without shifting in the next from the account 769 log.Trace("Gas limit exceeded for current block", "sender", from) 770 txs.Pop() 771 772 case core.ErrNonceTooLow: 773 // New head notification data race between the transaction pool and miner, shift 774 log.Trace("Skipping transaction with low nonce", "sender", from, "nonce", tx.Nonce()) 775 txs.Shift() 776 777 case core.ErrNonceTooHigh: 778 // Reorg notification data race between the transaction pool and miner, skip account = 779 log.Trace("Skipping account with hight nonce", "sender", from, "nonce", tx.Nonce()) 780 txs.Pop() 781 782 case nil: 783 // Everything ok, collect the logs and shift in the next transaction from the same account 784 coalescedLogs = append(coalescedLogs, logs...) 785 w.current.tcount++ 786 txs.Shift() 787 788 default: 789 // Strange error, discard the transaction and get the next in line (note, the 790 // nonce-too-high clause will prevent us from executing in vain). 791 log.Debug("Transaction failed, account skipped", "hash", tx.Hash(), "err", err) 792 txs.Shift() 793 } 794 } 795 796 if !w.isRunning() && len(coalescedLogs) > 0 { 797 // We don't push the pendingLogsEvent while we are mining. The reason is that 798 // when we are mining, the worker will regenerate a mining block every 3 seconds. 799 // In order to avoid pushing the repeated pendingLog, we disable the pending log pushing. 800 801 // make a copy, the state caches the logs and these logs get "upgraded" from pending to mined 802 // logs by filling in the block hash when the block was mined by the local miner. This can 803 // cause a race condition if a log was "upgraded" before the PendingLogsEvent is processed. 804 cpy := make([]*types.Log, len(coalescedLogs)) 805 for i, l := range coalescedLogs { 806 cpy[i] = new(types.Log) 807 *cpy[i] = *l 808 } 809 go w.mux.Post(core.PendingLogsEvent{Logs: cpy}) 810 } 811 // Notify resubmit loop to decrease resubmitting interval if current interval is larger 812 // than the user-specified one. 813 if interrupt != nil { 814 w.resubmitAdjustCh <- &intervalAdjust{inc: false} 815 } 816 return false 817 } 818 819 // commitNewWork generates several new sealing tasks based on the parent block. 820 func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) { 821 w.mu.RLock() 822 defer w.mu.RUnlock() 823 824 tstart := time.Now() 825 parent := w.chain.CurrentBlock() 826 827 if parent.Time().Cmp(new(big.Int).SetInt64(timestamp)) >= 0 { 828 timestamp = parent.Time().Int64() + 1 829 } 830 // this will ensure we're not going off too far in the future 831 if now := time.Now().Unix(); timestamp > now+1 { 832 wait := time.Duration(timestamp-now) * time.Second 833 log.Info("Mining too far in the future", "wait", common.PrettyDuration(wait)) 834 time.Sleep(wait) 835 } 836 837 num := parent.Number() 838 header := &types.Header{ 839 ParentHash: parent.Hash(), 840 Number: num.Add(num, common.Big1), 841 GasLimit: core.CalcGasLimit(parent, w.gasFloor, w.gasCeil), 842 Extra: w.extra, 843 Time: big.NewInt(timestamp), 844 } 845 // Only set the coinbase if our consensus engine is running (avoid spurious block rewards) 846 if w.isRunning() { 847 if w.coinbase == (common.Address{}) { 848 log.Error("Refusing to mine without etherbase") 849 return 850 } 851 header.Coinbase = w.coinbase 852 } 853 if err := w.engine.Prepare(w.chain, header); err != nil { 854 log.Error("Failed to prepare header for mining", "err", err) 855 return 856 } 857 // If we are care about TheDAO hard-fork check whether to override the extra-data or not 858 if daoBlock := w.config.DAOForkBlock; daoBlock != nil { 859 // Check whether the block is among the fork extra-override range 860 limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange) 861 if header.Number.Cmp(daoBlock) >= 0 && header.Number.Cmp(limit) < 0 { 862 // Depending whether we support or oppose the fork, override differently 863 if w.config.DAOForkSupport { 864 header.Extra = common.CopyBytes(params.DAOForkBlockExtra) 865 } else if bytes.Equal(header.Extra, params.DAOForkBlockExtra) { 866 header.Extra = []byte{} // If miner opposes, don't let it use the reserved extra-data 867 } 868 } 869 } 870 // Could potentially happen if starting to mine in an odd state. 871 err := w.makeCurrent(parent, header) 872 if err != nil { 873 log.Error("Failed to create mining context", "err", err) 874 return 875 } 876 // Create the current work task and check any fork transitions needed 877 env := w.current 878 if w.config.DAOForkSupport && w.config.DAOForkBlock != nil && w.config.DAOForkBlock.Cmp(header.Number) == 0 { 879 misc.ApplyDAOHardFork(env.state) 880 } 881 // Accumulate the uncles for the current block 882 uncles := make([]*types.Header, 0, 2) 883 commitUncles := func(blocks map[common.Hash]*types.Block) { 884 // Clean up stale uncle blocks first 885 for hash, uncle := range blocks { 886 if uncle.NumberU64()+staleThreshold <= header.Number.Uint64() { 887 delete(blocks, hash) 888 } 889 } 890 for hash, uncle := range blocks { 891 if len(uncles) == 2 { 892 break 893 } 894 if err := w.commitUncle(env, uncle.Header()); err != nil { 895 log.Trace("Possible uncle rejected", "hash", hash, "reason", err) 896 } else { 897 log.Debug("Committing new uncle to block", "hash", hash) 898 uncles = append(uncles, uncle.Header()) 899 } 900 } 901 } 902 // Prefer to locally generated uncle 903 commitUncles(w.localUncles) 904 commitUncles(w.remoteUncles) 905 906 if !noempty { 907 // Create an empty block based on temporary copied state for sealing in advance without waiting block 908 // execution finished. 909 w.commit(uncles, nil, false, tstart) 910 } 911 912 // Fill the block with all available pending transactions. 913 pending, err := w.eth.TxPool().Pending() 914 if err != nil { 915 log.Error("Failed to fetch pending transactions", "err", err) 916 return 917 } 918 // Short circuit if there is no available pending transactions 919 if len(pending) == 0 { 920 w.updateSnapshot() 921 return 922 } 923 // Split the pending transactions into locals and remotes 924 localTxs, remoteTxs := make(map[common.Address]types.Transactions), pending 925 for _, account := range w.eth.TxPool().Locals() { 926 if txs := remoteTxs[account]; len(txs) > 0 { 927 delete(remoteTxs, account) 928 localTxs[account] = txs 929 } 930 } 931 if len(localTxs) > 0 { 932 txs := types.NewTransactionsByPriceAndNonce(w.current.signer, localTxs) 933 if w.commitTransactions(txs, w.coinbase, interrupt) { 934 return 935 } 936 } 937 if len(remoteTxs) > 0 { 938 txs := types.NewTransactionsByPriceAndNonce(w.current.signer, remoteTxs) 939 if w.commitTransactions(txs, w.coinbase, interrupt) { 940 return 941 } 942 } 943 w.commit(uncles, w.fullTaskHook, true, tstart) 944 } 945 946 // commit runs any post-transaction state modifications, assembles the final block 947 // and commits new work if consensus engine is running. 948 func (w *worker) commit(uncles []*types.Header, interval func(), update bool, start time.Time) error { 949 // Deep copy receipts here to avoid interaction between different tasks. 950 receipts := make([]*types.Receipt, len(w.current.receipts)) 951 for i, l := range w.current.receipts { 952 receipts[i] = new(types.Receipt) 953 *receipts[i] = *l 954 } 955 s := w.current.state.Copy() 956 block, err := w.engine.Finalize(w.chain, w.current.header, s, w.current.txs, uncles, w.current.receipts) 957 if err != nil { 958 return err 959 } 960 if w.isRunning() { 961 if interval != nil { 962 interval() 963 } 964 select { 965 case w.taskCh <- &task{receipts: receipts, state: s, block: block, createdAt: time.Now()}: 966 w.unconfirmed.Shift(block.NumberU64() - 1) 967 968 feesWei := new(big.Int) 969 for i, tx := range block.Transactions() { 970 feesWei.Add(feesWei, new(big.Int).Mul(new(big.Int).SetUint64(receipts[i].GasUsed), tx.GasPrice())) 971 } 972 feesEth := new(big.Float).Quo(new(big.Float).SetInt(feesWei), new(big.Float).SetInt(big.NewInt(params.Ether))) 973 974 log.Info("Commit new mining work", "number", block.Number(), "sealhash", w.engine.SealHash(block.Header()), 975 "uncles", len(uncles), "txs", w.current.tcount, "gas", block.GasUsed(), "fees", feesEth, "elapsed", common.PrettyDuration(time.Since(start))) 976 977 case <-w.exitCh: 978 log.Info("Worker has exited") 979 } 980 } 981 if update { 982 w.updateSnapshot() 983 } 984 return nil 985 }