miner, consensus, core: remove tracing in mining workflow (#1422)

This PR removes open telemetry based tracing from the whole mining workflow. The tracing extended into consensus and core blockchain functions from miner is also removed in this PR. We weren't checking the tracing from a long time and the way it was implemented increased the code complexity a lot.
This commit is contained in:
Manav Darji 2025-01-30 22:27:03 +05:30 committed by GitHub
parent 984e074a9b
commit 9da0432ec2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 253 additions and 656 deletions

View file

@ -17,7 +17,6 @@
package beacon
import (
"context"
"errors"
"fmt"
"math/big"
@ -398,9 +397,9 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
//
// Note, the method returns immediately and will send the result async. More
// than one result may also be returned depending on the consensus algorithm.
func (beacon *Beacon) Seal(ctx context.Context, chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
func (beacon *Beacon) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
if !beacon.IsPoSHeader(block.Header()) {
return beacon.ethone.Seal(ctx, chain, block, results, stop)
return beacon.ethone.Seal(chain, block, results, stop)
}
// The seal verification is done by the external consensus engine,
// return directly without pushing any block back. In another word

View file

@ -17,13 +17,10 @@ import (
lru "github.com/hashicorp/golang-lru"
"github.com/holiman/uint256"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"golang.org/x/crypto/sha3"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/tracing"
balance_tracing "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/consensus"
@ -820,30 +817,28 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header) e
// Finalize implements consensus.Engine, ensuring no uncles are set, nor block
// rewards given.
func (c *Bor) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body) {
headerNumber := header.Number.Uint64()
if body.Withdrawals != nil || header.WithdrawalsHash != nil {
return
}
var (
stateSyncData []*types.StateSyncData
err error
)
headerNumber := header.Number.Uint64()
if body.Withdrawals != nil || header.WithdrawalsHash != nil {
return
}
if IsSprintStart(headerNumber, c.config.CalculateSprint(headerNumber)) {
start := time.Now()
ctx := context.Background()
cx := statefull.ChainContext{Chain: chain, Bor: c}
// check and commit span
if err := c.checkAndCommitSpan(ctx, state, header, cx); err != nil {
if err := c.checkAndCommitSpan(state, header, cx); err != nil {
log.Error("Error while committing span", "error", err)
return
}
if c.HeimdallClient != nil {
// commit states
stateSyncData, err = c.CommitStates(ctx, state, header, cx)
stateSyncData, err = c.CommitStates(state, header, cx)
if err != nil {
log.Error("Error while committing states", "error", err)
return
@ -908,38 +903,28 @@ func (c *Bor) changeContractCodeIfNeeded(headerNumber uint64, state *state.State
// FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set,
// nor block rewards given, and returns the final block.
func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) {
finalizeCtx, finalizeSpan := tracing.StartSpan(context.Background(), "bor.FinalizeAndAssemble")
defer tracing.EndSpan(finalizeSpan)
headerNumber := header.Number.Uint64()
if body.Withdrawals != nil || header.WithdrawalsHash != nil {
return nil, consensus.ErrUnexpectedWithdrawals
}
stateSyncData := []*types.StateSyncData{}
var err error
var (
stateSyncData []*types.StateSyncData
err error
)
if IsSprintStart(headerNumber, c.config.CalculateSprint(headerNumber)) {
cx := statefull.ChainContext{Chain: chain, Bor: c}
tracing.Exec(finalizeCtx, "", "bor.checkAndCommitSpan", func(ctx context.Context, span trace.Span) {
// check and commit span
err = c.checkAndCommitSpan(finalizeCtx, state, header, cx)
})
if err != nil {
if err = c.checkAndCommitSpan(state, header, cx); err != nil {
log.Error("Error while committing span", "error", err)
return nil, err
}
if c.HeimdallClient != nil {
tracing.Exec(finalizeCtx, "", "bor.checkAndCommitSpan", func(ctx context.Context, span trace.Span) {
// commit states
stateSyncData, err = c.CommitStates(finalizeCtx, state, header, cx)
})
stateSyncData, err = c.CommitStates(state, header, cx)
if err != nil {
log.Error("Error while committing states", "error", err)
return nil, err
@ -947,19 +932,13 @@ func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *typ
}
}
tracing.Exec(finalizeCtx, "", "bor.changeContractCodeIfNeeded", func(ctx context.Context, span trace.Span) {
err = c.changeContractCodeIfNeeded(headerNumber, state)
})
if err != nil {
if err = c.changeContractCodeIfNeeded(headerNumber, state); err != nil {
log.Error("Error changing contract code", "error", err)
return nil, err
}
// No block rewards in PoA, so the state remains as it is
tracing.Exec(finalizeCtx, "", "bor.IntermediateRoot", func(ctx context.Context, span trace.Span) {
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
})
// Uncles are dropped
header.UncleHash = types.CalcUncleHash(nil)
@ -971,14 +950,6 @@ func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *typ
bc := chain.(core.BorStateSyncer)
bc.SetStateSync(stateSyncData)
tracing.SetAttributes(
finalizeSpan,
attribute.Int("number", int(header.Number.Int64())),
attribute.String("hash", header.Hash().String()),
attribute.Int("number of txs", len(body.Transactions)),
attribute.Int("gas used", int(block.GasUsed())),
)
// return the final block for sealing
return block, nil
}
@ -994,18 +965,7 @@ func (c *Bor) Authorize(currentSigner common.Address, signFn SignerFn) {
// Seal implements consensus.Engine, attempting to create a sealed block using
// the local signing credentials.
func (c *Bor) Seal(ctx context.Context, chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
_, sealSpan := tracing.StartSpan(ctx, "bor.Seal")
var endSpan bool = true
defer func() {
// Only end span in case of early-returns/errors
if endSpan {
tracing.EndSpan(sealSpan)
}
}()
func (c *Bor) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
header := block.Header()
// Sealing the genesis block is not supported
number := header.Number.Uint64()
@ -1051,7 +1011,7 @@ func (c *Bor) Seal(ctx context.Context, chain consensus.ChainHeaderReader, block
// Wait until sealing is terminated or delay timeout.
log.Info("Waiting for slot to sign and propagate", "number", number, "hash", header.Hash, "delay-in-sec", uint(delay), "delay", common.PrettyDuration(delay))
go func(sealSpan trace.Span) {
go func() {
select {
case <-stop:
log.Debug("Discarding sealing operation for block", "number", number)
@ -1074,27 +1034,13 @@ func (c *Bor) Seal(ctx context.Context, chain consensus.ChainHeaderReader, block
"delay", delay,
"headerDifficulty", header.Difficulty,
)
tracing.SetAttributes(
sealSpan,
attribute.Int("number", int(number)),
attribute.String("hash", header.Hash().String()),
attribute.Int("delay", int(delay.Milliseconds())),
attribute.Int("wiggle", int(wiggle.Milliseconds())),
attribute.Bool("out-of-turn", wiggle > 0),
)
tracing.EndSpan(sealSpan)
}
select {
case results <- block.WithSeal(header):
default:
log.Warn("Sealing result was not read by miner", "number", number, "sealhash", SealHash(header, c.config))
}
}(sealSpan)
// Set the endSpan flag to false, as the go routine will handle it
endSpan = false
}()
return nil
}
@ -1150,11 +1096,11 @@ func (c *Bor) Close() error {
}
func (c *Bor) checkAndCommitSpan(
ctx context.Context,
state *state.StateDB,
header *types.Header,
chain core.ChainContext,
) error {
var ctx = context.Background()
headerNumber := header.Number.Uint64()
span, err := c.spanner.GetCurrentSpan(ctx, header.ParentHash)
@ -1228,7 +1174,6 @@ func (c *Bor) FetchAndCommitSpan(
// CommitStates commit states
func (c *Bor) CommitStates(
ctx context.Context,
state *state.StateDB,
header *types.Header,
chain statefull.ChainContext,
@ -1269,7 +1214,7 @@ func (c *Bor) CommitStates(
"fromID", from,
"to", to.Format(time.RFC3339))
eventRecords, err := c.HeimdallClient.StateSyncEvents(ctx, from, to.Unix())
eventRecords, err := c.HeimdallClient.StateSyncEvents(context.Background(), from, to.Unix())
if err != nil {
log.Error("Error occurred when fetching state sync events", "fromID", from, "to", to.Unix(), "err", err)
}

View file

@ -19,7 +19,6 @@ package clique
import (
"bytes"
"context"
"errors"
"fmt"
"io"
@ -652,7 +651,7 @@ func (c *Clique) Authorize(signer common.Address, signFn SignerFn) {
// Seal implements consensus.Engine, attempting to create a sealed block using
// the local signing credentials.
func (c *Clique) Seal(ctx context.Context, chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
func (c *Clique) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
header := block.Header()
// Sealing the genesis block is not supported

View file

@ -18,7 +18,6 @@
package consensus
import (
"context"
"math/big"
"github.com/ethereum/go-ethereum/common"
@ -103,7 +102,7 @@ type Engine interface {
//
// Note, the method returns immediately and will send the result async. More
// than one result may also be returned depending on the consensus algorithm.
Seal(ctx context.Context, chain ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error
Seal(chain ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error
// SealHash returns the hash of a block prior to it being sealed.
SealHash(header *types.Header) common.Hash

View file

@ -18,7 +18,6 @@
package ethash
import (
"context"
"time"
"github.com/ethereum/go-ethereum/consensus"
@ -81,6 +80,6 @@ func (ethash *Ethash) APIs(chain consensus.ChainHeaderReader) []rpc.API {
// Seal generates a new sealing request for the given input block and pushes
// the result into the given channel. For the ethash engine, this method will
// just panic as sealing is not supported anymore.
func (ethash *Ethash) Seal(ctx context.Context, chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
func (ethash *Ethash) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
panic("ethash (pow) sealing not supported any more")
}

View file

@ -1922,18 +1922,18 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
// WriteBlockAndSetHead writes the given block and all associated state to the database,
// and applies the block as the new chain head.
func (bc *BlockChain) WriteBlockAndSetHead(ctx context.Context, block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
func (bc *BlockChain) WriteBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
if !bc.chainmu.TryLock() {
return NonStatTy, errChainStopped
}
defer bc.chainmu.Unlock()
return bc.writeBlockAndSetHead(ctx, block, receipts, logs, state, emitHeadEvent)
return bc.writeBlockAndSetHead(block, receipts, logs, state, emitHeadEvent)
}
// writeBlockAndSetHead is the internal implementation of WriteBlockAndSetHead.
// This function expects the chain mutex to be held.
func (bc *BlockChain) writeBlockAndSetHead(ctx context.Context, block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
stateSyncLogs, err := bc.writeBlockWithState(block, receipts, logs, state)
if err != nil {
return NonStatTy, err
@ -2401,7 +2401,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
// Don't set the head, only insert the block
_, err = bc.writeBlockWithState(block, receipts, logs, statedb)
} else {
status, err = bc.writeBlockAndSetHead(context.Background(), block, receipts, logs, statedb, false)
status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false)
}
followupInterrupt.Store(true)
@ -2574,7 +2574,7 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
// Don't set the head, only insert the block
_, err = bc.writeBlockWithState(block, receipts, logs, statedb)
} else {
status, err = bc.writeBlockAndSetHead(context.Background(), block, receipts, logs, statedb, false)
status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false)
}
if err != nil {
return nil, err

View file

@ -3,8 +3,6 @@ package miner
import (
"context"
"errors"
"fmt"
"os"
"sync"
"sync/atomic"
"time"
@ -12,9 +10,8 @@ import (
// nolint:typecheck
"github.com/ethereum/go-ethereum/common"
cmath "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/common/tracing"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/blockstm"
"github.com/ethereum/go-ethereum/core/state"
@ -27,10 +24,6 @@ import (
"github.com/ethereum/go-ethereum/rlp"
"github.com/holiman/uint256"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
lru "github.com/hashicorp/golang-lru"
)
@ -102,12 +95,10 @@ func newWorkerWithDelay(config *Config, chainConfig *params.ChainConfig, engine
worker.newpayloadTimeout = newpayloadTimeout
ctx := tracing.WithTracer(context.Background(), otel.GetTracerProvider().Tracer("MinerWorker"))
worker.wg.Add(4)
go worker.mainLoopWithDelay(ctx, delay, opcodeDelay)
go worker.newWorkLoop(ctx, recommit)
go worker.mainLoopWithDelay(delay, opcodeDelay)
go worker.newWorkLoop(recommit)
go worker.resultLoop()
go worker.taskLoop()
@ -121,7 +112,7 @@ func newWorkerWithDelay(config *Config, chainConfig *params.ChainConfig, engine
// mainLoopWithDelay is mainLoop() with extra params to induce artficial delays for tests such as commit-interrupt.
// nolint:gocognit
func (w *worker) mainLoopWithDelay(ctx context.Context, delay uint, opcodeDelay uint) {
func (w *worker) mainLoopWithDelay(delay uint, opcodeDelay uint) {
defer w.wg.Done()
defer w.txsSub.Unsubscribe()
defer w.chainHeadSub.Unsubscribe()
@ -137,15 +128,15 @@ func (w *worker) mainLoopWithDelay(ctx context.Context, delay uint, opcodeDelay
if w.chainConfig.ChainID.Cmp(params.BorMainnetChainConfig.ChainID) == 0 || w.chainConfig.ChainID.Cmp(params.MumbaiChainConfig.ChainID) == 0 {
if w.eth.PeerCount() > 0 {
//nolint:contextcheck
w.commitWorkWithDelay(req.ctx, req.interrupt, req.noempty, req.timestamp, delay, opcodeDelay)
w.commitWorkWithDelay(req.interrupt, req.noempty, req.timestamp, delay, opcodeDelay)
}
} else {
//nolint:contextcheck
w.commitWorkWithDelay(req.ctx, req.interrupt, req.noempty, req.timestamp, delay, opcodeDelay)
w.commitWorkWithDelay(req.interrupt, req.noempty, req.timestamp, delay, opcodeDelay)
}
case req := <-w.getWorkCh:
req.result <- w.generateWork(ctx, req.params)
req.result <- w.generateWork(req.params)
case ev := <-w.txsCh:
// Apply transactions to the pending state if we're not sealing
@ -187,7 +178,7 @@ func (w *worker) mainLoopWithDelay(ctx context.Context, delay uint, opcodeDelay
// submit sealing work here since all empty submission will be rejected
// by clique. Of course the advance sealing(empty submission) is disabled.
if w.chainConfig.Clique != nil && w.chainConfig.Clique.Period == 0 {
w.commitWork(ctx, nil, true, time.Now().Unix())
w.commitWork(nil, true, time.Now().Unix())
}
}
@ -205,7 +196,7 @@ func (w *worker) mainLoopWithDelay(ctx context.Context, delay uint, opcodeDelay
}
// commitWorkWithDelay is commitWork() with extra params to induce artficial delays for tests such as commit-interrupt.
func (w *worker) commitWorkWithDelay(ctx context.Context, interrupt *atomic.Int32, noempty bool, timestamp int64, delay uint, opcodeDelay uint) {
func (w *worker) commitWorkWithDelay(interrupt *atomic.Int32, noempty bool, timestamp int64, delay uint, opcodeDelay uint) {
// Abort committing if node is still syncing
if w.syncing.Load() {
return
@ -217,7 +208,6 @@ func (w *worker) commitWorkWithDelay(ctx context.Context, interrupt *atomic.Int3
err error
)
tracing.Exec(ctx, "", "worker.prepareWork", func(ctx context.Context, span trace.Span) {
// Set the coinbase if the worker is running or it's required
var coinbase common.Address
if w.IsRunning() {
@ -232,8 +222,6 @@ func (w *worker) commitWorkWithDelay(ctx context.Context, interrupt *atomic.Int3
timestamp: uint64(timestamp),
coinbase: coinbase,
})
})
if err != nil {
return
}
@ -248,7 +236,7 @@ func (w *worker) commitWorkWithDelay(ctx context.Context, interrupt *atomic.Int3
if !noempty && w.interruptCommitFlag {
block := w.chain.GetBlockByHash(w.chain.CurrentBlock().Hash())
interruptCtx, stopFn = getInterruptTimer(ctx, work, block)
interruptCtx, stopFn = getInterruptTimer(work, block)
// nolint : staticcheck
interruptCtx = vm.PutCache(interruptCtx, w.interruptedTxCache)
// nolint : staticcheck
@ -257,21 +245,13 @@ func (w *worker) commitWorkWithDelay(ctx context.Context, interrupt *atomic.Int3
interruptCtx = context.WithValue(interruptCtx, vm.InterruptCtxOpcodeDelayKey, opcodeDelay)
}
ctx, span := tracing.StartSpan(ctx, "commitWork")
defer tracing.EndSpan(span)
tracing.SetAttributes(
span,
attribute.Int("number", int(work.header.Number.Uint64())),
)
// Create an empty block based on temporary copied state for
// sealing in advance without waiting block execution finished.
if !noempty && !w.noempty.Load() {
_ = w.commit(ctx, work.copy(), nil, false, start)
_ = w.commit(work.copy(), nil, false, start)
}
// Fill pending transactions from the txpool into the block.
err = w.fillTransactionsWithDelay(ctx, interrupt, work, interruptCtx)
err = w.fillTransactionsWithDelay(interrupt, work, interruptCtx)
switch {
case err == nil:
@ -302,7 +282,7 @@ func (w *worker) commitWorkWithDelay(ctx context.Context, interrupt *atomic.Int3
return
}
// Submit the generated block for consensus sealing.
_ = w.commit(ctx, work.copy(), w.fullTaskHook, true, start)
_ = w.commit(work.copy(), w.fullTaskHook, true, start)
// Swap out the old work with the new one, terminating any leftover
// prefetcher processes in the mean time and starting a new one.
@ -315,182 +295,78 @@ func (w *worker) commitWorkWithDelay(ctx context.Context, interrupt *atomic.Int3
// fillTransactionsWithDelay is fillTransactions() with extra params to induce artficial delays for tests such as commit-interrupt.
// nolint:gocognit
func (w *worker) fillTransactionsWithDelay(ctx context.Context, interrupt *atomic.Int32, env *environment, interruptCtx context.Context) error {
ctx, span := tracing.StartSpan(ctx, "fillTransactions")
defer tracing.EndSpan(span)
func (w *worker) fillTransactionsWithDelay(interrupt *atomic.Int32, env *environment, interruptCtx context.Context) error {
w.mu.RLock()
tip := w.tip
w.mu.RUnlock()
// Split the pending transactions into locals and remotes
// Fill the block with all available pending transactions.
pending := w.eth.TxPool().Pending(txpool.PendingFilter{})
localTxs, remoteTxs := make(map[common.Address][]*txpool.LazyTransaction), pending
// Retrieve the pending transactions pre-filtered by the 1559/4844 dynamic fees
filter := txpool.PendingFilter{
MinTip: uint256.MustFromBig(tip.ToBig()),
}
if env.header.BaseFee != nil {
filter.BaseFee = uint256.MustFromBig(env.header.BaseFee)
}
if env.header.ExcessBlobGas != nil {
filter.BlobFee = uint256.MustFromBig(eip4844.CalcBlobFee(*env.header.ExcessBlobGas))
}
var (
localTxsCount int
remoteTxsCount int
localPlainTxs, remotePlainTxs, localBlobTxs, remoteBlobTxs map[common.Address][]*txpool.LazyTransaction
)
// TODO: move to config or RPC
const profiling = false
filter.OnlyPlainTxs, filter.OnlyBlobTxs = true, false
pendingPlainTxs := w.eth.TxPool().Pending(filter)
if profiling {
doneCh := make(chan struct{})
filter.OnlyPlainTxs, filter.OnlyBlobTxs = false, true
pendingBlobTxs := w.eth.TxPool().Pending(filter)
defer func() {
close(doneCh)
}()
go func(number uint64) {
closeFn := func() error {
return nil
}
for {
select {
case <-time.After(150 * time.Millisecond):
// Check if we've not crossed limit
if attempt := atomic.AddInt32(w.profileCount, 1); attempt >= 10 {
log.Info("Completed profiling", "attempt", attempt)
return
}
log.Info("Starting profiling in fill transactions", "number", number)
dir, err := os.MkdirTemp("", fmt.Sprintf("bor-traces-%s-", time.Now().UTC().Format("2006-01-02-150405Z")))
if err != nil {
log.Error("Error in profiling", "path", dir, "number", number, "err", err)
return
}
// grab the cpu profile
closeFnInternal, err := startProfiler("cpu", dir, number)
if err != nil {
log.Error("Error in profiling", "path", dir, "number", number, "err", err)
return
}
closeFn = func() error {
err := closeFnInternal()
log.Info("Completed profiling", "path", dir, "number", number, "error", err)
return nil
}
case <-doneCh:
err := closeFn()
if err != nil {
log.Info("closing fillTransactions", "number", number, "error", err)
}
return
}
}
}(env.header.Number.Uint64())
}
tracing.Exec(ctx, "", "worker.SplittingTransactions", func(ctx context.Context, span trace.Span) {
prePendingTime := time.Now()
pending := w.eth.TxPool().Pending(txpool.PendingFilter{})
remoteTxs = pending
postPendingTime := time.Now()
// Split the pending transactions into locals and remotes.
localPlainTxs, remotePlainTxs = make(map[common.Address][]*txpool.LazyTransaction), pendingPlainTxs
localBlobTxs, remoteBlobTxs = make(map[common.Address][]*txpool.LazyTransaction), pendingBlobTxs
for _, account := range w.eth.TxPool().Locals() {
if txs := remoteTxs[account]; len(txs) > 0 {
delete(remoteTxs, account)
localTxs[account] = txs
if txs := remotePlainTxs[account]; len(txs) > 0 {
delete(remotePlainTxs, account)
localPlainTxs[account] = txs
}
if txs := remoteBlobTxs[account]; len(txs) > 0 {
delete(remoteBlobTxs, account)
localBlobTxs[account] = txs
}
}
postLocalsTime := time.Now()
// Fill the block with all available pending transactions.
if len(localPlainTxs) > 0 || len(localBlobTxs) > 0 {
var plainTxs, blobTxs *transactionsByPriceAndNonce
tracing.SetAttributes(
span,
attribute.Int("len of local txs", localTxsCount),
attribute.Int("len of remote txs", remoteTxsCount),
attribute.String("time taken by Pending()", fmt.Sprintf("%v", postPendingTime.Sub(prePendingTime))),
attribute.String("time taken by Locals()", fmt.Sprintf("%v", postLocalsTime.Sub(postPendingTime))),
)
})
plainTxs = newTransactionsByPriceAndNonce(env.signer, localPlainTxs, env.header.BaseFee)
blobTxs = newTransactionsByPriceAndNonce(env.signer, localBlobTxs, env.header.BaseFee)
var (
localEnvTCount int
remoteEnvTCount int
err error
)
if len(localTxs) > 0 {
var txs *transactionsByPriceAndNonce
tracing.Exec(ctx, "", "worker.LocalTransactionsByPriceAndNonce", func(ctx context.Context, span trace.Span) {
var baseFee *uint256.Int
if env.header.BaseFee != nil {
baseFee = cmath.FromBig(env.header.BaseFee)
}
txs = newTransactionsByPriceAndNonce(env.signer, localTxs, baseFee.ToBig())
tracing.SetAttributes(
span,
attribute.Int("len of tx local Heads", txs.GetTxs()),
)
})
tracing.Exec(ctx, "", "worker.LocalCommitTransactions", func(ctx context.Context, span trace.Span) {
err = w.commitTransactionsWithDelay(env, txs, interrupt, interruptCtx)
})
if err != nil {
if err := w.commitTransactionsWithDelay(env, plainTxs, blobTxs, interrupt, new(uint256.Int), interruptCtx); err != nil {
return err
}
localEnvTCount = env.tcount
}
if len(remoteTxs) > 0 {
var txs *transactionsByPriceAndNonce
if len(remotePlainTxs) > 0 || len(remoteBlobTxs) > 0 {
var plainTxs, blobTxs *transactionsByPriceAndNonce
tracing.Exec(ctx, "", "worker.RemoteTransactionsByPriceAndNonce", func(ctx context.Context, span trace.Span) {
var baseFee *uint256.Int
if env.header.BaseFee != nil {
baseFee = cmath.FromBig(env.header.BaseFee)
}
plainTxs = newTransactionsByPriceAndNonce(env.signer, remotePlainTxs, env.header.BaseFee)
blobTxs = newTransactionsByPriceAndNonce(env.signer, remoteBlobTxs, env.header.BaseFee)
txs = newTransactionsByPriceAndNonce(env.signer, remoteTxs, baseFee.ToBig())
tracing.SetAttributes(
span,
attribute.Int("len of tx remote Heads", txs.GetTxs()),
)
})
tracing.Exec(ctx, "", "worker.RemoteCommitTransactions", func(ctx context.Context, span trace.Span) {
err = w.commitTransactionsWithDelay(env, txs, interrupt, interruptCtx)
})
if err != nil {
if err := w.commitTransactionsWithDelay(env, plainTxs, blobTxs, interrupt, new(uint256.Int), interruptCtx); err != nil {
return err
}
remoteEnvTCount = env.tcount
}
tracing.SetAttributes(
span,
attribute.Int("len of final local txs ", localEnvTCount),
attribute.Int("len of final remote txs", remoteEnvTCount),
)
return nil
}
// commitTransactionsWithDelay is commitTransactions() with extra params to induce artficial delays for tests such as commit-interrupt.
// nolint:gocognit, unparam
func (w *worker) commitTransactionsWithDelay(env *environment, txs *transactionsByPriceAndNonce, interrupt *atomic.Int32, interruptCtx context.Context) error {
func (w *worker) commitTransactionsWithDelay(env *environment, plainTxs, blobTxs *transactionsByPriceAndNonce, interrupt *atomic.Int32, minTip *uint256.Int, interruptCtx context.Context) error {
gasLimit := env.header.GasLimit
if env.gasPool == nil {
env.gasPool = new(core.GasPool).AddGas(gasLimit)
@ -498,35 +374,25 @@ func (w *worker) commitTransactionsWithDelay(env *environment, txs *transactions
var coalescedLogs []*types.Log
var depsMVReadList [][]blockstm.ReadDescriptor
var depsMVFullWriteList [][]blockstm.WriteDescriptor
var mvReadMapList []map[blockstm.Key]blockstm.ReadDescriptor
var deps map[int]map[int]bool
chDeps := make(chan blockstm.TxDep)
var count int
var depsWg sync.WaitGroup
var once sync.Once
EnableMVHashMap := w.chainConfig.IsCancun(env.header.Number)
// create and add empty mvHashMap in statedb
if EnableMVHashMap {
depsMVReadList = [][]blockstm.ReadDescriptor{}
depsMVFullWriteList = [][]blockstm.WriteDescriptor{}
mvReadMapList = []map[blockstm.Key]blockstm.ReadDescriptor{}
if EnableMVHashMap && w.IsRunning() {
deps = map[int]map[int]bool{}
chDeps = make(chan blockstm.TxDep)
count = 0
// Make sure we safely close the channel in case of interrupt
defer once.Do(func() {
close(chDeps)
})
depsWg.Add(1)
@ -543,8 +409,15 @@ func (w *worker) commitTransactionsWithDelay(env *environment, txs *transactions
mainloop:
for {
// Check interruption signal and abort building if it's fired.
if interrupt != nil {
if signal := interrupt.Load(); signal != commitInterruptNone {
return signalToErr(signal)
}
}
if interruptCtx != nil {
if EnableMVHashMap {
if EnableMVHashMap && w.IsRunning() {
env.state.AddEmptyMVHashMap()
}
@ -558,19 +431,39 @@ mainloop:
}
}
// Check interruption signal and abort building if it's fired.
if interrupt != nil {
if signal := interrupt.Load(); signal != commitInterruptNone {
return signalToErr(signal)
}
}
// If we don't have enough gas for any further transactions then we're done.
if env.gasPool.Gas() < params.TxGas {
log.Trace("Not enough gas for further transactions", "have", env.gasPool, "want", params.TxGas)
break
}
// If we don't have enough blob space for any further blob transactions,
// skip that list altogether
if !blobTxs.Empty() && env.blobs*params.BlobTxBlobGasPerBlob >= params.MaxBlobGasPerBlock {
log.Trace("Not enough blob space for further blob transactions")
blobTxs.Clear()
// Fall though to pick up any plain txs
}
// Retrieve the next transaction and abort if all done.
ltx, _ := txs.Peek()
var (
ltx *txpool.LazyTransaction
txs *transactionsByPriceAndNonce
)
pltx, ptip := plainTxs.Peek()
bltx, btip := blobTxs.Peek()
switch {
case pltx == nil:
txs, ltx = blobTxs, bltx
case bltx == nil:
txs, ltx = plainTxs, pltx
default:
if ptip.Lt(btip) {
txs, ltx = blobTxs, bltx
} else {
txs, ltx = plainTxs, pltx
}
}
if ltx == nil {
break
}
@ -586,6 +479,11 @@ mainloop:
txs.Pop()
continue
}
// If we don't receive enough tip for the next transaction, skip the account
if ptip.Cmp(minTip) < 0 {
log.Trace("Not enough tip for transaction", "hash", ltx.Hash, "tip", ptip, "needed", minTip)
break // If the next-best is too low, surely no better will be available
}
// Transaction seems to fit, pull it up from the pool
tx := ltx.Resolve()
if tx == nil {
@ -594,7 +492,7 @@ mainloop:
continue
}
// Error may be ignored here. The error has already been checked
// during transaction acceptance is the transaction pool.
// during transaction acceptance in the transaction pool.
from, _ := types.Sender(env.signer, tx)
// not prioritising conditional transaction, yet.
@ -652,19 +550,21 @@ mainloop:
coalescedLogs = append(coalescedLogs, logs...)
env.tcount++
if EnableMVHashMap {
depsMVReadList = append(depsMVReadList, env.state.MVReadList())
depsMVFullWriteList = append(depsMVFullWriteList, env.state.MVFullWriteList())
mvReadMapList = append(mvReadMapList, env.state.MVReadMap())
if EnableMVHashMap && w.IsRunning() {
env.depsMVFullWriteList = append(env.depsMVFullWriteList, env.state.MVFullWriteList())
env.mvReadMapList = append(env.mvReadMapList, env.state.MVReadMap())
if env.tcount > len(env.depsMVFullWriteList) {
log.Warn("blockstm - env.tcount > len(env.depsMVFullWriteList)", "env.tcount", env.tcount, "len(depsMVFullWriteList)", len(env.depsMVFullWriteList))
}
temp := blockstm.TxDep{
Index: env.tcount - 1,
ReadList: depsMVReadList[count],
FullWriteList: depsMVFullWriteList,
ReadList: env.state.MVReadList(),
FullWriteList: env.depsMVFullWriteList,
}
chDeps <- temp
count++
}
txs.Shift()
@ -675,7 +575,7 @@ mainloop:
txs.Pop()
}
if EnableMVHashMap {
if EnableMVHashMap && w.IsRunning() {
env.state.ClearReadMap()
env.state.ClearWriteMap()
}
@ -683,7 +583,9 @@ mainloop:
// nolint:nestif
if EnableMVHashMap && w.IsRunning() {
once.Do(func() {
close(chDeps)
})
depsWg.Wait()
var blockExtraData types.BlockExtraData
@ -691,8 +593,8 @@ mainloop:
tempVanity := env.header.Extra[:types.ExtraVanityLength]
tempSeal := env.header.Extra[len(env.header.Extra)-types.ExtraSealLength:]
if len(mvReadMapList) > 0 {
tempDeps := make([][]uint64, len(mvReadMapList))
if len(env.mvReadMapList) > 0 {
tempDeps := make([][]uint64, len(env.mvReadMapList))
for j := range deps[0] {
tempDeps[0] = append(tempDeps[0], uint64(j))
@ -700,14 +602,15 @@ mainloop:
delayFlag := true
for i := 1; i <= len(mvReadMapList)-1; i++ {
reads := mvReadMapList[i-1]
for i := 1; i <= len(env.mvReadMapList)-1; i++ {
reads := env.mvReadMapList[i-1]
_, ok1 := reads[blockstm.NewSubpathKey(env.coinbase, state.BalancePath)]
_, ok2 := reads[blockstm.NewSubpathKey(common.HexToAddress(w.chainConfig.Bor.CalculateBurntContract(env.header.Number.Uint64())), state.BalancePath)]
if ok1 || ok2 {
delayFlag = false
break
}
for j := range deps[i] {

View file

@ -17,15 +17,10 @@
package miner
import (
"bytes"
"context"
"errors"
"fmt"
"math/big"
"os"
"runtime"
"runtime/pprof"
ptrace "runtime/trace"
"sync"
"sync/atomic"
"time"
@ -33,8 +28,6 @@ import (
lru "github.com/hashicorp/golang-lru"
"github.com/holiman/uint256"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/tracing"
@ -155,8 +148,6 @@ func (env *environment) discard() {
// task contains all information for consensus engine sealing and result submitting.
type task struct {
//nolint:containedctx
ctx context.Context
receipts []*types.Receipt
state *state.StateDB
block *types.Block
@ -172,8 +163,6 @@ const (
// newWorkReq represents a request for new sealing work submitting with relative interrupt notifier.
type newWorkReq struct {
//nolint:containedctx
ctx context.Context
interrupt *atomic.Int32
noempty bool
timestamp int64
@ -352,12 +341,10 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus
worker.newpayloadTimeout = newpayloadTimeout
ctx := tracing.WithTracer(context.Background(), otel.GetTracerProvider().Tracer("MinerWorker"))
worker.wg.Add(4)
go worker.mainLoop(ctx)
go worker.newWorkLoop(ctx, recommit)
go worker.mainLoop()
go worker.newWorkLoop(recommit)
go worker.resultLoop()
go worker.taskLoop()
@ -483,7 +470,7 @@ func recalcRecommit(minRecommit, prev time.Duration, target float64, inc bool) t
// newWorkLoop is a standalone goroutine to submit new sealing work upon received events.
//
//nolint:gocognit
func (w *worker) newWorkLoop(ctx context.Context, recommit time.Duration) {
func (w *worker) newWorkLoop(recommit time.Duration) {
defer w.wg.Done()
var (
@ -498,15 +485,13 @@ func (w *worker) newWorkLoop(ctx context.Context, recommit time.Duration) {
// commit aborts in-flight transaction execution with given signal and resubmits a new one.
commit := func(noempty bool, s int32) {
ctx, span := tracing.Trace(ctx, "worker.newWorkLoop.commit")
tracing.EndSpan(span)
if interrupt != nil {
interrupt.Store(s)
}
interrupt = new(atomic.Int32)
select {
case w.newWorkCh <- &newWorkReq{interrupt: interrupt, timestamp: timestamp, ctx: ctx, noempty: noempty}:
case w.newWorkCh <- &newWorkReq{interrupt: interrupt, timestamp: timestamp, noempty: noempty}:
case <-w.exitCh:
return
}
@ -515,9 +500,6 @@ func (w *worker) newWorkLoop(ctx context.Context, recommit time.Duration) {
}
// clearPending cleans the stale pending tasks.
clearPending := func(number uint64) {
_, span := tracing.Trace(ctx, "worker.newWorkLoop.clearPending")
tracing.EndSpan(span)
w.pendingMu.Lock()
for h, t := range w.pendingTasks {
if t.block.NumberU64()+staleThreshold <= number {
@ -594,7 +576,7 @@ func (w *worker) newWorkLoop(ctx context.Context, recommit time.Duration) {
// the received event. It can support two modes: automatically generate task and
// submit it or return task according to given parameters for various proposes.
// nolint: gocognit, contextcheck
func (w *worker) mainLoop(ctx context.Context) {
func (w *worker) mainLoop() {
defer w.wg.Done()
defer w.txsSub.Unsubscribe()
defer w.chainHeadSub.Unsubscribe()
@ -610,15 +592,15 @@ func (w *worker) mainLoop(ctx context.Context) {
if w.chainConfig.ChainID.Cmp(params.BorMainnetChainConfig.ChainID) == 0 || w.chainConfig.ChainID.Cmp(params.MumbaiChainConfig.ChainID) == 0 || w.chainConfig.ChainID.Cmp(params.AmoyChainConfig.ChainID) == 0 {
if w.eth.PeerCount() > 0 {
//nolint:contextcheck
w.commitWork(req.ctx, req.interrupt, req.noempty, req.timestamp)
w.commitWork(req.interrupt, req.noempty, req.timestamp)
}
} else {
//nolint:contextcheck
w.commitWork(req.ctx, req.interrupt, req.noempty, req.timestamp)
w.commitWork(req.interrupt, req.noempty, req.timestamp)
}
case req := <-w.getWorkCh:
req.result <- w.generateWork(ctx, req.params)
req.result <- w.generateWork(req.params)
case ev := <-w.txsCh:
// Apply transactions to the pending state if we're not sealing
@ -663,7 +645,7 @@ func (w *worker) mainLoop(ctx context.Context) {
// submit sealing work here since all empty submission will be rejected
// by clique. Of course the advance sealing(empty submission) is disabled.
if w.chainConfig.Clique != nil && w.chainConfig.Clique.Period == 0 {
w.commitWork(ctx, nil, true, time.Now().Unix())
w.commitWork(nil, true, time.Now().Unix())
}
}
@ -722,7 +704,7 @@ func (w *worker) taskLoop() {
w.pendingTasks[sealHash] = task
w.pendingMu.Unlock()
if err := w.engine.Seal(task.ctx, w.chain, task.block, w.resultCh, stopCh); err != nil {
if err := w.engine.Seal(w.chain, task.block, w.resultCh, stopCh); err != nil {
log.Warn("Block sealing failed", "err", err)
w.pendingMu.Lock()
delete(w.pendingTasks, sealHash)
@ -783,7 +765,6 @@ func (w *worker) resultLoop() {
err error
)
tracing.Exec(task.ctx, "", "resultLoop", func(ctx context.Context, span trace.Span) {
for i, taskReceipt := range task.receipts {
receipt := new(types.Receipt)
receipts[i] = receipt
@ -808,20 +789,7 @@ func (w *worker) resultLoop() {
logs = append(logs, receipt.Logs...)
}
// Commit block and state to database.
tracing.Exec(ctx, "", "resultLoop.WriteBlockAndSetHead", func(ctx context.Context, span trace.Span) {
_, err = w.chain.WriteBlockAndSetHead(ctx, block, receipts, logs, task.state, true)
})
tracing.SetAttributes(
span,
attribute.String("hash", hash.String()),
attribute.Int("number", int(block.Number().Uint64())),
attribute.Int("txns", block.Transactions().Len()),
attribute.Int("gas used", int(block.GasUsed())),
attribute.Int("elapsed", int(time.Since(task.createdAt).Milliseconds())),
attribute.Bool("error", err != nil),
)
})
_, err = w.chain.WriteBlockAndSetHead(block, receipts, logs, task.state, true)
if err != nil {
log.Error("Failed writing block to chain", "err", err)
@ -1301,80 +1269,13 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
return env, nil
}
func startProfiler(profile string, filepath string, number uint64) (func() error, error) {
var (
buf bytes.Buffer
err error
)
closeFn := func() {}
switch profile {
case "cpu":
err = pprof.StartCPUProfile(&buf)
if err == nil {
closeFn = func() {
pprof.StopCPUProfile()
}
}
case "trace":
err = ptrace.Start(&buf)
if err == nil {
closeFn = func() {
ptrace.Stop()
}
}
case "heap":
runtime.GC()
err = pprof.WriteHeapProfile(&buf)
default:
log.Info("Incorrect profile name")
}
if err != nil {
return func() error {
closeFn()
return nil
}, err
}
closeFnNew := func() error {
var err error
closeFn()
if buf.Len() == 0 {
return nil
}
f, err := os.Create(filepath + "/" + profile + "-" + fmt.Sprint(number) + ".prof")
if err != nil {
return err
}
defer f.Close()
_, err = f.Write(buf.Bytes())
return err
}
return closeFnNew, nil
}
// fillTransactions retrieves the pending transactions from the txpool and fills them
// into the given sealing block. The transaction selection and ordering strategy can
// be customized with the plugin in the future.
//
//nolint:gocognit
func (w *worker) fillTransactions(ctx context.Context, interrupt *atomic.Int32, env *environment, interruptCtx context.Context) error {
ctx, span := tracing.StartSpan(ctx, "fillTransactions")
defer tracing.EndSpan(span)
func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment, interruptCtx context.Context) error {
w.mu.RLock()
tip := w.tip
w.mu.RUnlock()
@ -1392,79 +1293,10 @@ func (w *worker) fillTransactions(ctx context.Context, interrupt *atomic.Int32,
filter.BlobFee = uint256.MustFromBig(eip4844.CalcBlobFee(*env.header.ExcessBlobGas))
}
var (
localPlainTxsCount int
remotePlainTxsCount int
)
// TODO: move to config or RPC
const profiling = false
if profiling {
doneCh := make(chan struct{})
defer func() {
close(doneCh)
}()
go func(number uint64) {
closeFn := func() error {
return nil
}
for {
select {
case <-time.After(150 * time.Millisecond):
// Check if we've not crossed limit
if attempt := atomic.AddInt32(w.profileCount, 1); attempt >= 10 {
log.Info("Completed profiling", "attempt", attempt)
return
}
log.Info("Starting profiling in fill transactions", "number", number)
dir, err := os.MkdirTemp("", fmt.Sprintf("bor-traces-%s-", time.Now().UTC().Format("2006-01-02-150405Z")))
if err != nil {
log.Error("Error in profiling", "path", dir, "number", number, "err", err)
return
}
// grab the cpu profile
closeFnInternal, err := startProfiler("cpu", dir, number)
if err != nil {
log.Error("Error in profiling", "path", dir, "number", number, "err", err)
return
}
closeFn = func() error {
err := closeFnInternal()
log.Info("Completed profiling", "path", dir, "number", number, "error", err)
return nil
}
case <-doneCh:
err := closeFn()
if err != nil {
log.Info("closing fillTransactions", "number", number, "error", err)
}
return
}
}
}(env.header.Number.Uint64())
}
var (
localPlainTxs, remotePlainTxs, localBlobTxs, remoteBlobTxs map[common.Address][]*txpool.LazyTransaction
)
tracing.Exec(ctx, "", "worker.SplittingTransactions", func(ctx context.Context, span trace.Span) {
prePendingTime := time.Now()
filter.OnlyPlainTxs, filter.OnlyBlobTxs = true, false
pendingPlainTxs := w.eth.TxPool().Pending(filter)
@ -1475,8 +1307,6 @@ func (w *worker) fillTransactions(ctx context.Context, interrupt *atomic.Int32,
localPlainTxs, remotePlainTxs = make(map[common.Address][]*txpool.LazyTransaction), pendingPlainTxs
localBlobTxs, remoteBlobTxs = make(map[common.Address][]*txpool.LazyTransaction), pendingBlobTxs
postPendingTime := time.Now()
for _, account := range w.eth.TxPool().Locals() {
if txs := remotePlainTxs[account]; len(txs) > 0 {
delete(remotePlainTxs, account)
@ -1488,83 +1318,34 @@ func (w *worker) fillTransactions(ctx context.Context, interrupt *atomic.Int32,
}
}
postLocalsTime := time.Now()
tracing.SetAttributes(
span,
attribute.Int("len of local txs", localPlainTxsCount),
attribute.Int("len of remote txs", remotePlainTxsCount),
attribute.String("time taken by Pending()", fmt.Sprintf("%v", postPendingTime.Sub(prePendingTime))),
attribute.String("time taken by Locals()", fmt.Sprintf("%v", postLocalsTime.Sub(postPendingTime))),
)
})
var (
localEnvTCount int
remoteEnvTCount int
err error
)
// Fill the block with all available pending transactions.
if len(localPlainTxs) > 0 || len(localBlobTxs) > 0 {
var plainTxs, blobTxs *transactionsByPriceAndNonce
tracing.Exec(ctx, "", "worker.LocalTransactionsByPriceAndNonce", func(ctx context.Context, span trace.Span) {
plainTxs = newTransactionsByPriceAndNonce(env.signer, localPlainTxs, env.header.BaseFee)
blobTxs = newTransactionsByPriceAndNonce(env.signer, localBlobTxs, env.header.BaseFee)
tracing.SetAttributes(
span,
attribute.Int("len of tx local Heads", plainTxs.GetTxs()),
)
})
tracing.Exec(ctx, "", "worker.LocalCommitTransactions", func(ctx context.Context, span trace.Span) {
err = w.commitTransactions(env, plainTxs, blobTxs, interrupt, new(uint256.Int), interruptCtx)
})
if err != nil {
if err := w.commitTransactions(env, plainTxs, blobTxs, interrupt, new(uint256.Int), interruptCtx); err != nil {
return err
}
localEnvTCount = env.tcount
}
if len(remotePlainTxs) > 0 || len(remoteBlobTxs) > 0 {
var plainTxs, blobTxs *transactionsByPriceAndNonce
tracing.Exec(ctx, "", "worker.RemoteTransactionsByPriceAndNonce", func(ctx context.Context, span trace.Span) {
plainTxs = newTransactionsByPriceAndNonce(env.signer, remotePlainTxs, env.header.BaseFee)
blobTxs = newTransactionsByPriceAndNonce(env.signer, remoteBlobTxs, env.header.BaseFee)
tracing.SetAttributes(
span,
attribute.Int("len of tx remote Heads", plainTxs.GetTxs()),
)
})
tracing.Exec(ctx, "", "worker.RemoteCommitTransactions", func(ctx context.Context, span trace.Span) {
err = w.commitTransactions(env, plainTxs, blobTxs, interrupt, new(uint256.Int), interruptCtx)
})
if err != nil {
if err := w.commitTransactions(env, plainTxs, blobTxs, interrupt, new(uint256.Int), interruptCtx); err != nil {
return err
}
remoteEnvTCount = env.tcount
}
tracing.SetAttributes(
span,
attribute.Int("len of final local txs ", localEnvTCount),
attribute.Int("len of final remote txs", remoteEnvTCount),
)
return nil
}
// generateWork generates a sealing block based on the given parameters.
func (w *worker) generateWork(ctx context.Context, params *generateParams) *newPayloadResult {
func (w *worker) generateWork(params *generateParams) *newPayloadResult {
work, err := w.prepareWork(params)
if err != nil {
return &newPayloadResult{err: err}
@ -1582,7 +1363,7 @@ func (w *worker) generateWork(ctx context.Context, params *generateParams) *newP
})
defer timer.Stop()
err := w.fillTransactions(ctx, interrupt, work, interruptCtx)
err := w.fillTransactions(interrupt, work, interruptCtx)
if errors.Is(err, errBlockInterruptedByTimeout) {
log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(w.newpayloadTimeout))
}
@ -1605,7 +1386,7 @@ func (w *worker) generateWork(ctx context.Context, params *generateParams) *newP
// commitWork generates several new sealing tasks based on the parent block
// and submit them to the sealer.
func (w *worker) commitWork(ctx context.Context, interrupt *atomic.Int32, noempty bool, timestamp int64) {
func (w *worker) commitWork(interrupt *atomic.Int32, noempty bool, timestamp int64) {
// Abort committing if node is still syncing
if w.syncing.Load() {
return
@ -1617,7 +1398,6 @@ func (w *worker) commitWork(ctx context.Context, interrupt *atomic.Int32, noempt
err error
)
tracing.Exec(ctx, "", "worker.prepareWork", func(ctx context.Context, span trace.Span) {
// Set the coinbase if the worker is running or it's required
var coinbase common.Address
if w.IsRunning() {
@ -1632,8 +1412,6 @@ func (w *worker) commitWork(ctx context.Context, interrupt *atomic.Int32, noempt
timestamp: uint64(timestamp),
coinbase: coinbase,
})
})
if err != nil {
return
}
@ -1648,26 +1426,18 @@ func (w *worker) commitWork(ctx context.Context, interrupt *atomic.Int32, noempt
if !noempty && w.interruptCommitFlag {
block := w.chain.GetBlockByHash(w.chain.CurrentBlock().Hash())
interruptCtx, stopFn = getInterruptTimer(ctx, work, block)
interruptCtx, stopFn = getInterruptTimer(work, block)
// nolint : staticcheck
interruptCtx = vm.PutCache(interruptCtx, w.interruptedTxCache)
}
ctx, span := tracing.StartSpan(ctx, "commitWork")
defer tracing.EndSpan(span)
tracing.SetAttributes(
span,
attribute.Int("number", int(work.header.Number.Uint64())),
)
// Create an empty block based on temporary copied state for
// sealing in advance without waiting block execution finished.
if !noempty && !w.noempty.Load() {
_ = w.commit(ctx, work.copy(), nil, false, start)
_ = w.commit(work.copy(), nil, false, start)
}
// Fill pending transactions from the txpool into the block.
err = w.fillTransactions(ctx, interrupt, work, interruptCtx)
err = w.fillTransactions(interrupt, work, interruptCtx)
switch {
case err == nil:
@ -1698,7 +1468,7 @@ func (w *worker) commitWork(ctx context.Context, interrupt *atomic.Int32, noempt
return
}
// Submit the generated block for consensus sealing.
_ = w.commit(ctx, work.copy(), w.fullTaskHook, true, start)
_ = w.commit(work.copy(), w.fullTaskHook, true, start)
// Swap out the old work with the new one, terminating any leftover
// prefetcher processes in the mean time and starting a new one.
@ -1709,7 +1479,7 @@ func (w *worker) commitWork(ctx context.Context, interrupt *atomic.Int32, noempt
w.current = work
}
func getInterruptTimer(ctx context.Context, work *environment, current *types.Block) (context.Context, func()) {
func getInterruptTimer(work *environment, current *types.Block) (context.Context, func()) {
delay := time.Until(time.Unix(int64(work.header.Time), 0))
interruptCtx, cancel := context.WithTimeout(context.Background(), delay)
@ -1717,14 +1487,11 @@ func getInterruptTimer(ctx context.Context, work *environment, current *types.Bl
blockNumber := current.NumberU64() + 1
go func() {
select {
case <-interruptCtx.Done():
<-interruptCtx.Done()
if interruptCtx.Err() != context.Canceled {
log.Info("Commit Interrupt. Pre-committing the current block", "block", blockNumber)
cancel()
}
case <-ctx.Done(): // nothing to do
}
}()
return interruptCtx, cancel
@ -1734,11 +1501,8 @@ func getInterruptTimer(ctx context.Context, work *environment, current *types.Bl
// and commits new work if consensus engine is running.
// Note the assumption is held that the mutation is allowed to the passed env, do
// the deep copy first.
func (w *worker) commit(ctx context.Context, env *environment, interval func(), update bool, start time.Time) error {
func (w *worker) commit(env *environment, interval func(), update bool, start time.Time) error {
if w.IsRunning() {
ctx, span := tracing.StartSpan(ctx, "commit")
defer tracing.EndSpan(span)
if interval != nil {
interval()
}
@ -1749,21 +1513,13 @@ func (w *worker) commit(ctx context.Context, env *environment, interval func(),
block, err := w.engine.FinalizeAndAssemble(w.chain, env.header, env.state, &types.Body{
Transactions: env.txs,
}, env.receipts)
tracing.SetAttributes(
span,
attribute.Int("number", int(env.header.Number.Uint64())),
attribute.String("hash", env.header.Hash().String()),
attribute.String("sealhash", w.engine.SealHash(env.header).String()),
attribute.Int("len of env.txs", len(env.txs)),
attribute.Bool("error", err != nil),
)
if err != nil {
return err
}
select {
case w.taskCh <- &task{ctx: ctx, receipts: env.receipts, state: env.state, block: block, createdAt: time.Now()}:
case w.taskCh <- &task{receipts: env.receipts, state: env.state, block: block, createdAt: time.Now()}:
fees := totalFees(block, env.receipts)
feesInEther := new(big.Float).Quo(new(big.Float).SetInt(fees), big.NewFloat(params.Ether))
log.Info("Commit new sealing work", "number", block.Number(), "sealhash", w.engine.SealHash(block.Header()),

View file

@ -3,7 +3,6 @@
package bor
import (
"context"
"crypto/ecdsa"
"encoding/hex"
"encoding/json"
@ -219,8 +218,6 @@ func buildNextBlock(t *testing.T, _bor consensus.Engine, chain *core.BlockChain,
b.addTxWithChain(chain, state, tx, addr)
}
ctx := context.Background()
// Finalize and seal the block
block, err := _bor.FinalizeAndAssemble(chain, b.header, state, &types.Body{
Transactions: b.txs,
@ -242,7 +239,7 @@ func buildNextBlock(t *testing.T, _bor consensus.Engine, chain *core.BlockChain,
res := make(chan *types.Block, 1)
err = _bor.Seal(ctx, chain, block, res, nil)
err = _bor.Seal(chain, block, res, nil)
if err != nil {
// an error case - sign manually
sign(t, header, signer, borConfig)