github.com/amazechain/amc@v0.1.3/internal/miner/worker.go (about)

     1  // Copyright 2022 The AmazeChain Authors
     2  // This file is part of the AmazeChain library.
     3  //
     4  // The AmazeChain 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 AmazeChain 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 AmazeChain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package miner
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  	"github.com/amazechain/amc/core"
    24  	"github.com/amazechain/amc/internal/api"
    25  	"github.com/amazechain/amc/internal/consensus/misc"
    26  	"github.com/amazechain/amc/internal/metrics/prometheus"
    27  	"github.com/holiman/uint256"
    28  	"sort"
    29  	"sync"
    30  
    31  	"github.com/amazechain/amc/modules/rawdb"
    32  
    33  	"github.com/amazechain/amc/internal"
    34  	vm2 "github.com/amazechain/amc/internal/vm"
    35  	"github.com/amazechain/amc/modules/state"
    36  
    37  	"sync/atomic"
    38  	"time"
    39  
    40  	"github.com/amazechain/amc/common"
    41  	"github.com/amazechain/amc/common/block"
    42  	"github.com/amazechain/amc/common/transaction"
    43  	"github.com/amazechain/amc/common/types"
    44  	"github.com/amazechain/amc/conf"
    45  
    46  	"github.com/amazechain/amc/internal/consensus"
    47  	"github.com/amazechain/amc/log"
    48  	event "github.com/amazechain/amc/modules/event/v2"
    49  	"github.com/amazechain/amc/params"
    50  
    51  	mapset "github.com/deckarep/golang-set"
    52  	"golang.org/x/sync/errgroup"
    53  )
    54  
    55  var (
    56  	blockSignGauge = prometheus.GetOrCreateCounter("block_sign_counter", true)
    57  )
    58  
    59  type task struct {
    60  	receipts  []*block.Receipt
    61  	state     *state.IntraBlockState
    62  	block     block.IBlock
    63  	createdAt time.Time
    64  	nopay     map[types.Address]*uint256.Int
    65  }
    66  
    67  type newWorkReq struct {
    68  	interrupt *atomic.Int32
    69  	noempty   bool
    70  	timestamp int64
    71  }
    72  
    73  type generateParams struct {
    74  	timestamp  uint64        // The timstamp for sealing task
    75  	parentHash types.Hash    // Parent block hash, empty means the latest chain head
    76  	coinbase   types.Address // The fee recipient address for including transaction
    77  	random     types.Hash    // The randomness generated by beacon chain, empty before the merge
    78  	noTxs      bool          // Flag whether an empty block without any transaction is expected
    79  }
    80  
    81  type environment struct {
    82  	//signer types.Signer
    83  
    84  	//state     *state.IntraBlockState
    85  	ancestors mapset.Set      // ancestor set (used for checking uncle parent validity)
    86  	family    mapset.Set      // family set (used for checking uncle invalidity)
    87  	tcount    int             // tx count in cycle
    88  	gasPool   *common.GasPool // available gas used to pack transactions
    89  	coinbase  types.Address
    90  
    91  	header   *block.Header
    92  	txs      []*transaction.Transaction
    93  	receipts []*block.Receipt
    94  }
    95  
    96  func (env *environment) copy() *environment {
    97  	cpy := &environment{
    98  		ancestors: env.ancestors.Clone(),
    99  		family:    env.family.Clone(),
   100  		tcount:    env.tcount,
   101  		coinbase:  env.coinbase,
   102  		header:    block.CopyHeader(env.header),
   103  		receipts:  env.receipts,
   104  	}
   105  	if env.gasPool != nil {
   106  		gasPool := *env.gasPool
   107  		cpy.gasPool = &gasPool
   108  	}
   109  
   110  	cpy.txs = make([]*transaction.Transaction, len(env.txs))
   111  	copy(cpy.txs, env.txs)
   112  	return cpy
   113  }
   114  
   115  const (
   116  	commitInterruptNone int32 = iota
   117  	commitInterruptNewHead
   118  	commitInterruptResubmit
   119  	commitInterruptTimeout
   120  )
   121  
   122  const (
   123  	minPeriodInterval      = 1 * time.Second // 1s
   124  	staleThreshold         = 7
   125  	resubmitAdjustChanSize = 10
   126  
   127  	// maxRecommitInterval is the maximum time interval to recreate the sealing block with
   128  	// any newly arrived transactions.
   129  	maxRecommitInterval = 12 * time.Second
   130  
   131  	intervalAdjustRatio = 0.1
   132  
   133  	intervalAdjustBias = 200 * 1000.0 * 1000.0
   134  )
   135  
   136  var (
   137  	errBlockInterruptedByNewHead  = errors.New("new head arrived while building block")
   138  	errBlockInterruptedByRecommit = errors.New("recommit interrupt while building block")
   139  	errBlockInterruptedByTimeout  = errors.New("timeout while building block")
   140  )
   141  
   142  // intervalAdjust represents a resubmitting interval adjustment.
   143  type intervalAdjust struct {
   144  	ratio float64
   145  	inc   bool
   146  }
   147  
   148  type worker struct {
   149  	minerConf conf.MinerConfig
   150  	engine    consensus.Engine
   151  	chain     common.IBlockChain
   152  	txsPool   common.ITxsPool
   153  
   154  	coinbase    types.Address
   155  	chainConfig *params.ChainConfig
   156  
   157  	isLocalBlock func(header *block.Header) bool
   158  	pendingTasks map[types.Hash]*task
   159  
   160  	wg sync.WaitGroup
   161  	mu sync.RWMutex
   162  
   163  	startCh   chan struct{}
   164  	newWorkCh chan *newWorkReq
   165  	resultCh  chan block.IBlock
   166  	taskCh    chan *task
   167  
   168  	resubmitAdjustCh chan *intervalAdjust
   169  
   170  	running int32
   171  	newTxs  int32
   172  
   173  	group  *errgroup.Group
   174  	ctx    context.Context
   175  	cancel context.CancelFunc
   176  	//current     *environment
   177  	newTaskHook func(*task)
   178  
   179  	snapshotMu       sync.RWMutex // The lock used to protect the snapshots below
   180  	snapshotBlock    block.IBlock
   181  	snapshotReceipts block.Receipts
   182  }
   183  
   184  func newWorker(ctx context.Context, group *errgroup.Group, chainConfig *params.ChainConfig, engine consensus.Engine, bc common.IBlockChain, txsPool common.ITxsPool, isLocalBlock func(header *block.Header) bool, init bool, minerConf conf.MinerConfig) *worker {
   185  	c, cancel := context.WithCancel(ctx)
   186  	worker := &worker{
   187  		engine:           engine,
   188  		chain:            bc,
   189  		txsPool:          txsPool,
   190  		chainConfig:      chainConfig,
   191  		mu:               sync.RWMutex{},
   192  		startCh:          make(chan struct{}, 1),
   193  		group:            group,
   194  		isLocalBlock:     isLocalBlock,
   195  		ctx:              c,
   196  		cancel:           cancel,
   197  		taskCh:           make(chan *task),
   198  		newWorkCh:        make(chan *newWorkReq),
   199  		resultCh:         make(chan block.IBlock),
   200  		pendingTasks:     make(map[types.Hash]*task),
   201  		minerConf:        minerConf,
   202  		resubmitAdjustCh: make(chan *intervalAdjust, resubmitAdjustChanSize),
   203  	}
   204  	recommit := worker.minerConf.Recommit
   205  	if recommit < minPeriodInterval {
   206  		recommit = minPeriodInterval
   207  	}
   208  
   209  	// machine verify
   210  	group.Go(func() error {
   211  		return api.MachineVerify(ctx)
   212  	})
   213  
   214  	group.Go(func() error {
   215  		return worker.workLoop(recommit)
   216  	})
   217  
   218  	group.Go(func() error {
   219  		return worker.runLoop()
   220  	})
   221  
   222  	group.Go(func() error {
   223  		return worker.taskLoop()
   224  	})
   225  
   226  	group.Go(func() error {
   227  		return worker.resultLoop()
   228  	})
   229  
   230  	if init {
   231  		worker.startCh <- struct{}{}
   232  	}
   233  
   234  	return worker
   235  }
   236  
   237  func (w *worker) start() {
   238  	atomic.StoreInt32(&w.running, 1)
   239  	w.startCh <- struct{}{}
   240  }
   241  
   242  func (w *worker) stop() {
   243  	atomic.StoreInt32(&w.running, 0)
   244  }
   245  
   246  func (w *worker) close() {
   247  
   248  }
   249  
   250  func (w *worker) isRunning() bool {
   251  	return atomic.LoadInt32(&w.running) == 1
   252  }
   253  func (w *worker) setCoinbase(addr types.Address) {
   254  	w.mu.Lock()
   255  	defer w.mu.Unlock()
   256  	w.coinbase = addr
   257  }
   258  
   259  func (w *worker) runLoop() error {
   260  	defer w.cancel()
   261  	defer w.stop()
   262  	for {
   263  		select {
   264  		case <-w.ctx.Done():
   265  			return w.ctx.Err()
   266  		case req := <-w.newWorkCh:
   267  			err := w.commitWork(req.interrupt, req.noempty, req.timestamp)
   268  			if err != nil {
   269  				log.Error("runLoop err:", err.Error())
   270  				//w.startCh <- struct{}{}
   271  			}
   272  		}
   273  	}
   274  }
   275  
   276  func (w *worker) resultLoop() error {
   277  	defer w.cancel()
   278  	defer w.stop()
   279  
   280  	for {
   281  		select {
   282  		case <-w.ctx.Done():
   283  			return w.ctx.Err()
   284  		case blk := <-w.resultCh:
   285  			if blk == nil {
   286  				continue
   287  			}
   288  
   289  			// Short circuit when receiving duplicate result caused by resubmitting.
   290  			if w.chain.HasBlock(blk.Hash(), blk.Number64().Uint64()) {
   291  				continue
   292  			}
   293  
   294  			var (
   295  				sealhash = w.engine.SealHash(blk.Header())
   296  				hash     = blk.Hash()
   297  			)
   298  			w.mu.RLock()
   299  			task, exist := w.pendingTasks[sealhash]
   300  			w.mu.RUnlock()
   301  			if !exist {
   302  				log.Error("Block found but no relative pending task", "number", blk.Number64().Uint64(), "sealhash", sealhash, "hash", hash)
   303  				//w.startCh <- struct{}{}
   304  				continue
   305  			}
   306  
   307  			// Different block could share same sealhash, deep copy here to prevent write-write conflict.
   308  			var (
   309  				receipts = make([]*block.Receipt, len(task.receipts))
   310  				logs     []*block.Log
   311  			)
   312  			for i, taskReceipt := range task.receipts {
   313  				receipt := new(block.Receipt)
   314  				receipts[i] = receipt
   315  				*receipt = *taskReceipt
   316  
   317  				// add block location fields
   318  				receipt.BlockHash = hash
   319  				receipt.BlockNumber = blk.Number64()
   320  				receipt.TransactionIndex = uint(i)
   321  
   322  				// Update the block hash in all logs since it is now available and not when the
   323  				// receipt/log of individual transactions were created.
   324  				receipt.Logs = make([]*block.Log, len(taskReceipt.Logs))
   325  				for i, taskLog := range taskReceipt.Logs {
   326  					log := new(block.Log)
   327  					receipt.Logs[i] = log
   328  					*log = *taskLog
   329  					log.BlockHash = hash
   330  				}
   331  				logs = append(logs, receipt.Logs...)
   332  			}
   333  
   334  			// Commit block and state to database.
   335  			err := w.chain.WriteBlockWithState(blk, receipts, task.state, task.nopay)
   336  			if err != nil {
   337  				log.Error("Failed writing block to chain", "err", err)
   338  				continue
   339  			}
   340  			blockSignGauge.Set(uint64(len(blk.Body().Verifier())))
   341  
   342  			if len(logs) > 0 {
   343  				event.GlobalEvent.Send(common.NewLogsEvent{Logs: logs})
   344  			}
   345  
   346  			log.Info("🔨 Successfully sealed new block",
   347  				"sealhash", sealhash,
   348  				"hash", hash,
   349  				"number", blk.Number64().Uint64(),
   350  				"used gas", blk.GasUsed(),
   351  				"diff", blk.Difficulty().Uint64(),
   352  				"headerTime", time.Unix(int64(blk.Time()), 0).Format(time.RFC3339),
   353  				"verifierCount", len(blk.Body().Verifier()),
   354  				"rewardCount", len(blk.Body().Reward()),
   355  				"elapsed", common.PrettyDuration(time.Since(task.createdAt)),
   356  				"txs", len(blk.Transactions()))
   357  
   358  			if err = w.chain.SealedBlock(blk); err != nil {
   359  				log.Error("Failed Broadcast block to p2p network", "err", err)
   360  				continue
   361  			}
   362  			event.GlobalEvent.Send(common.ChainHighestBlock{Block: *blk.(*block.Block), Inserted: true})
   363  		}
   364  	}
   365  }
   366  
   367  func (w *worker) taskLoop() error {
   368  	defer w.cancel()
   369  	defer w.stop()
   370  
   371  	var (
   372  		stopCh chan struct{}
   373  		prev   types.Hash
   374  	)
   375  
   376  	interrupt := func() {
   377  		if stopCh != nil {
   378  			close(stopCh)
   379  			stopCh = nil
   380  		}
   381  	}
   382  
   383  	for {
   384  		select {
   385  		case <-w.ctx.Done():
   386  			return w.ctx.Err()
   387  		case task := <-w.taskCh:
   388  
   389  			if w.newTaskHook != nil {
   390  				w.newTaskHook(task)
   391  			}
   392  
   393  			sealHash := w.engine.SealHash(task.block.Header())
   394  			hash := task.block.Hash()
   395  			stateRoot := task.block.StateRoot()
   396  			if sealHash == prev {
   397  				continue
   398  			}
   399  			interrupt()
   400  			stopCh, prev = make(chan struct{}), sealHash
   401  			w.mu.Lock()
   402  			w.pendingTasks[sealHash] = task
   403  			w.mu.Unlock()
   404  
   405  			if err := w.engine.Seal(w.chain, task.block, w.resultCh, stopCh); err != nil {
   406  				w.mu.Lock()
   407  				delete(w.pendingTasks, sealHash)
   408  				w.mu.Unlock()
   409  				log.Warn("delete task", "sealHash", sealHash, "hash", hash, "stateRoot", stateRoot, "err", err)
   410  				if errors.Is(err, consensus.ErrNotEnoughSign) {
   411  					time.Sleep(1 * time.Second)
   412  					w.startCh <- struct{}{}
   413  				}
   414  			} else {
   415  				log.Debug("send task", "sealHash", sealHash, "hash", hash, "stateRoot", stateRoot)
   416  			}
   417  		}
   418  	}
   419  }
   420  
   421  func (w *worker) commitWork(interrupt *atomic.Int32, noempty bool, timestamp int64) error {
   422  	start := time.Now()
   423  	if w.isRunning() {
   424  		if w.coinbase == (types.Address{}) {
   425  			return fmt.Errorf("coinbase is empty")
   426  		}
   427  	}
   428  
   429  	current, err := w.prepareWork(&generateParams{timestamp: uint64(timestamp), coinbase: w.coinbase})
   430  	if err != nil {
   431  		log.Error("cannot prepare work", "err", err)
   432  		return err
   433  	}
   434  
   435  	tx, err := w.chain.DB().BeginRo(w.ctx)
   436  	if nil != err {
   437  		log.Error("work.commitWork failed", err)
   438  		return err
   439  	}
   440  	defer tx.Rollback()
   441  
   442  	stateReader := state.NewPlainStateReader(tx)
   443  	stateWriter := state.NewNoopWriter()
   444  	ibs := state.New(stateReader)
   445  	// generate state for mobile verify
   446  	ibs.BeginWriteSnapshot()
   447  	ibs.BeginWriteCodes()
   448  	headers := make([]*block.Header, 0)
   449  	getHeader := func(hash types.Hash, number uint64) *block.Header {
   450  		h := rawdb.ReadHeader(tx, hash, number)
   451  		if nil != h {
   452  			headers = append(headers, h)
   453  		}
   454  		return h
   455  	}
   456  
   457  	err = w.fillTransactions(interrupt, current, ibs, getHeader)
   458  	switch {
   459  	case err == nil:
   460  		w.resubmitAdjustCh <- &intervalAdjust{inc: false}
   461  	case errors.Is(err, errBlockInterruptedByRecommit):
   462  		gaslimit := current.header.GasLimit
   463  		ratio := float64(gaslimit-current.gasPool.Gas()) / float64(gaslimit)
   464  		if ratio < 0.1 {
   465  			ratio = 0.1
   466  		}
   467  		w.resubmitAdjustCh <- &intervalAdjust{
   468  			ratio: ratio,
   469  			inc:   true,
   470  		}
   471  	}
   472  
   473  	//var rewards []*block.Reward
   474  	//if w.chainConfig.IsBeijing(current.header.Number.Uint64()) {
   475  	//	rewards, err = w.engine.Rewards(tx, block.CopyHeader(current.header), ibs, false)
   476  	//	if err != nil {
   477  	//		return err
   478  	//	}
   479  	//}
   480  
   481  	if err = w.commit(current, stateWriter, ibs, start, headers); nil != err {
   482  		log.Errorf("w.commit failed, error %v\n", err)
   483  		return err
   484  	}
   485  
   486  	return nil
   487  }
   488  
   489  // recalcRecommit recalculates the resubmitting interval upon feedback.
   490  func recalcRecommit(minRecommit, prev time.Duration, target float64, inc bool) time.Duration {
   491  	var (
   492  		prevF = float64(prev.Nanoseconds())
   493  		next  float64
   494  	)
   495  	if inc {
   496  		next = prevF*(1-intervalAdjustRatio) + intervalAdjustRatio*(target+intervalAdjustBias)
   497  		max := float64(maxRecommitInterval.Nanoseconds())
   498  		if next > max {
   499  			next = max
   500  		}
   501  	} else {
   502  		next = prevF*(1-intervalAdjustRatio) + intervalAdjustRatio*(target-intervalAdjustBias)
   503  		min := float64(minRecommit.Nanoseconds())
   504  		if next < min {
   505  			next = min
   506  		}
   507  	}
   508  	return time.Duration(int64(next))
   509  }
   510  
   511  func (w *worker) workLoop(recommit time.Duration) error {
   512  	defer w.cancel()
   513  	defer w.stop()
   514  	var (
   515  		interrupt   *atomic.Int32
   516  		minRecommit = recommit // minimal resubmit interval specified by user.
   517  		timestamp   int64      // timestamp for each round of sealing.
   518  	)
   519  
   520  	newBlockCh := make(chan common.ChainHighestBlock)
   521  	defer close(newBlockCh)
   522  
   523  	newBlockSub := event.GlobalEvent.Subscribe(newBlockCh)
   524  	defer newBlockSub.Unsubscribe()
   525  
   526  	timer := time.NewTimer(0)
   527  	defer timer.Stop()
   528  	<-timer.C // discard the initial tick
   529  
   530  	commit := func(noempty bool, s int32) {
   531  		if interrupt != nil {
   532  			interrupt.Store(s)
   533  		}
   534  		interrupt = new(atomic.Int32)
   535  		select {
   536  		case w.newWorkCh <- &newWorkReq{interrupt: interrupt, noempty: noempty, timestamp: timestamp}:
   537  		case <-w.ctx.Done():
   538  			return
   539  		}
   540  		timer.Reset(recommit)
   541  		//atomic.StoreInt32(&w.newTxs, 0)
   542  	}
   543  
   544  	clearPending := func(number *uint256.Int) {
   545  		w.mu.Lock()
   546  		for h, t := range w.pendingTasks {
   547  			if number.Cmp(uint256.NewInt(0).Add(t.block.Number64(), uint256.NewInt(staleThreshold))) < 1 {
   548  				delete(w.pendingTasks, h)
   549  			}
   550  		}
   551  		w.mu.Unlock()
   552  	}
   553  
   554  	for {
   555  		select {
   556  		case <-w.ctx.Done():
   557  			return w.ctx.Err()
   558  		case <-w.startCh:
   559  			clearPending(w.chain.CurrentBlock().Number64())
   560  			timestamp = time.Now().Unix()
   561  			commit(false, commitInterruptNewHead)
   562  
   563  		case blockEvent := <-newBlockCh:
   564  			clearPending(blockEvent.Block.Number64())
   565  			timestamp = time.Now().Unix()
   566  			commit(false, commitInterruptNewHead)
   567  		case err := <-newBlockSub.Err():
   568  			return err
   569  
   570  		case <-timer.C:
   571  			// If sealing is running resubmit a new work cycle periodically to pull in
   572  			// higher priced transactions. Disable this overhead for pending blocks.
   573  			//if w.isRunning() && (w.chainConfig.Apos == nil && w.chainConfig.Clique == nil) {
   574  			//	continue
   575  			//	commit(false, commitInterruptResubmit)
   576  			//}
   577  		case adjust := <-w.resubmitAdjustCh:
   578  			// Adjust resubmit interval by feedback.
   579  			if adjust.inc {
   580  				before := recommit
   581  				target := float64(recommit.Nanoseconds()) / adjust.ratio
   582  				recommit = recalcRecommit(minRecommit, recommit, target, true)
   583  				log.Trace("Increase miner recommit interval", "from", before, "to", recommit)
   584  			} else {
   585  				before := recommit
   586  				recommit = recalcRecommit(minRecommit, recommit, float64(minRecommit.Nanoseconds()), false)
   587  				log.Trace("Decrease miner recommit interval", "from", before, "to", recommit)
   588  			}
   589  		}
   590  	}
   591  }
   592  
   593  func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment, ibs *state.IntraBlockState, getHeader func(hash types.Hash, number uint64) *block.Header) error {
   594  	// todo fillTx
   595  	env.txs = []*transaction.Transaction{}
   596  	txs, err := w.txsPool.GetTransaction()
   597  	if err != nil {
   598  		log.Warn("get transaction error", "err", err)
   599  		return err
   600  	}
   601  
   602  	header := env.header
   603  	noop := state.NewNoopWriter()
   604  	var miningCommitTx = func(txn *transaction.Transaction, coinbase types.Address, vmConfig *vm2.Config, chainConfig *params.ChainConfig, ibs *state.IntraBlockState, current *environment) ([]*block.Log, error) {
   605  		ibs.Prepare(txn.Hash(), types.Hash{}, env.tcount)
   606  		gasSnap := current.gasPool.Gas()
   607  		snap := ibs.Snapshot()
   608  		log.Debug("addTransactionsToMiningBlock", "txn hash", txn.Hash())
   609  		receipt, _, err := internal.ApplyTransaction(chainConfig, internal.GetHashFn(header, getHeader), w.engine, &coinbase, env.gasPool, ibs, noop, current.header, txn, &header.GasUsed, *vmConfig)
   610  		if err != nil {
   611  			ibs.RevertToSnapshot(snap)
   612  			env.gasPool = new(common.GasPool).AddGas(gasSnap) // restore gasPool as well as ibs
   613  			return nil, err
   614  		}
   615  
   616  		current.txs = append(current.txs, txn)
   617  		current.receipts = append(current.receipts, receipt)
   618  		return receipt.Logs, nil
   619  	}
   620  
   621  	log.Tracef("fillTransactions txs len:%d", len(txs))
   622  	for _, tx := range txs {
   623  		// Check interruption signal and abort building if it's fired.
   624  		if interrupt != nil {
   625  			if signal := interrupt.Load(); signal != commitInterruptNone {
   626  				return signalToErr(signal)
   627  			}
   628  		}
   629  		if env.gasPool.Gas() < params.TxGas {
   630  			log.Trace("Not enough gas for further transactions", "have", env.gasPool, "want", params.TxGas)
   631  			break
   632  		}
   633  		// Start executing the transaction
   634  		_, err := miningCommitTx(tx, env.coinbase, &vm2.Config{}, w.chainConfig, ibs, env)
   635  
   636  		switch {
   637  		case errors.Is(err, core.ErrGasLimitReached):
   638  			continue
   639  		case errors.Is(err, core.ErrNonceTooHigh):
   640  			continue
   641  		case errors.Is(err, core.ErrNonceTooLow):
   642  			continue
   643  		case errors.Is(err, nil):
   644  			env.tcount++
   645  			continue
   646  		default:
   647  			log.Error("miningCommitTx failed ", "error", err)
   648  		}
   649  	}
   650  
   651  	return nil
   652  }
   653  
   654  func (w *worker) prepareWork(param *generateParams) (*environment, error) {
   655  	w.mu.RLock()
   656  	defer w.mu.RUnlock()
   657  
   658  	timestamp := param.timestamp
   659  
   660  	parent := w.chain.CurrentBlock().Header().(*block.Header)
   661  	if param.parentHash != (types.Hash{}) {
   662  		b, _ := w.chain.GetBlockByHash(param.parentHash)
   663  		if b == nil {
   664  			return nil, fmt.Errorf("missing parent")
   665  		}
   666  		parent = b.Header().(*block.Header)
   667  	}
   668  
   669  	if parent.Time >= param.timestamp {
   670  		timestamp = parent.Time + 1
   671  	}
   672  
   673  	header := &block.Header{
   674  		//Root:       parent.StateRoot(),
   675  		ParentHash: parent.Hash(),
   676  		Coinbase:   param.coinbase,
   677  		Number:     uint256.NewInt(0).Add(parent.Number64(), uint256.NewInt(1)),
   678  		GasLimit:   CalcGasLimit(parent.GasLimit, w.minerConf.GasCeil),
   679  		Time:       uint64(timestamp),
   680  		Difficulty: uint256.NewInt(0),
   681  		// just for now
   682  		BaseFee: uint256.NewInt(0),
   683  	}
   684  
   685  	// Set baseFee and GasLimit if we are on an EIP-1559 chain
   686  	if w.chainConfig.IsLondon(header.Number.Uint64()) {
   687  		header.BaseFee, _ = uint256.FromBig(misc.CalcBaseFee(w.chainConfig, parent))
   688  		if !w.chainConfig.IsLondon(parent.Number64().Uint64()) {
   689  			parentGasLimit := parent.GasLimit * params.ElasticityMultiplier
   690  			header.GasLimit = CalcGasLimit(parentGasLimit, w.minerConf.GasCeil)
   691  		}
   692  	}
   693  
   694  	if err := w.engine.Prepare(w.chain, header); err != nil {
   695  		return nil, err
   696  	}
   697  
   698  	return w.makeEnv(parent, header, param.coinbase), nil
   699  }
   700  
   701  func (w *worker) makeEnv(parent *block.Header, header *block.Header, coinbase types.Address) *environment {
   702  	//rtx, err := w.chain.DB().BeginRo(context.Background())
   703  	//if nil != err {
   704  	//	return nil
   705  	//}
   706  	//defer rtx.Rollback()
   707  	env := &environment{
   708  		ancestors: mapset.NewSet(),
   709  		family:    mapset.NewSet(),
   710  		coinbase:  coinbase,
   711  		header:    header,
   712  		//state:     ibs,
   713  		gasPool: new(common.GasPool),
   714  		tcount:  0,
   715  	}
   716  
   717  	env.gasPool = new(common.GasPool).AddGas(header.GasLimit)
   718  	//}
   719  
   720  	for _, ancestor := range w.chain.GetBlocksFromHash(parent.ParentHash, 3) {
   721  		env.family.Add(ancestor.(*block.Block).Hash())
   722  		env.ancestors.Add(ancestor.Hash())
   723  	}
   724  
   725  	return env
   726  }
   727  
   728  func (w *worker) commit(env *environment, writer state.WriterWithChangeSets, ibs *state.IntraBlockState, start time.Time, needHeaders []*block.Header) error {
   729  	if w.isRunning() {
   730  		env := env.copy()
   731  		iblock, rewards, unpay, err := w.engine.FinalizeAndAssemble(w.chain, env.header, ibs, env.txs, nil, env.receipts)
   732  		if nil != err {
   733  			return err
   734  		}
   735  
   736  		if w.chainConfig.IsBeijing(env.header.Number.Uint64()) {
   737  			txs := make([][]byte, len(env.txs))
   738  			for i, tx := range env.txs {
   739  				var err error
   740  
   741  				txs[i], err = tx.Marshal()
   742  				if nil != err {
   743  					panic(err)
   744  				}
   745  			}
   746  
   747  			entri := state.Entire{Header: iblock.Header().(*block.Header), Uncles: nil, Transactions: txs, Senders: nil, Snap: ibs.Snap(), Proof: types.Hash{}}
   748  			cs := ibs.CodeHashes()
   749  			hs := make(state.HashCodes, 0, len(cs))
   750  			for k, v := range cs {
   751  				hs = append(hs, &state.HashCode{Hash: k, Code: v})
   752  			}
   753  			sort.Sort(hs)
   754  
   755  			event.GlobalEvent.Send(common.MinedEntireEvent{Entire: state.EntireCode{Codes: hs, Headers: needHeaders, Entire: entri, Rewards: rewards, CoinBase: env.coinbase}})
   756  		}
   757  
   758  		//
   759  		w.updateSnapshot(env, rewards)
   760  
   761  		select {
   762  		case w.taskCh <- &task{receipts: env.receipts, block: iblock, createdAt: time.Now(), state: ibs, nopay: unpay}:
   763  			log.Debug("Commit new sealing work",
   764  				"number", iblock.Header().Number64().Uint64(),
   765  				"sealhash", w.engine.SealHash(iblock.Header()),
   766  				"txs", env.tcount,
   767  				"gas", iblock.GasUsed(),
   768  				"elapsed", common.PrettyDuration(time.Since(start)),
   769  				"headerTime", time.Unix(int64(iblock.Time()), 0).Format(time.RFC3339),
   770  				"rewardCount", len(iblock.Body().Reward()),
   771  			)
   772  		case <-w.ctx.Done():
   773  			return w.ctx.Err()
   774  		}
   775  	}
   776  	return nil
   777  }
   778  
   779  // copyReceipts makes a deep copy of the given receipts.
   780  func copyReceipts(receipts []*block.Receipt) []*block.Receipt {
   781  	result := make([]*block.Receipt, len(receipts))
   782  	for i, l := range receipts {
   783  		cpy := *l
   784  		result[i] = &cpy
   785  	}
   786  	return result
   787  }
   788  
   789  // pendingBlockAndReceipts returns pending block and corresponding receipts.
   790  func (w *worker) pendingBlockAndReceipts() (block.IBlock, block.Receipts) {
   791  	// return a snapshot to avoid contention on currentMu mutex
   792  	w.snapshotMu.RLock()
   793  	defer w.snapshotMu.RUnlock()
   794  	return w.snapshotBlock, w.snapshotReceipts
   795  }
   796  
   797  // updateSnapshot updates pending snapshot block, receipts and state.
   798  func (w *worker) updateSnapshot(env *environment, rewards []*block.Reward) {
   799  	w.snapshotMu.Lock()
   800  	defer w.snapshotMu.Unlock()
   801  
   802  	w.snapshotBlock = block.NewBlockFromReceipt(
   803  		env.header,
   804  		env.txs,
   805  		nil,
   806  		env.receipts,
   807  		rewards,
   808  	)
   809  	w.snapshotReceipts = copyReceipts(env.receipts)
   810  }
   811  
   812  func signalToErr(signal int32) error {
   813  	switch signal {
   814  	case commitInterruptNewHead:
   815  		return errBlockInterruptedByNewHead
   816  	case commitInterruptResubmit:
   817  		return errBlockInterruptedByRecommit
   818  	case commitInterruptTimeout:
   819  		return errBlockInterruptedByTimeout
   820  	default:
   821  		panic(fmt.Errorf("undefined signal %d", signal))
   822  	}
   823  }