github.com/luckypickle/go-ethereum-vet@v1.14.2/miner/worker.go (about)

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