github.com/ethereum/go-ethereum@v1.16.1/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  	"errors"
    21  	"fmt"
    22  	"math/big"
    23  	"sync/atomic"
    24  	"time"
    25  
    26  	"github.com/ethereum/go-ethereum/common"
    27  	"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
    28  	"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
    29  	"github.com/ethereum/go-ethereum/core"
    30  	"github.com/ethereum/go-ethereum/core/state"
    31  	"github.com/ethereum/go-ethereum/core/stateless"
    32  	"github.com/ethereum/go-ethereum/core/txpool"
    33  	"github.com/ethereum/go-ethereum/core/types"
    34  	"github.com/ethereum/go-ethereum/core/vm"
    35  	"github.com/ethereum/go-ethereum/crypto/kzg4844"
    36  	"github.com/ethereum/go-ethereum/log"
    37  	"github.com/ethereum/go-ethereum/params"
    38  	"github.com/holiman/uint256"
    39  )
    40  
    41  var (
    42  	errBlockInterruptedByNewHead  = errors.New("new head arrived while building block")
    43  	errBlockInterruptedByRecommit = errors.New("recommit interrupt while building block")
    44  	errBlockInterruptedByTimeout  = errors.New("timeout while building block")
    45  )
    46  
    47  // environment is the worker's current environment and holds all
    48  // information of the sealing block generation.
    49  type environment struct {
    50  	signer   types.Signer
    51  	state    *state.StateDB // apply state changes here
    52  	tcount   int            // tx count in cycle
    53  	gasPool  *core.GasPool  // available gas used to pack transactions
    54  	coinbase common.Address
    55  	evm      *vm.EVM
    56  
    57  	header   *types.Header
    58  	txs      []*types.Transaction
    59  	receipts []*types.Receipt
    60  	sidecars []*types.BlobTxSidecar
    61  	blobs    int
    62  
    63  	witness *stateless.Witness
    64  }
    65  
    66  const (
    67  	commitInterruptNone int32 = iota
    68  	commitInterruptNewHead
    69  	commitInterruptResubmit
    70  	commitInterruptTimeout
    71  )
    72  
    73  // newPayloadResult is the result of payload generation.
    74  type newPayloadResult struct {
    75  	err      error
    76  	block    *types.Block
    77  	fees     *big.Int               // total block fees
    78  	sidecars []*types.BlobTxSidecar // collected blobs of blob transactions
    79  	stateDB  *state.StateDB         // StateDB after executing the transactions
    80  	receipts []*types.Receipt       // Receipts collected during construction
    81  	requests [][]byte               // Consensus layer requests collected during block construction
    82  	witness  *stateless.Witness     // Witness is an optional stateless proof
    83  }
    84  
    85  // generateParams wraps various settings for generating sealing task.
    86  type generateParams struct {
    87  	timestamp   uint64            // The timestamp for sealing task
    88  	forceTime   bool              // Flag whether the given timestamp is immutable or not
    89  	parentHash  common.Hash       // Parent block hash, empty means the latest chain head
    90  	coinbase    common.Address    // The fee recipient address for including transaction
    91  	random      common.Hash       // The randomness generated by beacon chain, empty before the merge
    92  	withdrawals types.Withdrawals // List of withdrawals to include in block (shanghai field)
    93  	beaconRoot  *common.Hash      // The beacon root (cancun field).
    94  	noTxs       bool              // Flag whether an empty block without any transaction is expected
    95  }
    96  
    97  // generateWork generates a sealing block based on the given parameters.
    98  func (miner *Miner) generateWork(params *generateParams, witness bool) *newPayloadResult {
    99  	work, err := miner.prepareWork(params, witness)
   100  	if err != nil {
   101  		return &newPayloadResult{err: err}
   102  	}
   103  	if !params.noTxs {
   104  		interrupt := new(atomic.Int32)
   105  		timer := time.AfterFunc(miner.config.Recommit, func() {
   106  			interrupt.Store(commitInterruptTimeout)
   107  		})
   108  		defer timer.Stop()
   109  
   110  		err := miner.fillTransactions(interrupt, work)
   111  		if errors.Is(err, errBlockInterruptedByTimeout) {
   112  			log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(miner.config.Recommit))
   113  		}
   114  	}
   115  
   116  	body := types.Body{Transactions: work.txs, Withdrawals: params.withdrawals}
   117  	allLogs := make([]*types.Log, 0)
   118  	for _, r := range work.receipts {
   119  		allLogs = append(allLogs, r.Logs...)
   120  	}
   121  
   122  	// Collect consensus-layer requests if Prague is enabled.
   123  	var requests [][]byte
   124  	if miner.chainConfig.IsPrague(work.header.Number, work.header.Time) {
   125  		requests = [][]byte{}
   126  		// EIP-6110 deposits
   127  		if err := core.ParseDepositLogs(&requests, allLogs, miner.chainConfig); err != nil {
   128  			return &newPayloadResult{err: err}
   129  		}
   130  		// EIP-7002
   131  		if err := core.ProcessWithdrawalQueue(&requests, work.evm); err != nil {
   132  			return &newPayloadResult{err: err}
   133  		}
   134  		// EIP-7251 consolidations
   135  		if err := core.ProcessConsolidationQueue(&requests, work.evm); err != nil {
   136  			return &newPayloadResult{err: err}
   137  		}
   138  	}
   139  	if requests != nil {
   140  		reqHash := types.CalcRequestsHash(requests)
   141  		work.header.RequestsHash = &reqHash
   142  	}
   143  
   144  	block, err := miner.engine.FinalizeAndAssemble(miner.chain, work.header, work.state, &body, work.receipts)
   145  	if err != nil {
   146  		return &newPayloadResult{err: err}
   147  	}
   148  	return &newPayloadResult{
   149  		block:    block,
   150  		fees:     totalFees(block, work.receipts),
   151  		sidecars: work.sidecars,
   152  		stateDB:  work.state,
   153  		receipts: work.receipts,
   154  		requests: requests,
   155  		witness:  work.witness,
   156  	}
   157  }
   158  
   159  // prepareWork constructs the sealing task according to the given parameters,
   160  // either based on the last chain head or specified parent. In this function
   161  // the pending transactions are not filled yet, only the empty task returned.
   162  func (miner *Miner) prepareWork(genParams *generateParams, witness bool) (*environment, error) {
   163  	miner.confMu.RLock()
   164  	defer miner.confMu.RUnlock()
   165  
   166  	// Find the parent block for sealing task
   167  	parent := miner.chain.CurrentBlock()
   168  	if genParams.parentHash != (common.Hash{}) {
   169  		block := miner.chain.GetBlockByHash(genParams.parentHash)
   170  		if block == nil {
   171  			return nil, errors.New("missing parent")
   172  		}
   173  		parent = block.Header()
   174  	}
   175  	// Sanity check the timestamp correctness, recap the timestamp
   176  	// to parent+1 if the mutation is allowed.
   177  	timestamp := genParams.timestamp
   178  	if parent.Time >= timestamp {
   179  		if genParams.forceTime {
   180  			return nil, fmt.Errorf("invalid timestamp, parent %d given %d", parent.Time, timestamp)
   181  		}
   182  		timestamp = parent.Time + 1
   183  	}
   184  	// Construct the sealing block header.
   185  	header := &types.Header{
   186  		ParentHash: parent.Hash(),
   187  		Number:     new(big.Int).Add(parent.Number, common.Big1),
   188  		GasLimit:   core.CalcGasLimit(parent.GasLimit, miner.config.GasCeil),
   189  		Time:       timestamp,
   190  		Coinbase:   genParams.coinbase,
   191  	}
   192  	// Set the extra field.
   193  	if len(miner.config.ExtraData) != 0 {
   194  		header.Extra = miner.config.ExtraData
   195  	}
   196  	// Set the randomness field from the beacon chain if it's available.
   197  	if genParams.random != (common.Hash{}) {
   198  		header.MixDigest = genParams.random
   199  	}
   200  	// Set baseFee and GasLimit if we are on an EIP-1559 chain
   201  	if miner.chainConfig.IsLondon(header.Number) {
   202  		header.BaseFee = eip1559.CalcBaseFee(miner.chainConfig, parent)
   203  		if !miner.chainConfig.IsLondon(parent.Number) {
   204  			parentGasLimit := parent.GasLimit * miner.chainConfig.ElasticityMultiplier()
   205  			header.GasLimit = core.CalcGasLimit(parentGasLimit, miner.config.GasCeil)
   206  		}
   207  	}
   208  	// Run the consensus preparation with the default or customized consensus engine.
   209  	// Note that the `header.Time` may be changed.
   210  	if err := miner.engine.Prepare(miner.chain, header); err != nil {
   211  		log.Error("Failed to prepare header for sealing", "err", err)
   212  		return nil, err
   213  	}
   214  	// Apply EIP-4844, EIP-4788.
   215  	if miner.chainConfig.IsCancun(header.Number, header.Time) {
   216  		var excessBlobGas uint64
   217  		if miner.chainConfig.IsCancun(parent.Number, parent.Time) {
   218  			excessBlobGas = eip4844.CalcExcessBlobGas(miner.chainConfig, parent, timestamp)
   219  		}
   220  		header.BlobGasUsed = new(uint64)
   221  		header.ExcessBlobGas = &excessBlobGas
   222  		header.ParentBeaconRoot = genParams.beaconRoot
   223  	}
   224  	// Could potentially happen if starting to mine in an odd state.
   225  	// Note genParams.coinbase can be different with header.Coinbase
   226  	// since clique algorithm can modify the coinbase field in header.
   227  	env, err := miner.makeEnv(parent, header, genParams.coinbase, witness)
   228  	if err != nil {
   229  		log.Error("Failed to create sealing context", "err", err)
   230  		return nil, err
   231  	}
   232  	if header.ParentBeaconRoot != nil {
   233  		core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, env.evm)
   234  	}
   235  	if miner.chainConfig.IsPrague(header.Number, header.Time) {
   236  		core.ProcessParentBlockHash(header.ParentHash, env.evm)
   237  	}
   238  	return env, nil
   239  }
   240  
   241  // makeEnv creates a new environment for the sealing block.
   242  func (miner *Miner) makeEnv(parent *types.Header, header *types.Header, coinbase common.Address, witness bool) (*environment, error) {
   243  	// Retrieve the parent state to execute on top.
   244  	state, err := miner.chain.StateAt(parent.Root)
   245  	if err != nil {
   246  		return nil, err
   247  	}
   248  	if witness {
   249  		bundle, err := stateless.NewWitness(header, miner.chain)
   250  		if err != nil {
   251  			return nil, err
   252  		}
   253  		state.StartPrefetcher("miner", bundle)
   254  	}
   255  	// Note the passed coinbase may be different with header.Coinbase.
   256  	return &environment{
   257  		signer:   types.MakeSigner(miner.chainConfig, header.Number, header.Time),
   258  		state:    state,
   259  		coinbase: coinbase,
   260  		header:   header,
   261  		witness:  state.Witness(),
   262  		evm:      vm.NewEVM(core.NewEVMBlockContext(header, miner.chain, &coinbase), state, miner.chainConfig, vm.Config{}),
   263  	}, nil
   264  }
   265  
   266  func (miner *Miner) commitTransaction(env *environment, tx *types.Transaction) error {
   267  	if tx.Type() == types.BlobTxType {
   268  		return miner.commitBlobTransaction(env, tx)
   269  	}
   270  	receipt, err := miner.applyTransaction(env, tx)
   271  	if err != nil {
   272  		return err
   273  	}
   274  	env.txs = append(env.txs, tx)
   275  	env.receipts = append(env.receipts, receipt)
   276  	env.tcount++
   277  	return nil
   278  }
   279  
   280  func (miner *Miner) commitBlobTransaction(env *environment, tx *types.Transaction) error {
   281  	sc := tx.BlobTxSidecar()
   282  	if sc == nil {
   283  		panic("blob transaction without blobs in miner")
   284  	}
   285  	// Checking against blob gas limit: It's kind of ugly to perform this check here, but there
   286  	// isn't really a better place right now. The blob gas limit is checked at block validation time
   287  	// and not during execution. This means core.ApplyTransaction will not return an error if the
   288  	// tx has too many blobs. So we have to explicitly check it here.
   289  	maxBlobs := eip4844.MaxBlobsPerBlock(miner.chainConfig, env.header.Time)
   290  	if env.blobs+len(sc.Blobs) > maxBlobs {
   291  		return errors.New("max data blobs reached")
   292  	}
   293  	receipt, err := miner.applyTransaction(env, tx)
   294  	if err != nil {
   295  		return err
   296  	}
   297  	env.txs = append(env.txs, tx.WithoutBlobTxSidecar())
   298  	env.receipts = append(env.receipts, receipt)
   299  	env.sidecars = append(env.sidecars, sc)
   300  	env.blobs += len(sc.Blobs)
   301  	*env.header.BlobGasUsed += receipt.BlobGasUsed
   302  	env.tcount++
   303  	return nil
   304  }
   305  
   306  // applyTransaction runs the transaction. If execution fails, state and gas pool are reverted.
   307  func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (*types.Receipt, error) {
   308  	var (
   309  		snap = env.state.Snapshot()
   310  		gp   = env.gasPool.Gas()
   311  	)
   312  	receipt, err := core.ApplyTransaction(env.evm, env.gasPool, env.state, env.header, tx, &env.header.GasUsed)
   313  	if err != nil {
   314  		env.state.RevertToSnapshot(snap)
   315  		env.gasPool.SetGas(gp)
   316  	}
   317  	return receipt, err
   318  }
   319  
   320  func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *transactionsByPriceAndNonce, interrupt *atomic.Int32) error {
   321  	gasLimit := env.header.GasLimit
   322  	if env.gasPool == nil {
   323  		env.gasPool = new(core.GasPool).AddGas(gasLimit)
   324  	}
   325  	for {
   326  		// Check interruption signal and abort building if it's fired.
   327  		if interrupt != nil {
   328  			if signal := interrupt.Load(); signal != commitInterruptNone {
   329  				return signalToErr(signal)
   330  			}
   331  		}
   332  		// If we don't have enough gas for any further transactions then we're done.
   333  		if env.gasPool.Gas() < params.TxGas {
   334  			log.Trace("Not enough gas for further transactions", "have", env.gasPool, "want", params.TxGas)
   335  			break
   336  		}
   337  		// If we don't have enough blob space for any further blob transactions,
   338  		// skip that list altogether
   339  		if !blobTxs.Empty() && env.blobs >= eip4844.MaxBlobsPerBlock(miner.chainConfig, env.header.Time) {
   340  			log.Trace("Not enough blob space for further blob transactions")
   341  			blobTxs.Clear()
   342  			// Fall though to pick up any plain txs
   343  		}
   344  		// Retrieve the next transaction and abort if all done.
   345  		var (
   346  			ltx *txpool.LazyTransaction
   347  			txs *transactionsByPriceAndNonce
   348  		)
   349  		pltx, ptip := plainTxs.Peek()
   350  		bltx, btip := blobTxs.Peek()
   351  
   352  		switch {
   353  		case pltx == nil:
   354  			txs, ltx = blobTxs, bltx
   355  		case bltx == nil:
   356  			txs, ltx = plainTxs, pltx
   357  		default:
   358  			if ptip.Lt(btip) {
   359  				txs, ltx = blobTxs, bltx
   360  			} else {
   361  				txs, ltx = plainTxs, pltx
   362  			}
   363  		}
   364  		if ltx == nil {
   365  			break
   366  		}
   367  		// If we don't have enough space for the next transaction, skip the account.
   368  		if env.gasPool.Gas() < ltx.Gas {
   369  			log.Trace("Not enough gas left for transaction", "hash", ltx.Hash, "left", env.gasPool.Gas(), "needed", ltx.Gas)
   370  			txs.Pop()
   371  			continue
   372  		}
   373  
   374  		// Most of the blob gas logic here is agnostic as to if the chain supports
   375  		// blobs or not, however the max check panics when called on a chain without
   376  		// a defined schedule, so we need to verify it's safe to call.
   377  		if miner.chainConfig.IsCancun(env.header.Number, env.header.Time) {
   378  			left := eip4844.MaxBlobsPerBlock(miner.chainConfig, env.header.Time) - env.blobs
   379  			if left < int(ltx.BlobGas/params.BlobTxBlobGasPerBlob) {
   380  				log.Trace("Not enough blob space left for transaction", "hash", ltx.Hash, "left", left, "needed", ltx.BlobGas/params.BlobTxBlobGasPerBlob)
   381  				txs.Pop()
   382  				continue
   383  			}
   384  		}
   385  
   386  		// Transaction seems to fit, pull it up from the pool
   387  		tx := ltx.Resolve()
   388  		if tx == nil {
   389  			log.Trace("Ignoring evicted transaction", "hash", ltx.Hash)
   390  			txs.Pop()
   391  			continue
   392  		}
   393  
   394  		// Make sure all transactions after osaka have cell proofs
   395  		if miner.chainConfig.IsOsaka(env.header.Number, env.header.Time) {
   396  			if sidecar := tx.BlobTxSidecar(); sidecar != nil {
   397  				if sidecar.Version == 0 {
   398  					log.Info("Including blob tx with v0 sidecar, recomputing proofs", "hash", ltx.Hash)
   399  					sidecar.Proofs = make([]kzg4844.Proof, 0, len(sidecar.Blobs)*kzg4844.CellProofsPerBlob)
   400  					for _, blob := range sidecar.Blobs {
   401  						cellProofs, err := kzg4844.ComputeCellProofs(&blob)
   402  						if err != nil {
   403  							panic(err)
   404  						}
   405  						sidecar.Proofs = append(sidecar.Proofs, cellProofs...)
   406  					}
   407  				}
   408  			}
   409  		}
   410  
   411  		// Error may be ignored here. The error has already been checked
   412  		// during transaction acceptance in the transaction pool.
   413  		from, _ := types.Sender(env.signer, tx)
   414  
   415  		// Check whether the tx is replay protected. If we're not in the EIP155 hf
   416  		// phase, start ignoring the sender until we do.
   417  		if tx.Protected() && !miner.chainConfig.IsEIP155(env.header.Number) {
   418  			log.Trace("Ignoring replay protected transaction", "hash", ltx.Hash, "eip155", miner.chainConfig.EIP155Block)
   419  			txs.Pop()
   420  			continue
   421  		}
   422  		// Start executing the transaction
   423  		env.state.SetTxContext(tx.Hash(), env.tcount)
   424  
   425  		err := miner.commitTransaction(env, tx)
   426  		switch {
   427  		case errors.Is(err, core.ErrNonceTooLow):
   428  			// New head notification data race between the transaction pool and miner, shift
   429  			log.Trace("Skipping transaction with low nonce", "hash", ltx.Hash, "sender", from, "nonce", tx.Nonce())
   430  			txs.Shift()
   431  
   432  		case errors.Is(err, nil):
   433  			// Everything ok, collect the logs and shift in the next transaction from the same account
   434  			txs.Shift()
   435  
   436  		default:
   437  			// Transaction is regarded as invalid, drop all consecutive transactions from
   438  			// the same sender because of `nonce-too-high` clause.
   439  			log.Debug("Transaction failed, account skipped", "hash", ltx.Hash, "err", err)
   440  			txs.Pop()
   441  		}
   442  	}
   443  	return nil
   444  }
   445  
   446  // fillTransactions retrieves the pending transactions from the txpool and fills them
   447  // into the given sealing block. The transaction selection and ordering strategy can
   448  // be customized with the plugin in the future.
   449  func (miner *Miner) fillTransactions(interrupt *atomic.Int32, env *environment) error {
   450  	miner.confMu.RLock()
   451  	tip := miner.config.GasPrice
   452  	prio := miner.prio
   453  	miner.confMu.RUnlock()
   454  
   455  	// Retrieve the pending transactions pre-filtered by the 1559/4844 dynamic fees
   456  	filter := txpool.PendingFilter{
   457  		MinTip: uint256.MustFromBig(tip),
   458  	}
   459  	if env.header.BaseFee != nil {
   460  		filter.BaseFee = uint256.MustFromBig(env.header.BaseFee)
   461  	}
   462  	if env.header.ExcessBlobGas != nil {
   463  		filter.BlobFee = uint256.MustFromBig(eip4844.CalcBlobFee(miner.chainConfig, env.header))
   464  	}
   465  	filter.OnlyPlainTxs, filter.OnlyBlobTxs = true, false
   466  	pendingPlainTxs := miner.txpool.Pending(filter)
   467  
   468  	filter.OnlyPlainTxs, filter.OnlyBlobTxs = false, true
   469  	pendingBlobTxs := miner.txpool.Pending(filter)
   470  
   471  	// Split the pending transactions into locals and remotes.
   472  	prioPlainTxs, normalPlainTxs := make(map[common.Address][]*txpool.LazyTransaction), pendingPlainTxs
   473  	prioBlobTxs, normalBlobTxs := make(map[common.Address][]*txpool.LazyTransaction), pendingBlobTxs
   474  
   475  	for _, account := range prio {
   476  		if txs := normalPlainTxs[account]; len(txs) > 0 {
   477  			delete(normalPlainTxs, account)
   478  			prioPlainTxs[account] = txs
   479  		}
   480  		if txs := normalBlobTxs[account]; len(txs) > 0 {
   481  			delete(normalBlobTxs, account)
   482  			prioBlobTxs[account] = txs
   483  		}
   484  	}
   485  	// Fill the block with all available pending transactions.
   486  	if len(prioPlainTxs) > 0 || len(prioBlobTxs) > 0 {
   487  		plainTxs := newTransactionsByPriceAndNonce(env.signer, prioPlainTxs, env.header.BaseFee)
   488  		blobTxs := newTransactionsByPriceAndNonce(env.signer, prioBlobTxs, env.header.BaseFee)
   489  
   490  		if err := miner.commitTransactions(env, plainTxs, blobTxs, interrupt); err != nil {
   491  			return err
   492  		}
   493  	}
   494  	if len(normalPlainTxs) > 0 || len(normalBlobTxs) > 0 {
   495  		plainTxs := newTransactionsByPriceAndNonce(env.signer, normalPlainTxs, env.header.BaseFee)
   496  		blobTxs := newTransactionsByPriceAndNonce(env.signer, normalBlobTxs, env.header.BaseFee)
   497  
   498  		if err := miner.commitTransactions(env, plainTxs, blobTxs, interrupt); err != nil {
   499  			return err
   500  		}
   501  	}
   502  	return nil
   503  }
   504  
   505  // totalFees computes total consumed miner fees in Wei. Block transactions and receipts have to have the same order.
   506  func totalFees(block *types.Block, receipts []*types.Receipt) *big.Int {
   507  	feesWei := new(big.Int)
   508  	for i, tx := range block.Transactions() {
   509  		minerFee, _ := tx.EffectiveGasTip(block.BaseFee())
   510  		feesWei.Add(feesWei, new(big.Int).Mul(new(big.Int).SetUint64(receipts[i].GasUsed), minerFee))
   511  		// TODO (MariusVanDerWijden) add blob fees
   512  	}
   513  	return feesWei
   514  }
   515  
   516  // signalToErr converts the interruption signal to a concrete error type for return.
   517  // The given signal must be a valid interruption signal.
   518  func signalToErr(signal int32) error {
   519  	switch signal {
   520  	case commitInterruptNewHead:
   521  		return errBlockInterruptedByNewHead
   522  	case commitInterruptResubmit:
   523  		return errBlockInterruptedByRecommit
   524  	case commitInterruptTimeout:
   525  		return errBlockInterruptedByTimeout
   526  	default:
   527  		panic(fmt.Errorf("undefined signal %d", signal))
   528  	}
   529  }