| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright 2015 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-23 18:35:11 +02:00
										 |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-04 05:52:59 -08:00
										 |  |  | package miner | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2016-07-08 18:48:17 +03:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2015-02-04 05:52:59 -08:00
										 |  |  | 	"math/big" | 
					
						
							| 
									
										
										
										
											2015-02-15 16:16:27 +01:00
										 |  |  | 	"sync" | 
					
						
							| 
									
										
										
										
											2015-03-26 17:45:03 +01:00
										 |  |  | 	"sync/atomic" | 
					
						
							| 
									
										
										
										
											2015-06-15 11:33:08 +02:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2015-02-04 05:52:59 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-16 00:54:19 -07:00
										 |  |  | 	mapset "github.com/deckarep/golang-set" | 
					
						
							| 
									
										
										
										
											2015-03-18 13:00:01 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 	"github.com/ethereum/go-ethereum/consensus" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/consensus/misc" | 
					
						
							| 
									
										
										
										
											2015-02-04 05:52:59 -08:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core" | 
					
						
							| 
									
										
										
										
											2015-03-23 18:27:05 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/state" | 
					
						
							| 
									
										
										
										
											2015-02-04 05:52:59 -08:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/types" | 
					
						
							| 
									
										
										
										
											2015-08-30 10:19:10 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core/vm" | 
					
						
							| 
									
										
										
										
											2015-02-04 05:52:59 -08:00
										 |  |  | 	"github.com/ethereum/go-ethereum/event" | 
					
						
							| 
									
										
										
										
											2017-02-22 14:10:07 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/log" | 
					
						
							| 
									
										
										
										
											2016-07-08 13:00:37 +03:00
										 |  |  | 	"github.com/ethereum/go-ethereum/params" | 
					
						
							| 
									
										
										
										
											2015-02-04 05:52:59 -08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | const ( | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	// resultQueueSize is the size of channel listening to sealing result. | 
					
						
							|  |  |  | 	resultQueueSize = 10 | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-18 11:45:52 +03:00
										 |  |  | 	// txChanSize is the size of channel listening to NewTxsEvent. | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 	// The number is referenced from the size of tx pool. | 
					
						
							|  |  |  | 	txChanSize = 4096 | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 	// chainHeadChanSize is the size of channel listening to ChainHeadEvent. | 
					
						
							|  |  |  | 	chainHeadChanSize = 10 | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 	// chainSideChanSize is the size of channel listening to ChainSideEvent. | 
					
						
							|  |  |  | 	chainSideChanSize = 10 | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 	// resubmitAdjustChanSize is the size of resubmitting interval adjustment channel. | 
					
						
							|  |  |  | 	resubmitAdjustChanSize = 10 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 	// miningLogAtDepth is the number of confirmations before logging successful mining. | 
					
						
							| 
									
										
										
										
											2018-08-23 15:44:27 +03:00
										 |  |  | 	miningLogAtDepth = 7 | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 	// minRecommitInterval is the minimal time interval to recreate the mining block with | 
					
						
							|  |  |  | 	// any newly arrived transactions. | 
					
						
							|  |  |  | 	minRecommitInterval = 1 * time.Second | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// maxRecommitInterval is the maximum time interval to recreate the mining block with | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 	// any newly arrived transactions. | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 	maxRecommitInterval = 15 * time.Second | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// intervalAdjustRatio is the impact a single interval adjustment has on sealing work | 
					
						
							|  |  |  | 	// resubmitting interval. | 
					
						
							|  |  |  | 	intervalAdjustRatio = 0.1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// intervalAdjustBias is applied during the new resubmit interval calculation in favor of | 
					
						
							|  |  |  | 	// increasing upper limit or decreasing lower limit so that the limit can be reachable. | 
					
						
							|  |  |  | 	intervalAdjustBias = 200 * 1000.0 * 1000.0 | 
					
						
							| 
									
										
										
										
											2018-08-23 21:02:57 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 21:59:05 +08:00
										 |  |  | 	// staleThreshold is the maximum depth of the acceptable stale block. | 
					
						
							| 
									
										
										
										
											2018-08-23 21:02:57 +08:00
										 |  |  | 	staleThreshold = 7 | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2015-05-11 21:47:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | // environment is the worker's current environment and holds all of the current state information. | 
					
						
							|  |  |  | type environment struct { | 
					
						
							| 
									
										
										
										
											2016-11-02 13:44:13 +01:00
										 |  |  | 	signer types.Signer | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	state     *state.StateDB // apply state changes here | 
					
						
							| 
									
										
										
										
											2018-07-16 00:54:19 -07:00
										 |  |  | 	ancestors mapset.Set     // ancestor set (used for checking uncle parent validity) | 
					
						
							|  |  |  | 	family    mapset.Set     // family set (used for checking uncle invalidity) | 
					
						
							|  |  |  | 	uncles    mapset.Set     // uncle set | 
					
						
							| 
									
										
										
										
											2017-05-16 22:07:27 +03:00
										 |  |  | 	tcount    int            // tx count in cycle | 
					
						
							| 
									
										
										
										
											2018-05-18 11:45:52 +03:00
										 |  |  | 	gasPool   *core.GasPool  // available gas used to pack transactions | 
					
						
							| 
									
										
										
										
											2015-02-04 05:52:59 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-16 12:41:50 +02:00
										 |  |  | 	header   *types.Header | 
					
						
							|  |  |  | 	txs      []*types.Transaction | 
					
						
							|  |  |  | 	receipts []*types.Receipt | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-07-11 20:45:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | // task contains all information for consensus engine sealing and result submitting. | 
					
						
							|  |  |  | type task struct { | 
					
						
							|  |  |  | 	receipts  []*types.Receipt | 
					
						
							|  |  |  | 	state     *state.StateDB | 
					
						
							|  |  |  | 	block     *types.Block | 
					
						
							|  |  |  | 	createdAt time.Time | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | const ( | 
					
						
							|  |  |  | 	commitInterruptNone int32 = iota | 
					
						
							|  |  |  | 	commitInterruptNewHead | 
					
						
							|  |  |  | 	commitInterruptResubmit | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | // newWorkReq represents a request for new sealing work submitting with relative interrupt notifier. | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | type newWorkReq struct { | 
					
						
							|  |  |  | 	interrupt *int32 | 
					
						
							|  |  |  | 	noempty   bool | 
					
						
							| 
									
										
										
										
											2018-08-29 22:31:59 +08:00
										 |  |  | 	timestamp int64 | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | // intervalAdjust represents a resubmitting interval adjustment. | 
					
						
							|  |  |  | type intervalAdjust struct { | 
					
						
							|  |  |  | 	ratio float64 | 
					
						
							|  |  |  | 	inc   bool | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | // worker is the main object which takes care of submitting new work to consensus engine | 
					
						
							|  |  |  | // and gathering the sealing result. | 
					
						
							| 
									
										
										
										
											2015-02-04 05:52:59 -08:00
										 |  |  | type worker struct { | 
					
						
							| 
									
										
										
										
											2016-10-20 13:36:29 +02:00
										 |  |  | 	config *params.ChainConfig | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 	engine consensus.Engine | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	eth    Backend | 
					
						
							|  |  |  | 	chain  *core.BlockChain | 
					
						
							| 
									
										
										
										
											2016-03-01 23:32:43 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-29 12:21:12 +03:00
										 |  |  | 	gasFloor uint64 | 
					
						
							|  |  |  | 	gasCeil  uint64 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	// Subscriptions | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 	mux          *event.TypeMux | 
					
						
							| 
									
										
										
										
											2018-05-18 11:45:52 +03:00
										 |  |  | 	txsCh        chan core.NewTxsEvent | 
					
						
							| 
									
										
										
										
											2018-05-10 15:04:45 +08:00
										 |  |  | 	txsSub       event.Subscription | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 	chainHeadCh  chan core.ChainHeadEvent | 
					
						
							|  |  |  | 	chainHeadSub event.Subscription | 
					
						
							|  |  |  | 	chainSideCh  chan core.ChainSideEvent | 
					
						
							|  |  |  | 	chainSideSub event.Subscription | 
					
						
							| 
									
										
										
										
											2016-03-29 03:08:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	// Channels | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 	newWorkCh          chan *newWorkReq | 
					
						
							|  |  |  | 	taskCh             chan *task | 
					
						
							| 
									
										
										
										
											2018-08-28 21:59:05 +08:00
										 |  |  | 	resultCh           chan *types.Block | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 	startCh            chan struct{} | 
					
						
							|  |  |  | 	exitCh             chan struct{} | 
					
						
							|  |  |  | 	resubmitIntervalCh chan time.Duration | 
					
						
							|  |  |  | 	resubmitAdjustCh   chan *intervalAdjust | 
					
						
							| 
									
										
										
										
											2015-02-04 05:52:59 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 	current        *environment                 // An environment for current running cycle. | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	possibleUncles map[common.Hash]*types.Block // A set of side blocks as the possible uncle blocks. | 
					
						
							|  |  |  | 	unconfirmed    *unconfirmedBlocks           // A set of locally mined blocks pending canonicalness confirmations. | 
					
						
							| 
									
										
										
										
											2015-04-05 18:57:03 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	mu       sync.RWMutex // The lock used to protect the coinbase and extra fields | 
					
						
							| 
									
										
										
										
											2015-03-18 13:00:01 +01:00
										 |  |  | 	coinbase common.Address | 
					
						
							| 
									
										
										
										
											2015-04-05 18:57:03 +02:00
										 |  |  | 	extra    []byte | 
					
						
							| 
									
										
										
										
											2015-02-04 05:52:59 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-23 21:02:57 +08:00
										 |  |  | 	pendingMu    sync.RWMutex | 
					
						
							|  |  |  | 	pendingTasks map[common.Hash]*task | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	snapshotMu    sync.RWMutex // The lock used to protect the block snapshot and state snapshot | 
					
						
							| 
									
										
										
										
											2018-04-16 00:56:20 -07:00
										 |  |  | 	snapshotBlock *types.Block | 
					
						
							|  |  |  | 	snapshotState *state.StateDB | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-22 10:58:43 +02:00
										 |  |  | 	// atomic status counters | 
					
						
							| 
									
										
										
										
											2018-08-03 16:33:37 +08:00
										 |  |  | 	running int32 // The indicator whether the consensus engine is running or not. | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 	newTxs  int32 // New arrival transaction count since last sealing work submitting. | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Test hooks | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 	newTaskHook  func(*task)                        // Method to call upon receiving a new sealing task. | 
					
						
							|  |  |  | 	skipSealHook func(*task) bool                   // Method to decide whether skipping the sealing. | 
					
						
							|  |  |  | 	fullTaskHook func()                             // Method to call before pushing the full sealing task. | 
					
						
							|  |  |  | 	resubmitHook func(time.Duration, time.Duration) // Method to call upon updating resubmitting interval. | 
					
						
							| 
									
										
										
										
											2015-02-04 05:52:59 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-29 12:21:12 +03:00
										 |  |  | func newWorker(config *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux, recommit time.Duration, gasFloor, gasCeil uint64) *worker { | 
					
						
							| 
									
										
										
										
											2015-04-07 12:32:55 +02:00
										 |  |  | 	worker := &worker{ | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 		config:             config, | 
					
						
							|  |  |  | 		engine:             engine, | 
					
						
							|  |  |  | 		eth:                eth, | 
					
						
							|  |  |  | 		mux:                mux, | 
					
						
							|  |  |  | 		chain:              eth.BlockChain(), | 
					
						
							| 
									
										
										
										
											2018-08-29 12:21:12 +03:00
										 |  |  | 		gasFloor:           gasFloor, | 
					
						
							|  |  |  | 		gasCeil:            gasCeil, | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 		possibleUncles:     make(map[common.Hash]*types.Block), | 
					
						
							|  |  |  | 		unconfirmed:        newUnconfirmedBlocks(eth.BlockChain(), miningLogAtDepth), | 
					
						
							| 
									
										
										
										
											2018-08-23 21:02:57 +08:00
										 |  |  | 		pendingTasks:       make(map[common.Hash]*task), | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 		txsCh:              make(chan core.NewTxsEvent, txChanSize), | 
					
						
							|  |  |  | 		chainHeadCh:        make(chan core.ChainHeadEvent, chainHeadChanSize), | 
					
						
							|  |  |  | 		chainSideCh:        make(chan core.ChainSideEvent, chainSideChanSize), | 
					
						
							|  |  |  | 		newWorkCh:          make(chan *newWorkReq), | 
					
						
							|  |  |  | 		taskCh:             make(chan *task), | 
					
						
							| 
									
										
										
										
											2018-08-28 21:59:05 +08:00
										 |  |  | 		resultCh:           make(chan *types.Block, resultQueueSize), | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 		exitCh:             make(chan struct{}), | 
					
						
							|  |  |  | 		startCh:            make(chan struct{}, 1), | 
					
						
							|  |  |  | 		resubmitIntervalCh: make(chan time.Duration), | 
					
						
							|  |  |  | 		resubmitAdjustCh:   make(chan *intervalAdjust, resubmitAdjustChanSize), | 
					
						
							| 
									
										
										
										
											2015-02-09 16:20:34 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-05-18 11:45:52 +03:00
										 |  |  | 	// Subscribe NewTxsEvent for tx pool | 
					
						
							|  |  |  | 	worker.txsSub = eth.TxPool().SubscribeNewTxsEvent(worker.txsCh) | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 	// Subscribe events for blockchain | 
					
						
							|  |  |  | 	worker.chainHeadSub = eth.BlockChain().SubscribeChainHeadEvent(worker.chainHeadCh) | 
					
						
							|  |  |  | 	worker.chainSideSub = eth.BlockChain().SubscribeChainSideEvent(worker.chainSideCh) | 
					
						
							| 
									
										
										
										
											2015-04-07 12:32:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 	// Sanitize recommit interval if the user-specified one is too short. | 
					
						
							|  |  |  | 	if recommit < minRecommitInterval { | 
					
						
							|  |  |  | 		log.Warn("Sanitizing miner recommit interval", "provided", recommit, "updated", minRecommitInterval) | 
					
						
							|  |  |  | 		recommit = minRecommitInterval | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	go worker.mainLoop() | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 	go worker.newWorkLoop(recommit) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	go worker.resultLoop() | 
					
						
							|  |  |  | 	go worker.taskLoop() | 
					
						
							| 
									
										
										
										
											2015-04-07 12:32:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	// Submit first work to initialize pending state. | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 	worker.startCh <- struct{}{} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-07 12:32:55 +02:00
										 |  |  | 	return worker | 
					
						
							| 
									
										
										
										
											2015-02-09 16:20:34 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | // setEtherbase sets the etherbase used to initialize the block coinbase field. | 
					
						
							|  |  |  | func (w *worker) setEtherbase(addr common.Address) { | 
					
						
							|  |  |  | 	w.mu.Lock() | 
					
						
							|  |  |  | 	defer w.mu.Unlock() | 
					
						
							|  |  |  | 	w.coinbase = addr | 
					
						
							| 
									
										
										
										
											2015-07-07 10:58:47 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | // setExtra sets the content used to initialize the block extra field. | 
					
						
							|  |  |  | func (w *worker) setExtra(extra []byte) { | 
					
						
							|  |  |  | 	w.mu.Lock() | 
					
						
							|  |  |  | 	defer w.mu.Unlock() | 
					
						
							|  |  |  | 	w.extra = extra | 
					
						
							| 
									
										
										
										
											2016-12-13 14:03:18 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | // setRecommitInterval updates the interval for miner sealing work recommitting. | 
					
						
							|  |  |  | func (w *worker) setRecommitInterval(interval time.Duration) { | 
					
						
							|  |  |  | 	w.resubmitIntervalCh <- interval | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | // pending returns the pending state and corresponding block. | 
					
						
							|  |  |  | func (w *worker) pending() (*types.Block, *state.StateDB) { | 
					
						
							| 
									
										
										
										
											2018-08-03 16:33:37 +08:00
										 |  |  | 	// return a snapshot to avoid contention on currentMu mutex | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	w.snapshotMu.RLock() | 
					
						
							|  |  |  | 	defer w.snapshotMu.RUnlock() | 
					
						
							|  |  |  | 	if w.snapshotState == nil { | 
					
						
							|  |  |  | 		return nil, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return w.snapshotBlock, w.snapshotState.Copy() | 
					
						
							| 
									
										
										
										
											2018-04-16 00:56:20 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-11-30 10:48:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | // pendingBlock returns pending block. | 
					
						
							|  |  |  | func (w *worker) pendingBlock() *types.Block { | 
					
						
							| 
									
										
										
										
											2018-08-03 16:33:37 +08:00
										 |  |  | 	// return a snapshot to avoid contention on currentMu mutex | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	w.snapshotMu.RLock() | 
					
						
							|  |  |  | 	defer w.snapshotMu.RUnlock() | 
					
						
							|  |  |  | 	return w.snapshotBlock | 
					
						
							| 
									
										
										
										
											2016-11-30 10:48:48 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | // start sets the running status as 1 and triggers new work submitting. | 
					
						
							|  |  |  | func (w *worker) start() { | 
					
						
							|  |  |  | 	atomic.StoreInt32(&w.running, 1) | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 	w.startCh <- struct{}{} | 
					
						
							| 
									
										
										
										
											2015-02-09 16:20:34 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | // stop sets the running status as 0. | 
					
						
							|  |  |  | func (w *worker) stop() { | 
					
						
							|  |  |  | 	atomic.StoreInt32(&w.running, 0) | 
					
						
							| 
									
										
										
										
											2015-02-09 16:20:34 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | // isRunning returns an indicator whether worker is running or not. | 
					
						
							|  |  |  | func (w *worker) isRunning() bool { | 
					
						
							|  |  |  | 	return atomic.LoadInt32(&w.running) == 1 | 
					
						
							| 
									
										
										
										
											2018-08-03 16:33:37 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-28 21:59:05 +08:00
										 |  |  | // close terminates all background threads maintained by the worker. | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | // Note the worker does not support being closed multiple times. | 
					
						
							|  |  |  | func (w *worker) close() { | 
					
						
							|  |  |  | 	close(w.exitCh) | 
					
						
							| 
									
										
										
										
											2015-02-04 05:52:59 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | // newWorkLoop is a standalone goroutine to submit new mining work upon received events. | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | func (w *worker) newWorkLoop(recommit time.Duration) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		interrupt   *int32 | 
					
						
							|  |  |  | 		minRecommit = recommit // minimal resubmit interval specified by user. | 
					
						
							| 
									
										
										
										
											2018-08-29 22:31:59 +08:00
										 |  |  | 		timestamp   int64      // timestamp for each round of mining. | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	timer := time.NewTimer(0) | 
					
						
							|  |  |  | 	<-timer.C // discard the initial tick | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 	// commit aborts in-flight transaction execution with given signal and resubmits a new one. | 
					
						
							|  |  |  | 	commit := func(noempty bool, s int32) { | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 		if interrupt != nil { | 
					
						
							|  |  |  | 			atomic.StoreInt32(interrupt, s) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		interrupt = new(int32) | 
					
						
							| 
									
										
										
										
											2018-08-29 22:31:59 +08:00
										 |  |  | 		w.newWorkCh <- &newWorkReq{interrupt: interrupt, noempty: noempty, timestamp: timestamp} | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 		timer.Reset(recommit) | 
					
						
							|  |  |  | 		atomic.StoreInt32(&w.newTxs, 0) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// recalcRecommit recalculates the resubmitting interval upon feedback. | 
					
						
							|  |  |  | 	recalcRecommit := func(target float64, inc bool) { | 
					
						
							|  |  |  | 		var ( | 
					
						
							|  |  |  | 			prev = float64(recommit.Nanoseconds()) | 
					
						
							|  |  |  | 			next float64 | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 		if inc { | 
					
						
							|  |  |  | 			next = prev*(1-intervalAdjustRatio) + intervalAdjustRatio*(target+intervalAdjustBias) | 
					
						
							|  |  |  | 			// Recap if interval is larger than the maximum time interval | 
					
						
							|  |  |  | 			if next > float64(maxRecommitInterval.Nanoseconds()) { | 
					
						
							|  |  |  | 				next = float64(maxRecommitInterval.Nanoseconds()) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			next = prev*(1-intervalAdjustRatio) + intervalAdjustRatio*(target-intervalAdjustBias) | 
					
						
							|  |  |  | 			// Recap if interval is less than the user specified minimum | 
					
						
							|  |  |  | 			if next < float64(minRecommit.Nanoseconds()) { | 
					
						
							|  |  |  | 				next = float64(minRecommit.Nanoseconds()) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		recommit = time.Duration(int64(next)) | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-23 21:02:57 +08:00
										 |  |  | 	// clearPending cleans the stale pending tasks. | 
					
						
							|  |  |  | 	clearPending := func(number uint64) { | 
					
						
							|  |  |  | 		w.pendingMu.Lock() | 
					
						
							|  |  |  | 		for h, t := range w.pendingTasks { | 
					
						
							|  |  |  | 			if t.block.NumberU64()+staleThreshold <= number { | 
					
						
							|  |  |  | 				delete(w.pendingTasks, h) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		w.pendingMu.Unlock() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-w.startCh: | 
					
						
							| 
									
										
										
										
											2018-08-23 21:02:57 +08:00
										 |  |  | 			clearPending(w.chain.CurrentBlock().NumberU64()) | 
					
						
							| 
									
										
										
										
											2018-08-29 22:31:59 +08:00
										 |  |  | 			timestamp = time.Now().Unix() | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 			commit(false, commitInterruptNewHead) | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-23 21:02:57 +08:00
										 |  |  | 		case head := <-w.chainHeadCh: | 
					
						
							|  |  |  | 			clearPending(head.Block.NumberU64()) | 
					
						
							| 
									
										
										
										
											2018-08-29 22:31:59 +08:00
										 |  |  | 			timestamp = time.Now().Unix() | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 			commit(false, commitInterruptNewHead) | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		case <-timer.C: | 
					
						
							|  |  |  | 			// If mining is running resubmit a new work cycle periodically to pull in | 
					
						
							|  |  |  | 			// higher priced transactions. Disable this overhead for pending blocks. | 
					
						
							|  |  |  | 			if w.isRunning() && (w.config.Clique == nil || w.config.Clique.Period > 0) { | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 				// Short circuit if no new transaction arrives. | 
					
						
							|  |  |  | 				if atomic.LoadInt32(&w.newTxs) == 0 { | 
					
						
							|  |  |  | 					timer.Reset(recommit) | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				commit(true, commitInterruptResubmit) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case interval := <-w.resubmitIntervalCh: | 
					
						
							|  |  |  | 			// Adjust resubmit interval explicitly by user. | 
					
						
							|  |  |  | 			if interval < minRecommitInterval { | 
					
						
							|  |  |  | 				log.Warn("Sanitizing miner recommit interval", "provided", interval, "updated", minRecommitInterval) | 
					
						
							|  |  |  | 				interval = minRecommitInterval | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			log.Info("Miner recommit interval update", "from", minRecommit, "to", interval) | 
					
						
							|  |  |  | 			minRecommit, recommit = interval, interval | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if w.resubmitHook != nil { | 
					
						
							|  |  |  | 				w.resubmitHook(minRecommit, recommit) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case adjust := <-w.resubmitAdjustCh: | 
					
						
							|  |  |  | 			// Adjust resubmit interval by feedback. | 
					
						
							|  |  |  | 			if adjust.inc { | 
					
						
							|  |  |  | 				before := recommit | 
					
						
							|  |  |  | 				recalcRecommit(float64(recommit.Nanoseconds())/adjust.ratio, true) | 
					
						
							|  |  |  | 				log.Trace("Increase miner recommit interval", "from", before, "to", recommit) | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				before := recommit | 
					
						
							|  |  |  | 				recalcRecommit(float64(minRecommit.Nanoseconds()), false) | 
					
						
							|  |  |  | 				log.Trace("Decrease miner recommit interval", "from", before, "to", recommit) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if w.resubmitHook != nil { | 
					
						
							|  |  |  | 				w.resubmitHook(minRecommit, recommit) | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case <-w.exitCh: | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | // mainLoop is a standalone goroutine to regenerate the sealing task based on the received event. | 
					
						
							|  |  |  | func (w *worker) mainLoop() { | 
					
						
							|  |  |  | 	defer w.txsSub.Unsubscribe() | 
					
						
							|  |  |  | 	defer w.chainHeadSub.Unsubscribe() | 
					
						
							|  |  |  | 	defer w.chainSideSub.Unsubscribe() | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 		case req := <-w.newWorkCh: | 
					
						
							| 
									
										
										
										
											2018-08-29 22:31:59 +08:00
										 |  |  | 			w.commitNewWork(req.interrupt, req.noempty, req.timestamp) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		case ev := <-w.chainSideCh: | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 			if _, exist := w.possibleUncles[ev.Block.Hash()]; exist { | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 			// Add side block to possible uncle block set. | 
					
						
							|  |  |  | 			w.possibleUncles[ev.Block.Hash()] = ev.Block | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 			// If our mining block contains less than 2 uncle blocks, | 
					
						
							|  |  |  | 			// add the new uncle block if valid and regenerate a mining block. | 
					
						
							|  |  |  | 			if w.isRunning() && w.current != nil && w.current.uncles.Cardinality() < 2 { | 
					
						
							|  |  |  | 				start := time.Now() | 
					
						
							|  |  |  | 				if err := w.commitUncle(w.current, ev.Block.Header()); err == nil { | 
					
						
							|  |  |  | 					var uncles []*types.Header | 
					
						
							|  |  |  | 					w.current.uncles.Each(func(item interface{}) bool { | 
					
						
							|  |  |  | 						hash, ok := item.(common.Hash) | 
					
						
							|  |  |  | 						if !ok { | 
					
						
							|  |  |  | 							return false | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						uncle, exist := w.possibleUncles[hash] | 
					
						
							|  |  |  | 						if !exist { | 
					
						
							|  |  |  | 							return false | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						uncles = append(uncles, uncle.Header()) | 
					
						
							| 
									
										
										
										
											2018-08-21 22:33:04 +08:00
										 |  |  | 						return false | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 					}) | 
					
						
							|  |  |  | 					w.commit(uncles, nil, true, start) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		case ev := <-w.txsCh: | 
					
						
							| 
									
										
										
										
											2018-05-10 15:04:45 +08:00
										 |  |  | 			// Apply transactions to the pending state if we're not mining. | 
					
						
							|  |  |  | 			// | 
					
						
							|  |  |  | 			// Note all transactions received may not be continuous with transactions | 
					
						
							|  |  |  | 			// already included in the current mining block. These transactions will | 
					
						
							|  |  |  | 			// be automatically eliminated. | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 			if !w.isRunning() && w.current != nil { | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 				w.mu.RLock() | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 				coinbase := w.coinbase | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 				w.mu.RUnlock() | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 15:04:45 +08:00
										 |  |  | 				txs := make(map[common.Address]types.Transactions) | 
					
						
							|  |  |  | 				for _, tx := range ev.Txs { | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 					acc, _ := types.Sender(w.current.signer, tx) | 
					
						
							| 
									
										
										
										
											2018-05-10 15:04:45 +08:00
										 |  |  | 					txs[acc] = append(txs[acc], tx) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 				txset := types.NewTransactionsByPriceAndNonce(w.current.signer, txs) | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 				w.commitTransactions(txset, coinbase, nil) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 				w.updateSnapshot() | 
					
						
							| 
									
										
										
										
											2017-10-24 13:40:42 +03:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				// If we're mining, but nothing is being processed, wake on new transactions | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 				if w.config.Clique != nil && w.config.Clique.Period == 0 { | 
					
						
							| 
									
										
										
										
											2018-08-29 22:31:59 +08:00
										 |  |  | 					w.commitNewWork(nil, false, time.Now().Unix()) | 
					
						
							| 
									
										
										
										
											2017-10-24 13:40:42 +03:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2015-02-04 05:52:59 -08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 			atomic.AddInt32(&w.newTxs, int32(len(ev.Txs))) | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// System stopped | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 		case <-w.exitCh: | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 			return | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 		case <-w.txsSub.Err(): | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 			return | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 		case <-w.chainHeadSub.Err(): | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		case <-w.chainSideSub.Err(): | 
					
						
							| 
									
										
										
										
											2017-08-18 18:58:36 +08:00
										 |  |  | 			return | 
					
						
							| 
									
										
										
										
											2015-02-04 05:52:59 -08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | // taskLoop is a standalone goroutine to fetch sealing task from the generator and | 
					
						
							|  |  |  | // push them to consensus engine. | 
					
						
							|  |  |  | func (w *worker) taskLoop() { | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 	var ( | 
					
						
							|  |  |  | 		stopCh chan struct{} | 
					
						
							|  |  |  | 		prev   common.Hash | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// interrupt aborts the in-flight sealing task. | 
					
						
							|  |  |  | 	interrupt := func() { | 
					
						
							|  |  |  | 		if stopCh != nil { | 
					
						
							|  |  |  | 			close(stopCh) | 
					
						
							|  |  |  | 			stopCh = nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-09 16:20:34 +01:00
										 |  |  | 	for { | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 		select { | 
					
						
							|  |  |  | 		case task := <-w.taskCh: | 
					
						
							|  |  |  | 			if w.newTaskHook != nil { | 
					
						
							|  |  |  | 				w.newTaskHook(task) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 			// Reject duplicate sealing work due to resubmitting. | 
					
						
							| 
									
										
										
										
											2018-08-23 21:02:57 +08:00
										 |  |  | 			sealHash := w.engine.SealHash(task.block.Header()) | 
					
						
							|  |  |  | 			if sealHash == prev { | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-08-28 21:59:05 +08:00
										 |  |  | 			// Interrupt previous sealing operation | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 			interrupt() | 
					
						
							| 
									
										
										
										
											2018-08-28 21:59:05 +08:00
										 |  |  | 			stopCh, prev = make(chan struct{}), sealHash | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if w.skipSealHook != nil && w.skipSealHook(task) { | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			w.pendingMu.Lock() | 
					
						
							|  |  |  | 			w.pendingTasks[w.engine.SealHash(task.block.Header())] = task | 
					
						
							|  |  |  | 			w.pendingMu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if err := w.engine.Seal(w.chain, task.block, w.resultCh, stopCh); err != nil { | 
					
						
							|  |  |  | 				log.Warn("Block sealing failed", "err", err) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 		case <-w.exitCh: | 
					
						
							|  |  |  | 			interrupt() | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-03-26 17:45:03 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | // resultLoop is a standalone goroutine to handle sealing result submitting | 
					
						
							|  |  |  | // and flush relative data to the database. | 
					
						
							|  |  |  | func (w *worker) resultLoop() { | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							| 
									
										
										
										
											2018-08-28 21:59:05 +08:00
										 |  |  | 		case block := <-w.resultCh: | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 			// Short circuit when receiving empty result. | 
					
						
							| 
									
										
										
										
											2018-08-28 21:59:05 +08:00
										 |  |  | 			if block == nil { | 
					
						
							| 
									
										
										
										
											2015-03-26 17:45:03 +01:00
										 |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 			// Short circuit when receiving duplicate result caused by resubmitting. | 
					
						
							|  |  |  | 			if w.chain.HasBlock(block.Hash(), block.NumberU64()) { | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-08-28 21:59:05 +08:00
										 |  |  | 			var ( | 
					
						
							|  |  |  | 				sealhash = w.engine.SealHash(block.Header()) | 
					
						
							|  |  |  | 				hash     = block.Hash() | 
					
						
							|  |  |  | 			) | 
					
						
							|  |  |  | 			w.pendingMu.RLock() | 
					
						
							|  |  |  | 			task, exist := w.pendingTasks[sealhash] | 
					
						
							|  |  |  | 			w.pendingMu.RUnlock() | 
					
						
							|  |  |  | 			if !exist { | 
					
						
							|  |  |  | 				log.Error("Block found but no relative pending task", "number", block.Number(), "sealhash", sealhash, "hash", hash) | 
					
						
							|  |  |  | 				continue | 
					
						
							| 
									
										
										
										
											2015-07-03 11:24:42 +02:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-08-28 21:59:05 +08:00
										 |  |  | 			// Different block could share same sealhash, deep copy here to prevent write-write conflict. | 
					
						
							|  |  |  | 			var ( | 
					
						
							|  |  |  | 				receipts = make([]*types.Receipt, len(task.receipts)) | 
					
						
							|  |  |  | 				logs     []*types.Log | 
					
						
							|  |  |  | 			) | 
					
						
							|  |  |  | 			for i, receipt := range task.receipts { | 
					
						
							|  |  |  | 				receipts[i] = new(types.Receipt) | 
					
						
							|  |  |  | 				*receipts[i] = *receipt | 
					
						
							|  |  |  | 				// Update the block hash in all logs since it is now available and not when the | 
					
						
							|  |  |  | 				// receipt/log of individual transactions were created. | 
					
						
							|  |  |  | 				for _, log := range receipt.Logs { | 
					
						
							|  |  |  | 					log.BlockHash = hash | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				logs = append(logs, receipt.Logs...) | 
					
						
							| 
									
										
										
										
											2017-09-11 13:13:05 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 			// Commit block and state to database. | 
					
						
							| 
									
										
										
										
											2018-08-28 21:59:05 +08:00
										 |  |  | 			stat, err := w.chain.WriteBlockWithState(block, receipts, task.state) | 
					
						
							| 
									
										
										
										
											2017-09-11 13:13:05 +03:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				log.Error("Failed writing block to chain", "err", err) | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-08-28 21:59:05 +08:00
										 |  |  | 			log.Info("Successfully sealed new block", "number", block.Number(), "sealhash", sealhash, "hash", hash, | 
					
						
							|  |  |  | 				"elapsed", common.PrettyDuration(time.Since(task.createdAt))) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-11 13:13:05 +03:00
										 |  |  | 			// Broadcast the block and announce chain insertion event | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 			w.mux.Post(core.NewMinedBlockEvent{Block: block}) | 
					
						
							| 
									
										
										
										
											2018-08-28 21:59:05 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			var events []interface{} | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 			switch stat { | 
					
						
							|  |  |  | 			case core.CanonStatTy: | 
					
						
							|  |  |  | 				events = append(events, core.ChainEvent{Block: block, Hash: block.Hash(), Logs: logs}) | 
					
						
							| 
									
										
										
										
											2017-09-11 13:13:05 +03:00
										 |  |  | 				events = append(events, core.ChainHeadEvent{Block: block}) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 			case core.SideStatTy: | 
					
						
							|  |  |  | 				events = append(events, core.ChainSideEvent{Block: block}) | 
					
						
							| 
									
										
										
										
											2017-09-11 13:13:05 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 			w.chain.PostChainEvents(events, logs) | 
					
						
							| 
									
										
										
										
											2017-09-11 13:13:05 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 			// Insert the block into the set of pending ones to resultLoop for confirmations | 
					
						
							|  |  |  | 			w.unconfirmed.Insert(block.NumberU64(), block.Hash()) | 
					
						
							| 
									
										
										
										
											2015-02-09 16:20:34 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 		case <-w.exitCh: | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-02-04 05:52:59 -08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-16 12:41:50 +02:00
										 |  |  | // makeCurrent creates a new environment for the current cycle. | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | func (w *worker) makeCurrent(parent *types.Block, header *types.Header) error { | 
					
						
							|  |  |  | 	state, err := w.chain.StateAt(parent.Root()) | 
					
						
							| 
									
										
										
										
											2015-10-06 16:35:55 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 	env := &environment{ | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 		signer:    types.NewEIP155Signer(w.config.ChainID), | 
					
						
							| 
									
										
										
										
											2015-06-16 12:41:50 +02:00
										 |  |  | 		state:     state, | 
					
						
							| 
									
										
										
										
											2018-07-16 00:54:19 -07:00
										 |  |  | 		ancestors: mapset.NewSet(), | 
					
						
							|  |  |  | 		family:    mapset.NewSet(), | 
					
						
							|  |  |  | 		uncles:    mapset.NewSet(), | 
					
						
							| 
									
										
										
										
											2015-06-16 12:41:50 +02:00
										 |  |  | 		header:    header, | 
					
						
							| 
									
										
										
										
											2015-04-04 13:27:17 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-05 09:14:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-18 15:31:26 +01:00
										 |  |  | 	// when 08 is processed ancestors contain 07 (quick block) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	for _, ancestor := range w.chain.GetBlocksFromHash(parent.Hash(), 7) { | 
					
						
							| 
									
										
										
										
											2015-05-13 20:46:23 -04:00
										 |  |  | 		for _, uncle := range ancestor.Uncles() { | 
					
						
							| 
									
										
										
										
											2018-08-06 17:55:44 +08:00
										 |  |  | 			env.family.Add(uncle.Hash()) | 
					
						
							| 
									
										
										
										
											2015-05-13 20:46:23 -04:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-08-06 17:55:44 +08:00
										 |  |  | 		env.family.Add(ancestor.Hash()) | 
					
						
							|  |  |  | 		env.ancestors.Add(ancestor.Hash()) | 
					
						
							| 
									
										
										
										
											2015-03-23 12:12:49 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-06 19:40:34 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-11 01:28:15 +02:00
										 |  |  | 	// Keep track of transactions which return errors so they can be removed | 
					
						
							| 
									
										
										
										
											2018-08-06 17:55:44 +08:00
										 |  |  | 	env.tcount = 0 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	w.current = env | 
					
						
							| 
									
										
										
										
											2015-10-06 16:35:55 +02:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2015-04-07 12:32:55 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | // commitUncle adds the given block to uncle block set, returns error if failed to add. | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | func (w *worker) commitUncle(env *environment, uncle *types.Header) error { | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	hash := uncle.Hash() | 
					
						
							|  |  |  | 	if env.uncles.Contains(hash) { | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 		return errors.New("uncle not unique") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if env.header.ParentHash == uncle.ParentHash { | 
					
						
							|  |  |  | 		return errors.New("uncle is sibling") | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if !env.ancestors.Contains(uncle.ParentHash) { | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 		return errors.New("uncle's parent unknown") | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if env.family.Contains(hash) { | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 		return errors.New("uncle already included") | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	env.uncles.Add(uncle.Hash()) | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // updateSnapshot updates pending snapshot block and state. | 
					
						
							|  |  |  | // Note this function assumes the current variable is thread safe. | 
					
						
							|  |  |  | func (w *worker) updateSnapshot() { | 
					
						
							|  |  |  | 	w.snapshotMu.Lock() | 
					
						
							|  |  |  | 	defer w.snapshotMu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var uncles []*types.Header | 
					
						
							|  |  |  | 	w.current.uncles.Each(func(item interface{}) bool { | 
					
						
							|  |  |  | 		hash, ok := item.(common.Hash) | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							|  |  |  | 			return false | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		uncle, exist := w.possibleUncles[hash] | 
					
						
							|  |  |  | 		if !exist { | 
					
						
							|  |  |  | 			return false | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		uncles = append(uncles, uncle.Header()) | 
					
						
							| 
									
										
										
										
											2018-08-21 22:33:04 +08:00
										 |  |  | 		return false | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	w.snapshotBlock = types.NewBlock( | 
					
						
							|  |  |  | 		w.current.header, | 
					
						
							|  |  |  | 		w.current.txs, | 
					
						
							|  |  |  | 		uncles, | 
					
						
							|  |  |  | 		w.current.receipts, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	w.snapshotState = w.current.state.Copy() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) { | 
					
						
							|  |  |  | 	snap := w.current.state.Snapshot() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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{}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		w.current.state.RevertToSnapshot(snap) | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	w.current.txs = append(w.current.txs, tx) | 
					
						
							|  |  |  | 	w.current.receipts = append(w.current.receipts, receipt) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return receipt.Logs, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coinbase common.Address, interrupt *int32) bool { | 
					
						
							|  |  |  | 	// Short circuit if current is nil | 
					
						
							|  |  |  | 	if w.current == nil { | 
					
						
							|  |  |  | 		return true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if w.current.gasPool == nil { | 
					
						
							|  |  |  | 		w.current.gasPool = new(core.GasPool).AddGas(w.current.header.GasLimit) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var coalescedLogs []*types.Log | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		// In the following three cases, we will interrupt the execution of the transaction. | 
					
						
							|  |  |  | 		// (1) new head block event arrival, the interrupt signal is 1 | 
					
						
							|  |  |  | 		// (2) worker start or restart, the interrupt signal is 1 | 
					
						
							|  |  |  | 		// (3) worker recreate the mining block with any newly arrived transactions, the interrupt signal is 2. | 
					
						
							|  |  |  | 		// For the first two cases, the semi-finished work will be discarded. | 
					
						
							|  |  |  | 		// For the third case, the semi-finished work will be submitted to the consensus engine. | 
					
						
							|  |  |  | 		if interrupt != nil && atomic.LoadInt32(interrupt) != commitInterruptNone { | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 			// Notify resubmit loop to increase resubmitting interval due to too frequent commits. | 
					
						
							|  |  |  | 			if atomic.LoadInt32(interrupt) == commitInterruptResubmit { | 
					
						
							|  |  |  | 				ratio := float64(w.current.header.GasLimit-w.current.gasPool.Gas()) / float64(w.current.header.GasLimit) | 
					
						
							|  |  |  | 				if ratio < 0.1 { | 
					
						
							|  |  |  | 					ratio = 0.1 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				w.resubmitAdjustCh <- &intervalAdjust{ | 
					
						
							|  |  |  | 					ratio: ratio, | 
					
						
							|  |  |  | 					inc:   true, | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 			return atomic.LoadInt32(interrupt) == commitInterruptNewHead | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// If we don't have enough gas for any further transactions then we're done | 
					
						
							|  |  |  | 		if w.current.gasPool.Gas() < params.TxGas { | 
					
						
							|  |  |  | 			log.Trace("Not enough gas for further transactions", "have", w.current.gasPool, "want", params.TxGas) | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Retrieve the next transaction and abort if all done | 
					
						
							|  |  |  | 		tx := txs.Peek() | 
					
						
							|  |  |  | 		if tx == nil { | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Error may be ignored here. The error has already been checked | 
					
						
							|  |  |  | 		// during transaction acceptance is the transaction pool. | 
					
						
							|  |  |  | 		// | 
					
						
							|  |  |  | 		// We use the eip155 signer regardless of the current hf. | 
					
						
							|  |  |  | 		from, _ := types.Sender(w.current.signer, tx) | 
					
						
							|  |  |  | 		// Check whether the tx is replay protected. If we're not in the EIP155 hf | 
					
						
							|  |  |  | 		// phase, start ignoring the sender until we do. | 
					
						
							|  |  |  | 		if tx.Protected() && !w.config.IsEIP155(w.current.header.Number) { | 
					
						
							|  |  |  | 			log.Trace("Ignoring reply protected transaction", "hash", tx.Hash(), "eip155", w.config.EIP155Block) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			txs.Pop() | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Start executing the transaction | 
					
						
							|  |  |  | 		w.current.state.Prepare(tx.Hash(), common.Hash{}, w.current.tcount) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		logs, err := w.commitTransaction(tx, coinbase) | 
					
						
							|  |  |  | 		switch err { | 
					
						
							|  |  |  | 		case core.ErrGasLimitReached: | 
					
						
							|  |  |  | 			// Pop the current out-of-gas transaction without shifting in the next from the account | 
					
						
							|  |  |  | 			log.Trace("Gas limit exceeded for current block", "sender", from) | 
					
						
							|  |  |  | 			txs.Pop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case core.ErrNonceTooLow: | 
					
						
							|  |  |  | 			// New head notification data race between the transaction pool and miner, shift | 
					
						
							|  |  |  | 			log.Trace("Skipping transaction with low nonce", "sender", from, "nonce", tx.Nonce()) | 
					
						
							|  |  |  | 			txs.Shift() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case core.ErrNonceTooHigh: | 
					
						
							|  |  |  | 			// Reorg notification data race between the transaction pool and miner, skip account = | 
					
						
							|  |  |  | 			log.Trace("Skipping account with hight nonce", "sender", from, "nonce", tx.Nonce()) | 
					
						
							|  |  |  | 			txs.Pop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case nil: | 
					
						
							|  |  |  | 			// Everything ok, collect the logs and shift in the next transaction from the same account | 
					
						
							|  |  |  | 			coalescedLogs = append(coalescedLogs, logs...) | 
					
						
							|  |  |  | 			w.current.tcount++ | 
					
						
							|  |  |  | 			txs.Shift() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			// Strange error, discard the transaction and get the next in line (note, the | 
					
						
							|  |  |  | 			// nonce-too-high clause will prevent us from executing in vain). | 
					
						
							|  |  |  | 			log.Debug("Transaction failed, account skipped", "hash", tx.Hash(), "err", err) | 
					
						
							|  |  |  | 			txs.Shift() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if !w.isRunning() && len(coalescedLogs) > 0 { | 
					
						
							|  |  |  | 		// We don't push the pendingLogsEvent while we are mining. The reason is that | 
					
						
							|  |  |  | 		// when we are mining, the worker will regenerate a mining block every 3 seconds. | 
					
						
							|  |  |  | 		// In order to avoid pushing the repeated pendingLog, we disable the pending log pushing. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// make a copy, the state caches the logs and these logs get "upgraded" from pending to mined | 
					
						
							|  |  |  | 		// logs by filling in the block hash when the block was mined by the local miner. This can | 
					
						
							|  |  |  | 		// cause a race condition if a log was "upgraded" before the PendingLogsEvent is processed. | 
					
						
							|  |  |  | 		cpy := make([]*types.Log, len(coalescedLogs)) | 
					
						
							|  |  |  | 		for i, l := range coalescedLogs { | 
					
						
							|  |  |  | 			cpy[i] = new(types.Log) | 
					
						
							|  |  |  | 			*cpy[i] = *l | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		go w.mux.Post(core.PendingLogsEvent{Logs: cpy}) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-22 03:56:54 +08:00
										 |  |  | 	// Notify resubmit loop to decrease resubmitting interval if current interval is larger | 
					
						
							|  |  |  | 	// than the user-specified one. | 
					
						
							|  |  |  | 	if interrupt != nil { | 
					
						
							|  |  |  | 		w.resubmitAdjustCh <- &intervalAdjust{inc: false} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 	return false | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | // commitNewWork generates several new sealing tasks based on the parent block. | 
					
						
							| 
									
										
										
										
											2018-08-29 22:31:59 +08:00
										 |  |  | func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) { | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	w.mu.RLock() | 
					
						
							|  |  |  | 	defer w.mu.RUnlock() | 
					
						
							| 
									
										
										
										
											2015-04-07 12:32:55 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-15 11:33:08 +02:00
										 |  |  | 	tstart := time.Now() | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	parent := w.chain.CurrentBlock() | 
					
						
							| 
									
										
										
										
											2016-11-28 14:59:06 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-29 22:31:59 +08:00
										 |  |  | 	if parent.Time().Cmp(new(big.Int).SetInt64(timestamp)) >= 0 { | 
					
						
							|  |  |  | 		timestamp = parent.Time().Int64() + 1 | 
					
						
							| 
									
										
										
										
											2015-06-16 12:41:50 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-06-29 18:55:49 +02:00
										 |  |  | 	// this will ensure we're not going off too far in the future | 
					
						
							| 
									
										
										
										
											2018-08-29 22:31:59 +08:00
										 |  |  | 	if now := time.Now().Unix(); timestamp > now+1 { | 
					
						
							|  |  |  | 		wait := time.Duration(timestamp-now) * time.Second | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 		log.Info("Mining too far in the future", "wait", common.PrettyDuration(wait)) | 
					
						
							| 
									
										
										
										
											2015-06-29 18:55:49 +02:00
										 |  |  | 		time.Sleep(wait) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-16 12:41:50 +02:00
										 |  |  | 	num := parent.Number() | 
					
						
							|  |  |  | 	header := &types.Header{ | 
					
						
							|  |  |  | 		ParentHash: parent.Hash(), | 
					
						
							|  |  |  | 		Number:     num.Add(num, common.Big1), | 
					
						
							| 
									
										
										
										
											2018-08-29 12:21:12 +03:00
										 |  |  | 		GasLimit:   core.CalcGasLimit(parent, w.gasFloor, w.gasCeil), | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 		Extra:      w.extra, | 
					
						
							| 
									
										
										
										
											2018-08-29 22:31:59 +08:00
										 |  |  | 		Time:       big.NewInt(timestamp), | 
					
						
							| 
									
										
										
										
											2015-06-16 12:41:50 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-03 16:33:37 +08:00
										 |  |  | 	// Only set the coinbase if our consensus engine is running (avoid spurious block rewards) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	if w.isRunning() { | 
					
						
							|  |  |  | 		if w.coinbase == (common.Address{}) { | 
					
						
							| 
									
										
										
										
											2018-08-03 16:33:37 +08:00
										 |  |  | 			log.Error("Refusing to mine without etherbase") | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 		header.Coinbase = w.coinbase | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	if err := w.engine.Prepare(w.chain, header); err != nil { | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 		log.Error("Failed to prepare header for mining", "err", err) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-08 18:48:17 +03:00
										 |  |  | 	// If we are care about TheDAO hard-fork check whether to override the extra-data or not | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	if daoBlock := w.config.DAOForkBlock; daoBlock != nil { | 
					
						
							| 
									
										
										
										
											2016-07-08 13:00:37 +03:00
										 |  |  | 		// Check whether the block is among the fork extra-override range | 
					
						
							|  |  |  | 		limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange) | 
					
						
							| 
									
										
										
										
											2016-07-14 11:22:58 +03:00
										 |  |  | 		if header.Number.Cmp(daoBlock) >= 0 && header.Number.Cmp(limit) < 0 { | 
					
						
							| 
									
										
										
										
											2016-07-08 18:48:17 +03:00
										 |  |  | 			// Depending whether we support or oppose the fork, override differently | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 			if w.config.DAOForkSupport { | 
					
						
							| 
									
										
										
										
											2016-07-08 18:48:17 +03:00
										 |  |  | 				header.Extra = common.CopyBytes(params.DAOForkBlockExtra) | 
					
						
							| 
									
										
										
										
											2017-01-06 16:44:20 +01:00
										 |  |  | 			} else if bytes.Equal(header.Extra, params.DAOForkBlockExtra) { | 
					
						
							| 
									
										
										
										
											2016-07-08 18:48:17 +03:00
										 |  |  | 				header.Extra = []byte{} // If miner opposes, don't let it use the reserved extra-data | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-07-08 13:00:37 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-10-06 16:35:55 +02:00
										 |  |  | 	// Could potentially happen if starting to mine in an odd state. | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	err := w.makeCurrent(parent, header) | 
					
						
							| 
									
										
										
										
											2015-10-06 16:35:55 +02:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 		log.Error("Failed to create mining context", "err", err) | 
					
						
							| 
									
										
										
										
											2015-10-06 16:35:55 +02:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-11 13:55:11 +03:00
										 |  |  | 	// Create the current work task and check any fork transitions needed | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	env := w.current | 
					
						
							|  |  |  | 	if w.config.DAOForkSupport && w.config.DAOForkBlock != nil && w.config.DAOForkBlock.Cmp(header.Number) == 0 { | 
					
						
							| 
									
										
										
										
											2018-08-06 17:55:44 +08:00
										 |  |  | 		misc.ApplyDAOHardFork(env.state) | 
					
						
							| 
									
										
										
										
											2016-07-11 13:55:11 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 	// Accumulate the uncles for the current block | 
					
						
							|  |  |  | 	for hash, uncle := range w.possibleUncles { | 
					
						
							|  |  |  | 		if uncle.NumberU64()+staleThreshold <= header.Number.Uint64() { | 
					
						
							|  |  |  | 			delete(w.possibleUncles, hash) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	uncles := make([]*types.Header, 0, 2) | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	for hash, uncle := range w.possibleUncles { | 
					
						
							| 
									
										
										
										
											2015-03-23 16:14:33 +01:00
										 |  |  | 		if len(uncles) == 2 { | 
					
						
							| 
									
										
										
										
											2015-03-23 12:12:49 +01:00
										 |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 		if err := w.commitUncle(env, uncle.Header()); err != nil { | 
					
						
							| 
									
										
										
										
											2018-08-28 16:48:20 +03:00
										 |  |  | 			log.Trace("Possible uncle rejected", "hash", hash, "reason", err) | 
					
						
							| 
									
										
										
										
											2015-03-23 12:12:49 +01:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2017-04-05 01:16:29 +03:00
										 |  |  | 			log.Debug("Committing new uncle to block", "hash", hash) | 
					
						
							| 
									
										
										
										
											2015-03-23 16:14:33 +01:00
										 |  |  | 			uncles = append(uncles, uncle.Header()) | 
					
						
							| 
									
										
										
										
											2015-03-23 12:12:49 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-03 16:33:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 	if !noempty { | 
					
						
							|  |  |  | 		// Create an empty block based on temporary copied state for sealing in advance without waiting block | 
					
						
							|  |  |  | 		// execution finished. | 
					
						
							|  |  |  | 		w.commit(uncles, nil, false, tstart) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-03 16:33:37 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Fill the block with all available pending transactions. | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	pending, err := w.eth.TxPool().Pending() | 
					
						
							| 
									
										
										
										
											2018-08-03 16:33:37 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		log.Error("Failed to fetch pending transactions", "err", err) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	// Short circuit if there is no available pending transactions | 
					
						
							|  |  |  | 	if len(pending) == 0 { | 
					
						
							|  |  |  | 		w.updateSnapshot() | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-21 20:30:06 +03:00
										 |  |  | 	// Split the pending transactions into locals and remotes | 
					
						
							|  |  |  | 	localTxs, remoteTxs := make(map[common.Address]types.Transactions), pending | 
					
						
							|  |  |  | 	for _, account := range w.eth.TxPool().Locals() { | 
					
						
							|  |  |  | 		if txs := remoteTxs[account]; len(txs) > 0 { | 
					
						
							|  |  |  | 			delete(remoteTxs, account) | 
					
						
							|  |  |  | 			localTxs[account] = txs | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if len(localTxs) > 0 { | 
					
						
							|  |  |  | 		txs := types.NewTransactionsByPriceAndNonce(w.current.signer, localTxs) | 
					
						
							|  |  |  | 		if w.commitTransactions(txs, w.coinbase, interrupt) { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if len(remoteTxs) > 0 { | 
					
						
							|  |  |  | 		txs := types.NewTransactionsByPriceAndNonce(w.current.signer, remoteTxs) | 
					
						
							|  |  |  | 		if w.commitTransactions(txs, w.coinbase, interrupt) { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-08-16 19:14:33 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 	w.commit(uncles, w.fullTaskHook, true, tstart) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // commit runs any post-transaction state modifications, assembles the final block | 
					
						
							|  |  |  | // and commits new work if consensus engine is running. | 
					
						
							|  |  |  | func (w *worker) commit(uncles []*types.Header, interval func(), update bool, start time.Time) error { | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	// Deep copy receipts here to avoid interaction between different tasks. | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 	receipts := make([]*types.Receipt, len(w.current.receipts)) | 
					
						
							|  |  |  | 	for i, l := range w.current.receipts { | 
					
						
							|  |  |  | 		receipts[i] = new(types.Receipt) | 
					
						
							|  |  |  | 		*receipts[i] = *l | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	s := w.current.state.Copy() | 
					
						
							|  |  |  | 	block, err := w.engine.Finalize(w.chain, w.current.header, s, w.current.txs, uncles, w.current.receipts) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2018-05-10 15:04:45 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 	if w.isRunning() { | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 		if interval != nil { | 
					
						
							|  |  |  | 			interval() | 
					
						
							| 
									
										
										
										
											2015-05-11 01:28:15 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 		select { | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 		case w.taskCh <- &task{receipts: receipts, state: s, block: block, createdAt: time.Now()}: | 
					
						
							|  |  |  | 			w.unconfirmed.Shift(block.NumberU64() - 1) | 
					
						
							| 
									
										
										
										
											2018-08-16 14:47:49 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			feesWei := new(big.Int) | 
					
						
							| 
									
										
										
										
											2018-08-17 15:47:14 +03:00
										 |  |  | 			for i, tx := range block.Transactions() { | 
					
						
							|  |  |  | 				feesWei.Add(feesWei, new(big.Int).Mul(new(big.Int).SetUint64(receipts[i].GasUsed), tx.GasPrice())) | 
					
						
							| 
									
										
										
										
											2018-08-16 14:47:49 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			feesEth := new(big.Float).Quo(new(big.Float).SetInt(feesWei), new(big.Float).SetInt(big.NewInt(params.Ether))) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-23 21:02:57 +08:00
										 |  |  | 			log.Info("Commit new mining work", "number", block.Number(), "sealhash", w.engine.SealHash(block.Header()), | 
					
						
							|  |  |  | 				"uncles", len(uncles), "txs", w.current.tcount, "gas", block.GasUsed(), "fees", feesEth, "elapsed", common.PrettyDuration(time.Since(start))) | 
					
						
							| 
									
										
										
										
											2018-08-16 14:47:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-08-14 23:34:33 +08:00
										 |  |  | 		case <-w.exitCh: | 
					
						
							|  |  |  | 			log.Info("Worker has exited") | 
					
						
							| 
									
										
										
										
											2016-11-28 14:59:06 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-02-04 05:52:59 -08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-08-15 19:09:17 +08:00
										 |  |  | 	if update { | 
					
						
							|  |  |  | 		w.updateSnapshot() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2015-02-04 05:52:59 -08:00
										 |  |  | } |