|
|
|
@ -27,6 +27,7 @@ import ( |
|
|
|
|
"github.com/ethereum/go-ethereum/common" |
|
|
|
|
"github.com/ethereum/go-ethereum/consensus" |
|
|
|
|
"github.com/ethereum/go-ethereum/consensus/misc/eip1559" |
|
|
|
|
"github.com/ethereum/go-ethereum/consensus/misc/eip4844" |
|
|
|
|
"github.com/ethereum/go-ethereum/core" |
|
|
|
|
"github.com/ethereum/go-ethereum/core/state" |
|
|
|
|
"github.com/ethereum/go-ethereum/core/txpool" |
|
|
|
@ -89,6 +90,8 @@ type environment struct { |
|
|
|
|
header *types.Header |
|
|
|
|
txs []*types.Transaction |
|
|
|
|
receipts []*types.Receipt |
|
|
|
|
sidecars []*types.BlobTxSidecar |
|
|
|
|
blobs int |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// copy creates a deep copy of environment.
|
|
|
|
@ -107,6 +110,10 @@ func (env *environment) copy() *environment { |
|
|
|
|
} |
|
|
|
|
cpy.txs = make([]*types.Transaction, len(env.txs)) |
|
|
|
|
copy(cpy.txs, env.txs) |
|
|
|
|
|
|
|
|
|
cpy.sidecars = make([]*types.BlobTxSidecar, len(env.sidecars)) |
|
|
|
|
copy(cpy.sidecars, env.sidecars) |
|
|
|
|
|
|
|
|
|
return cpy |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -141,11 +148,12 @@ type newWorkReq struct { |
|
|
|
|
timestamp int64 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// newPayloadResult represents a result struct corresponds to payload generation.
|
|
|
|
|
// newPayloadResult is the result of payload generation.
|
|
|
|
|
type newPayloadResult struct { |
|
|
|
|
err error |
|
|
|
|
block *types.Block |
|
|
|
|
fees *big.Int |
|
|
|
|
fees *big.Int // total block fees
|
|
|
|
|
sidecars []*types.BlobTxSidecar // collected blobs of blob transactions
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// getWorkReq represents a request for getting a new sealing work with provided parameters.
|
|
|
|
@ -516,12 +524,7 @@ func (w *worker) mainLoop() { |
|
|
|
|
w.commitWork(req.interrupt, req.timestamp) |
|
|
|
|
|
|
|
|
|
case req := <-w.getWorkCh: |
|
|
|
|
block, fees, err := w.generateWork(req.params) |
|
|
|
|
req.result <- &newPayloadResult{ |
|
|
|
|
err: err, |
|
|
|
|
block: block, |
|
|
|
|
fees: fees, |
|
|
|
|
} |
|
|
|
|
req.result <- w.generateWork(req.params) |
|
|
|
|
|
|
|
|
|
case ev := <-w.txsCh: |
|
|
|
|
// Apply transactions to the pending state if we're not sealing
|
|
|
|
@ -739,15 +742,29 @@ func (w *worker) commitTransaction(env *environment, tx *types.Transaction) ([]* |
|
|
|
|
snap = env.state.Snapshot() |
|
|
|
|
gp = env.gasPool.Gas() |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
// Checking against blob gas limit: It's kind of ugly to perform this check here, but there
|
|
|
|
|
// isn't really a better place right now. The blob gas limit is checked at block validation time
|
|
|
|
|
// and not during execution. This means core.ApplyTransaction will not return an error if the
|
|
|
|
|
// tx has too many blobs. So we have to explicitly check it here.
|
|
|
|
|
if (env.blobs+len(tx.BlobHashes()))*params.BlobTxBlobGasPerBlob > params.MaxBlobGasPerBlock { |
|
|
|
|
return nil, errors.New("max data blobs reached") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &env.coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, *w.chain.GetVMConfig()) |
|
|
|
|
if err != nil { |
|
|
|
|
env.state.RevertToSnapshot(snap) |
|
|
|
|
env.gasPool.SetGas(gp) |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
env.txs = append(env.txs, tx) |
|
|
|
|
env.txs = append(env.txs, tx.WithoutBlobTxSidecar()) |
|
|
|
|
env.receipts = append(env.receipts, receipt) |
|
|
|
|
|
|
|
|
|
if sc := tx.BlobTxSidecar(); sc != nil { |
|
|
|
|
env.sidecars = append(env.sidecars, sc) |
|
|
|
|
env.blobs += len(sc.Blobs) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return receipt.Logs, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -895,6 +912,16 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { |
|
|
|
|
header.GasLimit = core.CalcGasLimit(parentGasLimit, w.config.GasCeil) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if w.chainConfig.IsCancun(header.Number, header.Time) { |
|
|
|
|
var excessBlobGas uint64 |
|
|
|
|
if w.chainConfig.IsCancun(parent.Number, parent.Time) { |
|
|
|
|
excessBlobGas = eip4844.CalcExcessBlobGas(*parent.ExcessBlobGas, *parent.BlobGasUsed) |
|
|
|
|
} else { |
|
|
|
|
// For the first post-fork block, both parent.data_gas_used and parent.excess_data_gas are evaluated as 0
|
|
|
|
|
excessBlobGas = eip4844.CalcExcessBlobGas(0, 0) |
|
|
|
|
} |
|
|
|
|
header.ExcessBlobGas = &excessBlobGas |
|
|
|
|
} |
|
|
|
|
// Run the consensus preparation with the default or customized consensus engine.
|
|
|
|
|
if err := w.engine.Prepare(w.chain, header); err != nil { |
|
|
|
|
log.Error("Failed to prepare header for sealing", "err", err) |
|
|
|
@ -915,10 +942,9 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { |
|
|
|
|
// into the given sealing block. The transaction selection and ordering strategy can
|
|
|
|
|
// be customized with the plugin in the future.
|
|
|
|
|
func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) error { |
|
|
|
|
// Split the pending transactions into locals and remotes
|
|
|
|
|
// Fill the block with all available pending transactions.
|
|
|
|
|
pending := w.eth.TxPool().Pending(true) |
|
|
|
|
|
|
|
|
|
// Split the pending transactions into locals and remotes.
|
|
|
|
|
localTxs, remoteTxs := make(map[common.Address][]*txpool.LazyTransaction), pending |
|
|
|
|
for _, account := range w.eth.TxPool().Locals() { |
|
|
|
|
if txs := remoteTxs[account]; len(txs) > 0 { |
|
|
|
@ -926,6 +952,8 @@ func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) err |
|
|
|
|
localTxs[account] = txs |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Fill the block with all available pending transactions.
|
|
|
|
|
if len(localTxs) > 0 { |
|
|
|
|
txs := newTransactionsByPriceAndNonce(env.signer, localTxs, env.header.BaseFee) |
|
|
|
|
if err := w.commitTransactions(env, txs, interrupt); err != nil { |
|
|
|
@ -942,10 +970,10 @@ func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// generateWork generates a sealing block based on the given parameters.
|
|
|
|
|
func (w *worker) generateWork(params *generateParams) (*types.Block, *big.Int, error) { |
|
|
|
|
func (w *worker) generateWork(params *generateParams) *newPayloadResult { |
|
|
|
|
work, err := w.prepareWork(params) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, nil, err |
|
|
|
|
return &newPayloadResult{err: err} |
|
|
|
|
} |
|
|
|
|
defer work.discard() |
|
|
|
|
|
|
|
|
@ -963,9 +991,13 @@ func (w *worker) generateWork(params *generateParams) (*types.Block, *big.Int, e |
|
|
|
|
} |
|
|
|
|
block, err := w.engine.FinalizeAndAssemble(w.chain, work.header, work.state, work.txs, nil, work.receipts, params.withdrawals) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, nil, err |
|
|
|
|
return &newPayloadResult{err: err} |
|
|
|
|
} |
|
|
|
|
return &newPayloadResult{ |
|
|
|
|
block: block, |
|
|
|
|
fees: totalFees(block, work.receipts), |
|
|
|
|
sidecars: work.sidecars, |
|
|
|
|
} |
|
|
|
|
return block, totalFees(block, work.receipts), nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// commitWork generates several new sealing tasks based on the parent block
|
|
|
|
@ -1074,7 +1106,7 @@ func (w *worker) commit(env *environment, interval func(), update bool, start ti |
|
|
|
|
// getSealingBlock generates the sealing block based on the given parameters.
|
|
|
|
|
// The generation result will be passed back via the given channel no matter
|
|
|
|
|
// the generation itself succeeds or not.
|
|
|
|
|
func (w *worker) getSealingBlock(parent common.Hash, timestamp uint64, coinbase common.Address, random common.Hash, withdrawals types.Withdrawals, noTxs bool) (*types.Block, *big.Int, error) { |
|
|
|
|
func (w *worker) getSealingBlock(parent common.Hash, timestamp uint64, coinbase common.Address, random common.Hash, withdrawals types.Withdrawals, noTxs bool) *newPayloadResult { |
|
|
|
|
req := &getWorkReq{ |
|
|
|
|
params: &generateParams{ |
|
|
|
|
timestamp: timestamp, |
|
|
|
@ -1089,13 +1121,9 @@ func (w *worker) getSealingBlock(parent common.Hash, timestamp uint64, coinbase |
|
|
|
|
} |
|
|
|
|
select { |
|
|
|
|
case w.getWorkCh <- req: |
|
|
|
|
result := <-req.result |
|
|
|
|
if result.err != nil { |
|
|
|
|
return nil, nil, result.err |
|
|
|
|
} |
|
|
|
|
return result.block, result.fees, nil |
|
|
|
|
return <-req.result |
|
|
|
|
case <-w.exitCh: |
|
|
|
|
return nil, nil, errors.New("miner closed") |
|
|
|
|
return &newPayloadResult{err: errors.New("miner closed")} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|