github.com/intfoundation/intchain@v0.0.0-20220727031208-4316ad31ca73/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  	"fmt"
    21  	"math/big"
    22  	"sync"
    23  	"sync/atomic"
    24  	"time"
    25  
    26  	"github.com/intfoundation/intchain/common"
    27  	"github.com/intfoundation/intchain/consensus"
    28  	tdmTypes "github.com/intfoundation/intchain/consensus/ipbft/types"
    29  	"github.com/intfoundation/intchain/core"
    30  	"github.com/intfoundation/intchain/core/state"
    31  	"github.com/intfoundation/intchain/core/types"
    32  	"github.com/intfoundation/intchain/core/vm"
    33  	"github.com/intfoundation/intchain/event"
    34  	"github.com/intfoundation/intchain/log"
    35  	"github.com/intfoundation/intchain/params"
    36  	"github.com/intfoundation/set.v0"
    37  )
    38  
    39  const (
    40  	resultQueueSize  = 10
    41  	miningLogAtDepth = 5
    42  
    43  	// txChanSize is the size of channel listening to TxPreEvent.
    44  	// The number is referenced from the size of tx pool.
    45  	txChanSize = 4096
    46  	// chainHeadChanSize is the size of channel listening to ChainHeadEvent.
    47  	chainHeadChanSize = 10
    48  	// chainSideChanSize is the size of channel listening to ChainSideEvent.
    49  	chainSideChanSize = 10
    50  )
    51  
    52  // Agent can register themself with the worker
    53  type Agent interface {
    54  	Work() chan<- *Work
    55  	SetReturnCh(chan<- *Result)
    56  	Stop()
    57  	Start()
    58  }
    59  
    60  // Work is the workers current environment and holds
    61  // all of the current state information
    62  type Work struct {
    63  	signer types.Signer
    64  
    65  	state     *state.StateDB // apply state changes here
    66  	ancestors *set.Set       // ancestor set (used for checking uncle parent validity)
    67  	family    *set.Set       // family set (used for checking uncle invalidity)
    68  	uncles    *set.Set       // uncle set
    69  	tcount    int            // tx count in cycle
    70  
    71  	Block *types.Block // the new block
    72  
    73  	header   *types.Header
    74  	txs      []*types.Transaction
    75  	receipts []*types.Receipt
    76  
    77  	ops *types.PendingOps // pending events here
    78  
    79  	createdAt time.Time
    80  	logger    log.Logger
    81  }
    82  
    83  type Result struct {
    84  	Work         *Work
    85  	Block        *types.Block
    86  	Intermediate *tdmTypes.IntermediateBlockResult
    87  }
    88  
    89  // worker is the main object which takes care of applying messages to the new state
    90  type worker struct {
    91  	config *params.ChainConfig
    92  	engine consensus.Engine
    93  	eth    Backend
    94  	chain  *core.BlockChain
    95  
    96  	gasFloor uint64
    97  	gasCeil  uint64
    98  
    99  	mu sync.Mutex
   100  
   101  	// update loop
   102  	mux          *event.TypeMux
   103  	txCh         chan core.TxPreEvent
   104  	txSub        event.Subscription
   105  	chainHeadCh  chan core.ChainHeadEvent
   106  	chainHeadSub event.Subscription
   107  	chainSideCh  chan core.ChainSideEvent
   108  	chainSideSub event.Subscription
   109  	wg           sync.WaitGroup
   110  
   111  	agents   map[Agent]struct{}
   112  	resultCh chan *Result
   113  	exitCh   chan struct{}
   114  
   115  	proc core.Validator
   116  
   117  	coinbase common.Address
   118  	extra    []byte
   119  
   120  	currentMu sync.Mutex
   121  	current   *Work
   122  
   123  	uncleMu        sync.Mutex
   124  	possibleUncles map[common.Hash]*types.Block
   125  
   126  	unconfirmed *unconfirmedBlocks // set of locally mined blocks pending canonicalness confirmations
   127  
   128  	// atomic status counters
   129  	mining int32
   130  	atWork int32
   131  
   132  	logger log.Logger
   133  	cch    core.CrossChainHelper
   134  }
   135  
   136  func newWorker(config *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux, gasFloor, gasCeil uint64, cch core.CrossChainHelper) *worker {
   137  	worker := &worker{
   138  		config:         config,
   139  		engine:         engine,
   140  		eth:            eth,
   141  		mux:            mux,
   142  		gasFloor:       gasFloor,
   143  		gasCeil:        gasCeil,
   144  		txCh:           make(chan core.TxPreEvent, txChanSize),
   145  		chainHeadCh:    make(chan core.ChainHeadEvent, chainHeadChanSize),
   146  		chainSideCh:    make(chan core.ChainSideEvent, chainSideChanSize),
   147  		resultCh:       make(chan *Result, resultQueueSize),
   148  		exitCh:         make(chan struct{}),
   149  		chain:          eth.BlockChain(),
   150  		proc:           eth.BlockChain().Validator(),
   151  		possibleUncles: make(map[common.Hash]*types.Block),
   152  		agents:         make(map[Agent]struct{}),
   153  		unconfirmed:    newUnconfirmedBlocks(eth.BlockChain(), miningLogAtDepth, config.ChainLogger),
   154  		logger:         config.ChainLogger,
   155  		cch:            cch,
   156  	}
   157  	// Subscribe TxPreEvent for tx pool
   158  	worker.txSub = eth.TxPool().SubscribeTxPreEvent(worker.txCh)
   159  	// Subscribe events for blockchain
   160  	worker.chainHeadSub = eth.BlockChain().SubscribeChainHeadEvent(worker.chainHeadCh)
   161  	worker.chainSideSub = eth.BlockChain().SubscribeChainSideEvent(worker.chainSideCh)
   162  
   163  	go worker.mainLoop()
   164  
   165  	go worker.resultLoop()
   166  	//worker.commitNewWork()
   167  
   168  	return worker
   169  }
   170  
   171  func (self *worker) setCoinbase(addr common.Address) {
   172  	self.mu.Lock()
   173  	defer self.mu.Unlock()
   174  	self.coinbase = addr
   175  }
   176  
   177  func (self *worker) setExtra(extra []byte) {
   178  	self.mu.Lock()
   179  	defer self.mu.Unlock()
   180  	self.extra = extra
   181  }
   182  
   183  func (self *worker) pending() (*types.Block, *state.StateDB) {
   184  	self.currentMu.Lock()
   185  	defer self.currentMu.Unlock()
   186  
   187  	if atomic.LoadInt32(&self.mining) == 0 {
   188  		return types.NewBlock(
   189  			self.current.header,
   190  			self.current.txs,
   191  			nil,
   192  			self.current.receipts,
   193  		), self.current.state.Copy()
   194  	}
   195  	return self.current.Block, self.current.state.Copy()
   196  }
   197  
   198  func (self *worker) pendingBlock() *types.Block {
   199  	self.currentMu.Lock()
   200  	defer self.currentMu.Unlock()
   201  
   202  	if atomic.LoadInt32(&self.mining) == 0 {
   203  		return types.NewBlock(
   204  			self.current.header,
   205  			self.current.txs,
   206  			nil,
   207  			self.current.receipts,
   208  		)
   209  	}
   210  	return self.current.Block
   211  }
   212  
   213  func (self *worker) start() {
   214  	self.mu.Lock()
   215  	defer self.mu.Unlock()
   216  
   217  	atomic.StoreInt32(&self.mining, 1)
   218  
   219  	//if istanbul, ok := self.engine.(consensus.Istanbul); ok {
   220  	//	istanbul.Start(self.chain, self.chain.CurrentBlock, self.chain.HasBadBlock)
   221  	//}
   222  
   223  	if ipbft, ok := self.engine.(consensus.IPBFT); ok {
   224  		err := ipbft.Start(self.chain, self.chain.CurrentBlock, self.chain.HasBadBlock)
   225  		if err != nil {
   226  			self.logger.Error("Starting IPBFT failed", "err", err)
   227  		}
   228  	}
   229  
   230  	// spin up agents
   231  	for agent := range self.agents {
   232  		agent.Start()
   233  	}
   234  }
   235  
   236  func (self *worker) stop() {
   237  	self.wg.Wait()
   238  
   239  	self.mu.Lock()
   240  	defer self.mu.Unlock()
   241  	if atomic.LoadInt32(&self.mining) == 1 {
   242  		for agent := range self.agents {
   243  			agent.Stop()
   244  		}
   245  	}
   246  
   247  	if stoppableEngine, ok := self.engine.(consensus.EngineStartStop); ok {
   248  		engineStopErr := stoppableEngine.Stop()
   249  		if engineStopErr != nil {
   250  			self.logger.Error("Stop Engine failed.", "err", engineStopErr)
   251  		} else {
   252  			self.logger.Info("Stop Engine Success.")
   253  		}
   254  	}
   255  
   256  	atomic.StoreInt32(&self.mining, 0)
   257  	atomic.StoreInt32(&self.atWork, 0)
   258  }
   259  
   260  // isRunning returns an indicator whether worker is running or not.
   261  func (self *worker) isRunning() bool {
   262  	return atomic.LoadInt32(&self.mining) == 1
   263  }
   264  
   265  // close terminates all background threads maintained by the worker.
   266  // Note the worker does not support being closed multiple times.
   267  func (self *worker) close() {
   268  	close(self.exitCh)
   269  }
   270  
   271  func (self *worker) register(agent Agent) {
   272  	self.mu.Lock()
   273  	defer self.mu.Unlock()
   274  	self.agents[agent] = struct{}{}
   275  	agent.SetReturnCh(self.resultCh)
   276  }
   277  
   278  func (self *worker) unregister(agent Agent) {
   279  	self.mu.Lock()
   280  	defer self.mu.Unlock()
   281  	delete(self.agents, agent)
   282  	agent.Stop()
   283  }
   284  
   285  func (self *worker) mainLoop() {
   286  	defer self.txSub.Unsubscribe()
   287  	defer self.chainHeadSub.Unsubscribe()
   288  	defer self.chainSideSub.Unsubscribe()
   289  
   290  	for {
   291  		// A real event arrived, process interesting content
   292  		select {
   293  		// Handle ChainHeadEvent
   294  		case ev := <-self.chainHeadCh:
   295  			if h, ok := self.engine.(consensus.Handler); ok {
   296  				h.NewChainHead(ev.Block)
   297  			}
   298  			self.commitNewWork()
   299  
   300  		// Handle ChainSideEvent
   301  		case ev := <-self.chainSideCh:
   302  			self.uncleMu.Lock()
   303  			self.possibleUncles[ev.Block.Hash()] = ev.Block
   304  			self.uncleMu.Unlock()
   305  
   306  		// Handle TxPreEvent
   307  		case ev := <-self.txCh:
   308  			// Apply transaction to the pending state if we're not mining
   309  			if !self.isRunning() && self.current != nil {
   310  				self.currentMu.Lock()
   311  				acc, _ := types.Sender(self.current.signer, ev.Tx)
   312  				txs := map[common.Address]types.Transactions{acc: {ev.Tx}}
   313  				txset := types.NewTransactionsByPriceAndNonce(self.current.signer, txs)
   314  
   315  				self.commitTransactionsEx(txset, self.coinbase, big.NewInt(0), self.cch)
   316  				self.currentMu.Unlock()
   317  			}
   318  
   319  		// System stopped
   320  		case <-self.exitCh:
   321  			return
   322  		case <-self.txSub.Err():
   323  			return
   324  		case <-self.chainHeadSub.Err():
   325  			return
   326  		case <-self.chainSideSub.Err():
   327  			return
   328  		}
   329  	}
   330  }
   331  
   332  func (self *worker) resultLoop() {
   333  	for {
   334  		mustCommitNewWork := true
   335  		select {
   336  		case result := <-self.resultCh:
   337  			atomic.AddInt32(&self.atWork, -1)
   338  
   339  			if result == nil {
   340  				continue
   341  			}
   342  
   343  			var block *types.Block
   344  			var receipts types.Receipts
   345  			var state *state.StateDB
   346  			var ops *types.PendingOps
   347  
   348  			if result.Work != nil {
   349  				block = result.Block
   350  				hash := block.Hash()
   351  				work := result.Work
   352  
   353  				for i, receipt := range work.receipts {
   354  					// add block location fields
   355  					receipt.BlockHash = hash
   356  					receipt.BlockNumber = block.Number()
   357  					receipt.TransactionIndex = uint(i)
   358  
   359  					// Update the block hash in all logs since it is now available and not when the
   360  					// receipt/log of individual transactions were created.
   361  					for _, l := range receipt.Logs {
   362  						l.BlockHash = hash
   363  					}
   364  				}
   365  				for _, log := range work.state.Logs() {
   366  					log.BlockHash = hash
   367  				}
   368  				receipts = work.receipts
   369  				state = work.state
   370  				ops = work.ops
   371  			} else if result.Intermediate != nil {
   372  				block = result.Intermediate.Block
   373  
   374  				for i, receipt := range result.Intermediate.Receipts {
   375  					// add block location fields
   376  					receipt.BlockHash = block.Hash()
   377  					receipt.BlockNumber = block.Number()
   378  					receipt.TransactionIndex = uint(i)
   379  				}
   380  
   381  				receipts = result.Intermediate.Receipts
   382  				state = result.Intermediate.State
   383  				ops = result.Intermediate.Ops
   384  			} else {
   385  				continue
   386  			}
   387  
   388  			self.chain.MuLock()
   389  
   390  			stat, err := self.chain.WriteBlockWithState(block, receipts, state)
   391  			if err != nil {
   392  				self.logger.Error("Failed writing block to chain", "err", err)
   393  				self.chain.MuUnLock()
   394  				continue
   395  			}
   396  			// execute the pending ops.
   397  			for _, op := range ops.Ops() {
   398  				if err := core.ApplyOp(op, self.chain, self.cch); err != nil {
   399  					log.Error("Failed executing op", op, "err", err)
   400  				}
   401  			}
   402  			// check if canon block and write transactions
   403  			if stat == core.CanonStatTy {
   404  				// implicit by posting ChainHeadEvent
   405  				mustCommitNewWork = false
   406  			}
   407  			// Broadcast the block and announce chain insertion event
   408  			self.mux.Post(core.NewMinedBlockEvent{Block: block})
   409  			var (
   410  				events []interface{}
   411  				logs   = state.Logs()
   412  			)
   413  			events = append(events, core.ChainEvent{Block: block, Hash: block.Hash(), Logs: logs})
   414  			if stat == core.CanonStatTy {
   415  				events = append(events, core.ChainHeadEvent{Block: block})
   416  			}
   417  
   418  			self.chain.MuUnLock()
   419  
   420  			self.chain.PostChainEvents(events, logs)
   421  
   422  			// Insert the block into the set of pending ones to wait for confirmations
   423  			self.unconfirmed.Insert(block.NumberU64(), block.Hash())
   424  
   425  			if mustCommitNewWork {
   426  				self.commitNewWork()
   427  			}
   428  		case <-self.exitCh:
   429  			return
   430  		}
   431  	}
   432  }
   433  
   434  // push sends a new work task to currently live miner agents.
   435  func (self *worker) push(work *Work) {
   436  	if atomic.LoadInt32(&self.mining) != 1 {
   437  		return
   438  	}
   439  	for agent := range self.agents {
   440  		atomic.AddInt32(&self.atWork, 1)
   441  		if ch := agent.Work(); ch != nil {
   442  			ch <- work
   443  		}
   444  	}
   445  }
   446  
   447  // makeCurrent creates a new environment for the current cycle.
   448  func (self *worker) makeCurrent(parent *types.Block, header *types.Header) error {
   449  	state, err := self.chain.StateAt(parent.Root())
   450  	if err != nil {
   451  		return err
   452  	}
   453  	work := &Work{
   454  		signer:    types.NewEIP155Signer(self.config.ChainId),
   455  		state:     state,
   456  		ancestors: set.New(),
   457  		family:    set.New(),
   458  		uncles:    set.New(),
   459  		header:    header,
   460  		ops:       new(types.PendingOps),
   461  		createdAt: time.Now(),
   462  		logger:    self.logger,
   463  	}
   464  
   465  	// when 08 is processed ancestors contain 07 (quick block)
   466  	for _, ancestor := range self.chain.GetBlocksFromHash(parent.Hash(), 7) {
   467  		for _, uncle := range ancestor.Uncles() {
   468  			work.family.Add(uncle.Hash())
   469  		}
   470  		work.family.Add(ancestor.Hash())
   471  		work.ancestors.Add(ancestor.Hash())
   472  	}
   473  
   474  	// Keep track of transactions which return errors so they can be removed
   475  	work.tcount = 0
   476  	self.current = work
   477  	return nil
   478  }
   479  
   480  func (self *worker) commitNewWork() {
   481  	self.mu.Lock()
   482  	defer self.mu.Unlock()
   483  	self.uncleMu.Lock()
   484  	defer self.uncleMu.Unlock()
   485  	self.currentMu.Lock()
   486  	defer self.currentMu.Unlock()
   487  
   488  	tstart := time.Now()
   489  	parent := self.chain.CurrentBlock()
   490  
   491  	tstamp := tstart.Unix()
   492  	if parent.Time() >= uint64(tstamp) {
   493  		tstamp = int64(parent.Time() + 1)
   494  	}
   495  
   496  	// this will ensure we're not going off too far in the future
   497  	if now := time.Now().Unix(); tstamp > now+1 {
   498  		wait := time.Duration(tstamp-now) * time.Second
   499  		self.logger.Info("Mining too far in the future", "suppose but not wait", common.PrettyDuration(wait))
   500  		//In intchain, there is no need to sleep to wait, commit work immediately
   501  		//time.Sleep(wait)
   502  	}
   503  
   504  	num := parent.Number()
   505  	header := &types.Header{
   506  		ParentHash: parent.Hash(),
   507  		Number:     num.Add(num, common.Big1),
   508  		GasLimit:   core.CalcGasLimit(parent, self.gasFloor, self.gasCeil),
   509  		Extra:      self.extra,
   510  		Time:       big.NewInt(tstamp),
   511  	}
   512  	// Only set the coinbase if our consensus engine is running (avoid spurious block rewards)
   513  	if self.isRunning() {
   514  		if self.coinbase == (common.Address{}) {
   515  			log.Error("Refusing to mine without coinbase")
   516  			return
   517  		}
   518  		header.Coinbase = self.coinbase
   519  	}
   520  	if err := self.engine.Prepare(self.chain, header); err != nil {
   521  		self.logger.Error("Failed to prepare header for mining", "err", err)
   522  		return
   523  	}
   524  	// Could potentially happen if starting to mine in an odd state.
   525  	err := self.makeCurrent(parent, header)
   526  	if err != nil {
   527  		self.logger.Error("Failed to create mining context", "err", err)
   528  		return
   529  	}
   530  	// Create the current work task and check any fork transitions needed
   531  	work := self.current
   532  	//if self.config.DAOForkSupport && self.config.DAOForkBlock != nil && self.config.DAOForkBlock.Cmp(header.Number) == 0 {
   533  	//	misc.ApplyDAOHardFork(work.state)
   534  	//}
   535  
   536  	// Fill the block with all available pending transactions.
   537  	pending, err := self.eth.TxPool().Pending()
   538  	if err != nil {
   539  		self.logger.Error("Failed to fetch pending transactions", "err", err)
   540  		return
   541  	}
   542  
   543  	totalUsedMoney := big.NewInt(0)
   544  	txs := types.NewTransactionsByPriceAndNonce(self.current.signer, pending)
   545  	//work.commitTransactions(self.mux, txs, self.chain, self.coinbase)
   546  	rmTxs := self.commitTransactionsEx(txs, self.coinbase, totalUsedMoney, self.cch)
   547  
   548  	// Remove the Invalid Transactions during tx execution (eg: tx4)
   549  	if len(rmTxs) > 0 {
   550  		self.eth.TxPool().RemoveTxs(rmTxs)
   551  	}
   552  
   553  	// compute uncles for the new block.
   554  	var (
   555  		uncles    []*types.Header
   556  		badUncles []common.Hash
   557  	)
   558  	for hash, uncle := range self.possibleUncles {
   559  		if len(uncles) == 2 {
   560  			break
   561  		}
   562  		if err := self.commitUncle(work, uncle.Header()); err != nil {
   563  			self.logger.Trace("Bad uncle found and will be removed", "hash", hash)
   564  			self.logger.Trace(fmt.Sprint(uncle))
   565  
   566  			badUncles = append(badUncles, hash)
   567  		} else {
   568  			self.logger.Debug("Committing new uncle to block", "hash", hash)
   569  			uncles = append(uncles, uncle.Header())
   570  		}
   571  	}
   572  	for _, hash := range badUncles {
   573  		delete(self.possibleUncles, hash)
   574  	}
   575  	// Create the new block to seal with the consensus engine
   576  	if work.Block, err = self.engine.Finalize(self.chain, header, work.state, work.txs, totalUsedMoney, uncles, work.receipts, work.ops); err != nil {
   577  		self.logger.Error("Failed to finalize block for sealing", "err", err)
   578  		return
   579  	}
   580  	// We only care about logging if we're actually mining.
   581  	if self.isRunning() {
   582  		self.logger.Info("Commit new full mining work", "number", work.Block.Number(), "txs", work.tcount, "uncles", len(uncles), "elapsed", common.PrettyDuration(time.Since(tstart)))
   583  		self.unconfirmed.Shift(work.Block.NumberU64() - 1)
   584  	}
   585  	self.push(work)
   586  }
   587  
   588  func (self *worker) commitUncle(work *Work, uncle *types.Header) error {
   589  	hash := uncle.Hash()
   590  	if work.uncles.Has(hash) {
   591  		return fmt.Errorf("uncle not unique")
   592  	}
   593  	if !work.ancestors.Has(uncle.ParentHash) {
   594  		return fmt.Errorf("uncle's parent unknown (%x)", uncle.ParentHash[0:4])
   595  	}
   596  	if work.family.Has(hash) {
   597  		return fmt.Errorf("uncle already in family (%x)", hash)
   598  	}
   599  	work.uncles.Add(uncle.Hash())
   600  	return nil
   601  }
   602  
   603  func (self *worker) commitTransactionsEx(txs *types.TransactionsByPriceAndNonce, coinbase common.Address, totalUsedMoney *big.Int, cch core.CrossChainHelper) (rmTxs types.Transactions) {
   604  
   605  	gp := new(core.GasPool).AddGas(self.current.header.GasLimit)
   606  
   607  	var coalescedLogs []*types.Log
   608  
   609  	for {
   610  		// If we don't have enough gas for any further transactions then we're done
   611  		if gp.Gas() < params.TxGas {
   612  			self.logger.Trace("Not enough gas for further transactions", "have", gp, "want", params.TxGas)
   613  			break
   614  		}
   615  		// Retrieve the next transaction and abort if all done
   616  		tx := txs.Peek()
   617  		if tx == nil {
   618  			break
   619  		}
   620  		// Error may be ignored here. The error has already been checked
   621  		// during transaction acceptance is the transaction pool.
   622  		//
   623  		// We use the eip155 signer regardless of the current hf.
   624  		from, _ := types.Sender(self.current.signer, tx)
   625  		// Check whether the tx is replay protected. If we're not in the EIP155 hf
   626  		// phase, start ignoring the sender until we do.
   627  		if tx.Protected() && !self.config.IsEIP155(self.current.header.Number) {
   628  			self.logger.Trace("Ignoring reply protected transaction", "hash", tx.Hash(), "eip155", self.config.EIP155Block)
   629  
   630  			txs.Pop()
   631  			continue
   632  		}
   633  
   634  		// Start executing the transaction
   635  		self.current.state.Prepare(tx.Hash(), common.Hash{}, self.current.tcount)
   636  
   637  		logs, err := self.commitTransactionEx(tx, coinbase, gp, totalUsedMoney, cch)
   638  		switch err {
   639  		case core.ErrGasLimitReached:
   640  			// Pop the current out-of-gas transaction without shifting in the next from the account
   641  			self.logger.Trace("Gas limit exceeded for current block", "sender", from)
   642  			txs.Pop()
   643  
   644  		case core.ErrNonceTooLow:
   645  			// New head notification data race between the transaction pool and miner, shift
   646  			self.logger.Trace("Skipping transaction with low nonce", "sender", from, "nonce", tx.Nonce())
   647  			txs.Shift()
   648  
   649  		case core.ErrNonceTooHigh:
   650  			// Reorg notification data race between the transaction pool and miner, skip account =
   651  			self.logger.Trace("Skipping account with hight nonce", "sender", from, "nonce", tx.Nonce())
   652  			txs.Pop()
   653  
   654  		case core.ErrInvalidTx4:
   655  			// Remove the tx4
   656  			rmTxs = append(rmTxs, tx)
   657  			self.logger.Trace("Invalid Tx4, this tx will be removed", "hash", tx.Hash())
   658  			txs.Shift()
   659  
   660  		case nil:
   661  			// Everything ok, collect the logs and shift in the next transaction from the same account
   662  			coalescedLogs = append(coalescedLogs, logs...)
   663  			self.current.tcount++
   664  			txs.Shift()
   665  
   666  		default:
   667  			// Strange error, discard the transaction and get the next in line (note, the
   668  			// nonce-too-high clause will prevent us from executing in vain).
   669  			self.logger.Debug("Transaction failed, account skipped", "hash", tx.Hash(), "err", err)
   670  			txs.Shift()
   671  		}
   672  	}
   673  
   674  	if len(coalescedLogs) > 0 || self.current.tcount > 0 {
   675  		// make a copy, the state caches the logs and these logs get "upgraded" from pending to mined
   676  		// logs by filling in the block hash when the block was mined by the local miner. This can
   677  		// cause a race condition if a log was "upgraded" before the PendingLogsEvent is processed.
   678  		cpy := make([]*types.Log, len(coalescedLogs))
   679  		for i, l := range coalescedLogs {
   680  			cpy[i] = new(types.Log)
   681  			*cpy[i] = *l
   682  		}
   683  		go func(logs []*types.Log, tcount int) {
   684  			if len(logs) > 0 {
   685  				self.mux.Post(core.PendingLogsEvent{Logs: logs})
   686  			}
   687  			if tcount > 0 {
   688  				self.mux.Post(core.PendingStateEvent{})
   689  			}
   690  		}(cpy, self.current.tcount)
   691  	}
   692  	return
   693  }
   694  
   695  func (self *worker) commitTransactionEx(tx *types.Transaction, coinbase common.Address, gp *core.GasPool, totalUsedMoney *big.Int, cch core.CrossChainHelper) ([]*types.Log, error) {
   696  	snap := self.current.state.Snapshot()
   697  
   698  	receipt, err := core.ApplyTransactionEx(self.config, self.chain, nil, gp, self.current.state, self.current.ops, self.current.header, tx, &self.current.header.GasUsed, totalUsedMoney, vm.Config{}, cch, true)
   699  	if err != nil {
   700  		self.current.state.RevertToSnapshot(snap)
   701  		return nil, err
   702  	}
   703  
   704  	self.current.txs = append(self.current.txs, tx)
   705  	self.current.receipts = append(self.current.receipts, receipt)
   706  
   707  	return receipt.Logs, nil
   708  }