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 package beacon
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"math/big" "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 // Note, the method returns immediately and will send the result async. More
// than one result may also be returned depending on the consensus algorithm. // 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()) { 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, // The seal verification is done by the external consensus engine,
// return directly without pushing any block back. In another word // return directly without pushing any block back. In another word

View file

@ -17,13 +17,10 @@ import (
lru "github.com/hashicorp/golang-lru" lru "github.com/hashicorp/golang-lru"
"github.com/holiman/uint256" "github.com/holiman/uint256"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"golang.org/x/crypto/sha3" "golang.org/x/crypto/sha3"
"github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/tracing"
balance_tracing "github.com/ethereum/go-ethereum/core/tracing" balance_tracing "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/consensus" "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 // Finalize implements consensus.Engine, ensuring no uncles are set, nor block
// rewards given. // rewards given.
func (c *Bor) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body) { 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 ( var (
stateSyncData []*types.StateSyncData stateSyncData []*types.StateSyncData
err error err error
) )
headerNumber := header.Number.Uint64()
if body.Withdrawals != nil || header.WithdrawalsHash != nil {
return
}
if IsSprintStart(headerNumber, c.config.CalculateSprint(headerNumber)) { if IsSprintStart(headerNumber, c.config.CalculateSprint(headerNumber)) {
start := time.Now() start := time.Now()
ctx := context.Background()
cx := statefull.ChainContext{Chain: chain, Bor: c} cx := statefull.ChainContext{Chain: chain, Bor: c}
// check and commit span // 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) log.Error("Error while committing span", "error", err)
return return
} }
if c.HeimdallClient != nil { if c.HeimdallClient != nil {
// commit states // commit states
stateSyncData, err = c.CommitStates(ctx, state, header, cx) stateSyncData, err = c.CommitStates(state, header, cx)
if err != nil { if err != nil {
log.Error("Error while committing states", "error", err) log.Error("Error while committing states", "error", err)
return return
@ -908,38 +903,28 @@ func (c *Bor) changeContractCodeIfNeeded(headerNumber uint64, state *state.State
// FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set, // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set,
// nor block rewards given, and returns the final block. // 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) { 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() headerNumber := header.Number.Uint64()
if body.Withdrawals != nil || header.WithdrawalsHash != nil { if body.Withdrawals != nil || header.WithdrawalsHash != nil {
return nil, consensus.ErrUnexpectedWithdrawals return nil, consensus.ErrUnexpectedWithdrawals
} }
stateSyncData := []*types.StateSyncData{} var (
stateSyncData []*types.StateSyncData
var err error err error
)
if IsSprintStart(headerNumber, c.config.CalculateSprint(headerNumber)) { if IsSprintStart(headerNumber, c.config.CalculateSprint(headerNumber)) {
cx := statefull.ChainContext{Chain: chain, Bor: c} cx := statefull.ChainContext{Chain: chain, Bor: c}
tracing.Exec(finalizeCtx, "", "bor.checkAndCommitSpan", func(ctx context.Context, span trace.Span) { // check and commit span
// check and commit span if err = c.checkAndCommitSpan(state, header, cx); err != nil {
err = c.checkAndCommitSpan(finalizeCtx, state, header, cx)
})
if err != nil {
log.Error("Error while committing span", "error", err) log.Error("Error while committing span", "error", err)
return nil, err return nil, err
} }
if c.HeimdallClient != nil { if c.HeimdallClient != nil {
tracing.Exec(finalizeCtx, "", "bor.checkAndCommitSpan", func(ctx context.Context, span trace.Span) { // commit states
// commit states stateSyncData, err = c.CommitStates(state, header, cx)
stateSyncData, err = c.CommitStates(finalizeCtx, state, header, cx)
})
if err != nil { if err != nil {
log.Error("Error while committing states", "error", err) log.Error("Error while committing states", "error", err)
return nil, 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) { if err = c.changeContractCodeIfNeeded(headerNumber, state); err != nil {
err = c.changeContractCodeIfNeeded(headerNumber, state)
})
if err != nil {
log.Error("Error changing contract code", "error", err) log.Error("Error changing contract code", "error", err)
return nil, err return nil, err
} }
// No block rewards in PoA, so the state remains as it is // 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))
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
})
// Uncles are dropped // Uncles are dropped
header.UncleHash = types.CalcUncleHash(nil) header.UncleHash = types.CalcUncleHash(nil)
@ -971,14 +950,6 @@ func (c *Bor) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *typ
bc := chain.(core.BorStateSyncer) bc := chain.(core.BorStateSyncer)
bc.SetStateSync(stateSyncData) 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 the final block for sealing
return block, nil 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 // Seal implements consensus.Engine, attempting to create a sealed block using
// the local signing credentials. // 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 { func (c *Bor) Seal(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)
}
}()
header := block.Header() header := block.Header()
// Sealing the genesis block is not supported // Sealing the genesis block is not supported
number := header.Number.Uint64() 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. // 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)) 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 { select {
case <-stop: case <-stop:
log.Debug("Discarding sealing operation for block", "number", number) 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, "delay", delay,
"headerDifficulty", header.Difficulty, "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 { select {
case results <- block.WithSeal(header): case results <- block.WithSeal(header):
default: default:
log.Warn("Sealing result was not read by miner", "number", number, "sealhash", SealHash(header, c.config)) 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 return nil
} }
@ -1150,11 +1096,11 @@ func (c *Bor) Close() error {
} }
func (c *Bor) checkAndCommitSpan( func (c *Bor) checkAndCommitSpan(
ctx context.Context,
state *state.StateDB, state *state.StateDB,
header *types.Header, header *types.Header,
chain core.ChainContext, chain core.ChainContext,
) error { ) error {
var ctx = context.Background()
headerNumber := header.Number.Uint64() headerNumber := header.Number.Uint64()
span, err := c.spanner.GetCurrentSpan(ctx, header.ParentHash) span, err := c.spanner.GetCurrentSpan(ctx, header.ParentHash)
@ -1228,7 +1174,6 @@ func (c *Bor) FetchAndCommitSpan(
// CommitStates commit states // CommitStates commit states
func (c *Bor) CommitStates( func (c *Bor) CommitStates(
ctx context.Context,
state *state.StateDB, state *state.StateDB,
header *types.Header, header *types.Header,
chain statefull.ChainContext, chain statefull.ChainContext,
@ -1269,7 +1214,7 @@ func (c *Bor) CommitStates(
"fromID", from, "fromID", from,
"to", to.Format(time.RFC3339)) "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 { if err != nil {
log.Error("Error occurred when fetching state sync events", "fromID", from, "to", to.Unix(), "err", err) 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 ( import (
"bytes" "bytes"
"context"
"errors" "errors"
"fmt" "fmt"
"io" "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 // Seal implements consensus.Engine, attempting to create a sealed block using
// the local signing credentials. // 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() header := block.Header()
// Sealing the genesis block is not supported // Sealing the genesis block is not supported

View file

@ -18,7 +18,6 @@
package consensus package consensus
import ( import (
"context"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "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 // Note, the method returns immediately and will send the result async. More
// than one result may also be returned depending on the consensus algorithm. // 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 returns the hash of a block prior to it being sealed.
SealHash(header *types.Header) common.Hash SealHash(header *types.Header) common.Hash

View file

@ -18,7 +18,6 @@
package ethash package ethash
import ( import (
"context"
"time" "time"
"github.com/ethereum/go-ethereum/consensus" "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 // 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 // the result into the given channel. For the ethash engine, this method will
// just panic as sealing is not supported anymore. // 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") 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, // WriteBlockAndSetHead writes the given block and all associated state to the database,
// and applies the block as the new chain head. // 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() { if !bc.chainmu.TryLock() {
return NonStatTy, errChainStopped return NonStatTy, errChainStopped
} }
defer bc.chainmu.Unlock() 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. // writeBlockAndSetHead is the internal implementation of WriteBlockAndSetHead.
// This function expects the chain mutex to be held. // 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) stateSyncLogs, err := bc.writeBlockWithState(block, receipts, logs, state)
if err != nil { if err != nil {
return NonStatTy, err 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 // Don't set the head, only insert the block
_, err = bc.writeBlockWithState(block, receipts, logs, statedb) _, err = bc.writeBlockWithState(block, receipts, logs, statedb)
} else { } else {
status, err = bc.writeBlockAndSetHead(context.Background(), block, receipts, logs, statedb, false) status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false)
} }
followupInterrupt.Store(true) 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 // Don't set the head, only insert the block
_, err = bc.writeBlockWithState(block, receipts, logs, statedb) _, err = bc.writeBlockWithState(block, receipts, logs, statedb)
} else { } else {
status, err = bc.writeBlockAndSetHead(context.Background(), block, receipts, logs, statedb, false) status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false)
} }
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -3,8 +3,6 @@ package miner
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"os"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
@ -12,9 +10,8 @@ import (
// nolint:typecheck // nolint:typecheck
"github.com/ethereum/go-ethereum/common" "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"
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/blockstm" "github.com/ethereum/go-ethereum/core/blockstm"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
@ -27,10 +24,6 @@ import (
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/holiman/uint256" "github.com/holiman/uint256"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
lru "github.com/hashicorp/golang-lru" lru "github.com/hashicorp/golang-lru"
) )
@ -102,12 +95,10 @@ func newWorkerWithDelay(config *Config, chainConfig *params.ChainConfig, engine
worker.newpayloadTimeout = newpayloadTimeout worker.newpayloadTimeout = newpayloadTimeout
ctx := tracing.WithTracer(context.Background(), otel.GetTracerProvider().Tracer("MinerWorker"))
worker.wg.Add(4) worker.wg.Add(4)
go worker.mainLoopWithDelay(ctx, delay, opcodeDelay) go worker.mainLoopWithDelay(delay, opcodeDelay)
go worker.newWorkLoop(ctx, recommit) go worker.newWorkLoop(recommit)
go worker.resultLoop() go worker.resultLoop()
go worker.taskLoop() 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. // mainLoopWithDelay is mainLoop() with extra params to induce artficial delays for tests such as commit-interrupt.
// nolint:gocognit // 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.wg.Done()
defer w.txsSub.Unsubscribe() defer w.txsSub.Unsubscribe()
defer w.chainHeadSub.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.chainConfig.ChainID.Cmp(params.BorMainnetChainConfig.ChainID) == 0 || w.chainConfig.ChainID.Cmp(params.MumbaiChainConfig.ChainID) == 0 {
if w.eth.PeerCount() > 0 { if w.eth.PeerCount() > 0 {
//nolint:contextcheck //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 { } else {
//nolint:contextcheck //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: case req := <-w.getWorkCh:
req.result <- w.generateWork(ctx, req.params) req.result <- w.generateWork(req.params)
case ev := <-w.txsCh: case ev := <-w.txsCh:
// Apply transactions to the pending state if we're not sealing // 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 // submit sealing work here since all empty submission will be rejected
// by clique. Of course the advance sealing(empty submission) is disabled. // by clique. Of course the advance sealing(empty submission) is disabled.
if w.chainConfig.Clique != nil && w.chainConfig.Clique.Period == 0 { 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. // 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 // Abort committing if node is still syncing
if w.syncing.Load() { if w.syncing.Load() {
return return
@ -217,23 +208,20 @@ func (w *worker) commitWorkWithDelay(ctx context.Context, interrupt *atomic.Int3
err error 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
// Set the coinbase if the worker is running or it's required var coinbase common.Address
var coinbase common.Address if w.IsRunning() {
if w.IsRunning() { coinbase = w.etherbase()
coinbase = w.etherbase() if coinbase == (common.Address{}) {
if coinbase == (common.Address{}) { log.Error("Refusing to mine without etherbase")
log.Error("Refusing to mine without etherbase") return
return
}
} }
}
work, err = w.prepareWork(&generateParams{ work, err = w.prepareWork(&generateParams{
timestamp: uint64(timestamp), timestamp: uint64(timestamp),
coinbase: coinbase, coinbase: coinbase,
})
}) })
if err != nil { if err != nil {
return return
} }
@ -248,7 +236,7 @@ func (w *worker) commitWorkWithDelay(ctx context.Context, interrupt *atomic.Int3
if !noempty && w.interruptCommitFlag { if !noempty && w.interruptCommitFlag {
block := w.chain.GetBlockByHash(w.chain.CurrentBlock().Hash()) block := w.chain.GetBlockByHash(w.chain.CurrentBlock().Hash())
interruptCtx, stopFn = getInterruptTimer(ctx, work, block) interruptCtx, stopFn = getInterruptTimer(work, block)
// nolint : staticcheck // nolint : staticcheck
interruptCtx = vm.PutCache(interruptCtx, w.interruptedTxCache) interruptCtx = vm.PutCache(interruptCtx, w.interruptedTxCache)
// nolint : staticcheck // nolint : staticcheck
@ -257,21 +245,13 @@ func (w *worker) commitWorkWithDelay(ctx context.Context, interrupt *atomic.Int3
interruptCtx = context.WithValue(interruptCtx, vm.InterruptCtxOpcodeDelayKey, opcodeDelay) 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 // Create an empty block based on temporary copied state for
// sealing in advance without waiting block execution finished. // sealing in advance without waiting block execution finished.
if !noempty && !w.noempty.Load() { 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. // Fill pending transactions from the txpool into the block.
err = w.fillTransactionsWithDelay(ctx, interrupt, work, interruptCtx) err = w.fillTransactionsWithDelay(interrupt, work, interruptCtx)
switch { switch {
case err == nil: case err == nil:
@ -302,7 +282,7 @@ func (w *worker) commitWorkWithDelay(ctx context.Context, interrupt *atomic.Int3
return return
} }
// Submit the generated block for consensus sealing. // 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 // Swap out the old work with the new one, terminating any leftover
// prefetcher processes in the mean time and starting a new one. // 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. // fillTransactionsWithDelay is fillTransactions() with extra params to induce artficial delays for tests such as commit-interrupt.
// nolint:gocognit // nolint:gocognit
func (w *worker) fillTransactionsWithDelay(ctx context.Context, interrupt *atomic.Int32, env *environment, interruptCtx context.Context) error { func (w *worker) fillTransactionsWithDelay(interrupt *atomic.Int32, env *environment, interruptCtx context.Context) error {
ctx, span := tracing.StartSpan(ctx, "fillTransactions") w.mu.RLock()
defer tracing.EndSpan(span) tip := w.tip
w.mu.RUnlock()
// 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 (
localPlainTxs, remotePlainTxs, localBlobTxs, remoteBlobTxs map[common.Address][]*txpool.LazyTransaction
)
filter.OnlyPlainTxs, filter.OnlyBlobTxs = true, false
pendingPlainTxs := w.eth.TxPool().Pending(filter)
filter.OnlyPlainTxs, filter.OnlyBlobTxs = false, true
pendingBlobTxs := w.eth.TxPool().Pending(filter)
// 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 := remotePlainTxs[account]; len(txs) > 0 {
delete(remotePlainTxs, account)
localPlainTxs[account] = txs
}
if txs := remoteBlobTxs[account]; len(txs) > 0 {
delete(remoteBlobTxs, account)
localBlobTxs[account] = txs
}
}
// Split the pending transactions into locals and remotes
// Fill the block with all available pending transactions. // Fill the block with all available pending transactions.
pending := w.eth.TxPool().Pending(txpool.PendingFilter{}) if len(localPlainTxs) > 0 || len(localBlobTxs) > 0 {
localTxs, remoteTxs := make(map[common.Address][]*txpool.LazyTransaction), pending var plainTxs, blobTxs *transactionsByPriceAndNonce
var ( plainTxs = newTransactionsByPriceAndNonce(env.signer, localPlainTxs, env.header.BaseFee)
localTxsCount int blobTxs = newTransactionsByPriceAndNonce(env.signer, localBlobTxs, env.header.BaseFee)
remoteTxsCount int
)
// TODO: move to config or RPC if err := w.commitTransactionsWithDelay(env, plainTxs, blobTxs, interrupt, new(uint256.Int), interruptCtx); err != nil {
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())
}
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()
for _, account := range w.eth.TxPool().Locals() {
if txs := remoteTxs[account]; len(txs) > 0 {
delete(remoteTxs, account)
localTxs[account] = txs
}
}
postLocalsTime := time.Now()
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))),
)
})
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 {
return err return err
} }
localEnvTCount = env.tcount
} }
if len(remoteTxs) > 0 { if len(remotePlainTxs) > 0 || len(remoteBlobTxs) > 0 {
var txs *transactionsByPriceAndNonce var plainTxs, blobTxs *transactionsByPriceAndNonce
tracing.Exec(ctx, "", "worker.RemoteTransactionsByPriceAndNonce", func(ctx context.Context, span trace.Span) { plainTxs = newTransactionsByPriceAndNonce(env.signer, remotePlainTxs, env.header.BaseFee)
var baseFee *uint256.Int blobTxs = newTransactionsByPriceAndNonce(env.signer, remoteBlobTxs, env.header.BaseFee)
if env.header.BaseFee != nil {
baseFee = cmath.FromBig(env.header.BaseFee)
}
txs = newTransactionsByPriceAndNonce(env.signer, remoteTxs, baseFee.ToBig()) if err := w.commitTransactionsWithDelay(env, plainTxs, blobTxs, interrupt, new(uint256.Int), interruptCtx); err != nil {
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 {
return err 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 return nil
} }
// commitTransactionsWithDelay is commitTransactions() with extra params to induce artficial delays for tests such as commit-interrupt. // commitTransactionsWithDelay is commitTransactions() with extra params to induce artficial delays for tests such as commit-interrupt.
// nolint:gocognit, unparam // 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 gasLimit := env.header.GasLimit
if env.gasPool == nil { if env.gasPool == nil {
env.gasPool = new(core.GasPool).AddGas(gasLimit) env.gasPool = new(core.GasPool).AddGas(gasLimit)
@ -498,35 +374,25 @@ func (w *worker) commitTransactionsWithDelay(env *environment, txs *transactions
var coalescedLogs []*types.Log 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 var deps map[int]map[int]bool
chDeps := make(chan blockstm.TxDep) chDeps := make(chan blockstm.TxDep)
var count int
var depsWg sync.WaitGroup var depsWg sync.WaitGroup
var once sync.Once
EnableMVHashMap := w.chainConfig.IsCancun(env.header.Number) EnableMVHashMap := w.chainConfig.IsCancun(env.header.Number)
// create and add empty mvHashMap in statedb // create and add empty mvHashMap in statedb
if EnableMVHashMap { if EnableMVHashMap && w.IsRunning() {
depsMVReadList = [][]blockstm.ReadDescriptor{}
depsMVFullWriteList = [][]blockstm.WriteDescriptor{}
mvReadMapList = []map[blockstm.Key]blockstm.ReadDescriptor{}
deps = map[int]map[int]bool{} deps = map[int]map[int]bool{}
chDeps = make(chan blockstm.TxDep) 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) depsWg.Add(1)
@ -543,8 +409,15 @@ func (w *worker) commitTransactionsWithDelay(env *environment, txs *transactions
mainloop: mainloop:
for { 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 interruptCtx != nil {
if EnableMVHashMap { if EnableMVHashMap && w.IsRunning() {
env.state.AddEmptyMVHashMap() 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 we don't have enough gas for any further transactions then we're done.
if env.gasPool.Gas() < params.TxGas { if env.gasPool.Gas() < params.TxGas {
log.Trace("Not enough gas for further transactions", "have", env.gasPool, "want", params.TxGas) log.Trace("Not enough gas for further transactions", "have", env.gasPool, "want", params.TxGas)
break 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. // 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 { if ltx == nil {
break break
} }
@ -586,6 +479,11 @@ mainloop:
txs.Pop() txs.Pop()
continue 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 // Transaction seems to fit, pull it up from the pool
tx := ltx.Resolve() tx := ltx.Resolve()
if tx == nil { if tx == nil {
@ -594,7 +492,7 @@ mainloop:
continue continue
} }
// Error may be ignored here. The error has already been checked // 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) from, _ := types.Sender(env.signer, tx)
// not prioritising conditional transaction, yet. // not prioritising conditional transaction, yet.
@ -652,19 +550,21 @@ mainloop:
coalescedLogs = append(coalescedLogs, logs...) coalescedLogs = append(coalescedLogs, logs...)
env.tcount++ env.tcount++
if EnableMVHashMap { if EnableMVHashMap && w.IsRunning() {
depsMVReadList = append(depsMVReadList, env.state.MVReadList()) env.depsMVFullWriteList = append(env.depsMVFullWriteList, env.state.MVFullWriteList())
depsMVFullWriteList = append(depsMVFullWriteList, env.state.MVFullWriteList()) env.mvReadMapList = append(env.mvReadMapList, env.state.MVReadMap())
mvReadMapList = append(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{ temp := blockstm.TxDep{
Index: env.tcount - 1, Index: env.tcount - 1,
ReadList: depsMVReadList[count], ReadList: env.state.MVReadList(),
FullWriteList: depsMVFullWriteList, FullWriteList: env.depsMVFullWriteList,
} }
chDeps <- temp chDeps <- temp
count++
} }
txs.Shift() txs.Shift()
@ -675,7 +575,7 @@ mainloop:
txs.Pop() txs.Pop()
} }
if EnableMVHashMap { if EnableMVHashMap && w.IsRunning() {
env.state.ClearReadMap() env.state.ClearReadMap()
env.state.ClearWriteMap() env.state.ClearWriteMap()
} }
@ -683,7 +583,9 @@ mainloop:
// nolint:nestif // nolint:nestif
if EnableMVHashMap && w.IsRunning() { if EnableMVHashMap && w.IsRunning() {
close(chDeps) once.Do(func() {
close(chDeps)
})
depsWg.Wait() depsWg.Wait()
var blockExtraData types.BlockExtraData var blockExtraData types.BlockExtraData
@ -691,8 +593,8 @@ mainloop:
tempVanity := env.header.Extra[:types.ExtraVanityLength] tempVanity := env.header.Extra[:types.ExtraVanityLength]
tempSeal := env.header.Extra[len(env.header.Extra)-types.ExtraSealLength:] tempSeal := env.header.Extra[len(env.header.Extra)-types.ExtraSealLength:]
if len(mvReadMapList) > 0 { if len(env.mvReadMapList) > 0 {
tempDeps := make([][]uint64, len(mvReadMapList)) tempDeps := make([][]uint64, len(env.mvReadMapList))
for j := range deps[0] { for j := range deps[0] {
tempDeps[0] = append(tempDeps[0], uint64(j)) tempDeps[0] = append(tempDeps[0], uint64(j))
@ -700,14 +602,15 @@ mainloop:
delayFlag := true delayFlag := true
for i := 1; i <= len(mvReadMapList)-1; i++ { for i := 1; i <= len(env.mvReadMapList)-1; i++ {
reads := mvReadMapList[i-1] reads := env.mvReadMapList[i-1]
_, ok1 := reads[blockstm.NewSubpathKey(env.coinbase, state.BalancePath)] _, ok1 := reads[blockstm.NewSubpathKey(env.coinbase, state.BalancePath)]
_, ok2 := reads[blockstm.NewSubpathKey(common.HexToAddress(w.chainConfig.Bor.CalculateBurntContract(env.header.Number.Uint64())), state.BalancePath)] _, ok2 := reads[blockstm.NewSubpathKey(common.HexToAddress(w.chainConfig.Bor.CalculateBurntContract(env.header.Number.Uint64())), state.BalancePath)]
if ok1 || ok2 { if ok1 || ok2 {
delayFlag = false delayFlag = false
break
} }
for j := range deps[i] { for j := range deps[i] {

View file

@ -17,15 +17,10 @@
package miner package miner
import ( import (
"bytes"
"context" "context"
"errors" "errors"
"fmt" "fmt"
"math/big" "math/big"
"os"
"runtime"
"runtime/pprof"
ptrace "runtime/trace"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
@ -33,8 +28,6 @@ import (
lru "github.com/hashicorp/golang-lru" lru "github.com/hashicorp/golang-lru"
"github.com/holiman/uint256" "github.com/holiman/uint256"
"go.opentelemetry.io/otel" "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"
"github.com/ethereum/go-ethereum/common/tracing" "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. // task contains all information for consensus engine sealing and result submitting.
type task struct { type task struct {
//nolint:containedctx
ctx context.Context
receipts []*types.Receipt receipts []*types.Receipt
state *state.StateDB state *state.StateDB
block *types.Block block *types.Block
@ -172,8 +163,6 @@ const (
// newWorkReq represents a request for new sealing work submitting with relative interrupt notifier. // newWorkReq represents a request for new sealing work submitting with relative interrupt notifier.
type newWorkReq struct { type newWorkReq struct {
//nolint:containedctx
ctx context.Context
interrupt *atomic.Int32 interrupt *atomic.Int32
noempty bool noempty bool
timestamp int64 timestamp int64
@ -352,12 +341,10 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus
worker.newpayloadTimeout = newpayloadTimeout worker.newpayloadTimeout = newpayloadTimeout
ctx := tracing.WithTracer(context.Background(), otel.GetTracerProvider().Tracer("MinerWorker"))
worker.wg.Add(4) worker.wg.Add(4)
go worker.mainLoop(ctx) go worker.mainLoop()
go worker.newWorkLoop(ctx, recommit) go worker.newWorkLoop(recommit)
go worker.resultLoop() go worker.resultLoop()
go worker.taskLoop() 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. // newWorkLoop is a standalone goroutine to submit new sealing work upon received events.
// //
//nolint:gocognit //nolint:gocognit
func (w *worker) newWorkLoop(ctx context.Context, recommit time.Duration) { func (w *worker) newWorkLoop(recommit time.Duration) {
defer w.wg.Done() defer w.wg.Done()
var ( 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 aborts in-flight transaction execution with given signal and resubmits a new one.
commit := func(noempty bool, s int32) { commit := func(noempty bool, s int32) {
ctx, span := tracing.Trace(ctx, "worker.newWorkLoop.commit")
tracing.EndSpan(span)
if interrupt != nil { if interrupt != nil {
interrupt.Store(s) interrupt.Store(s)
} }
interrupt = new(atomic.Int32) interrupt = new(atomic.Int32)
select { 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: case <-w.exitCh:
return return
} }
@ -515,9 +500,6 @@ func (w *worker) newWorkLoop(ctx context.Context, recommit time.Duration) {
} }
// clearPending cleans the stale pending tasks. // clearPending cleans the stale pending tasks.
clearPending := func(number uint64) { clearPending := func(number uint64) {
_, span := tracing.Trace(ctx, "worker.newWorkLoop.clearPending")
tracing.EndSpan(span)
w.pendingMu.Lock() w.pendingMu.Lock()
for h, t := range w.pendingTasks { for h, t := range w.pendingTasks {
if t.block.NumberU64()+staleThreshold <= number { 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 // the received event. It can support two modes: automatically generate task and
// submit it or return task according to given parameters for various proposes. // submit it or return task according to given parameters for various proposes.
// nolint: gocognit, contextcheck // nolint: gocognit, contextcheck
func (w *worker) mainLoop(ctx context.Context) { func (w *worker) mainLoop() {
defer w.wg.Done() defer w.wg.Done()
defer w.txsSub.Unsubscribe() defer w.txsSub.Unsubscribe()
defer w.chainHeadSub.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.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 { if w.eth.PeerCount() > 0 {
//nolint:contextcheck //nolint:contextcheck
w.commitWork(req.ctx, req.interrupt, req.noempty, req.timestamp) w.commitWork(req.interrupt, req.noempty, req.timestamp)
} }
} else { } else {
//nolint:contextcheck //nolint:contextcheck
w.commitWork(req.ctx, req.interrupt, req.noempty, req.timestamp) w.commitWork(req.interrupt, req.noempty, req.timestamp)
} }
case req := <-w.getWorkCh: case req := <-w.getWorkCh:
req.result <- w.generateWork(ctx, req.params) req.result <- w.generateWork(req.params)
case ev := <-w.txsCh: case ev := <-w.txsCh:
// Apply transactions to the pending state if we're not sealing // 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 // submit sealing work here since all empty submission will be rejected
// by clique. Of course the advance sealing(empty submission) is disabled. // by clique. Of course the advance sealing(empty submission) is disabled.
if w.chainConfig.Clique != nil && w.chainConfig.Clique.Period == 0 { 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.pendingTasks[sealHash] = task
w.pendingMu.Unlock() 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) log.Warn("Block sealing failed", "err", err)
w.pendingMu.Lock() w.pendingMu.Lock()
delete(w.pendingTasks, sealHash) delete(w.pendingTasks, sealHash)
@ -783,45 +765,31 @@ func (w *worker) resultLoop() {
err error err error
) )
tracing.Exec(task.ctx, "", "resultLoop", func(ctx context.Context, span trace.Span) { for i, taskReceipt := range task.receipts {
for i, taskReceipt := range task.receipts { receipt := new(types.Receipt)
receipt := new(types.Receipt) receipts[i] = receipt
receipts[i] = receipt *receipt = *taskReceipt
*receipt = *taskReceipt
// add block location fields // add block location fields
receipt.BlockHash = hash receipt.BlockHash = hash
receipt.BlockNumber = block.Number() receipt.BlockNumber = block.Number()
receipt.TransactionIndex = uint(i) receipt.TransactionIndex = uint(i)
// Update the block hash in all logs since it is now available and not when the // Update the block hash in all logs since it is now available and not when the
// receipt/log of individual transactions were created. // receipt/log of individual transactions were created.
receipt.Logs = make([]*types.Log, len(taskReceipt.Logs)) receipt.Logs = make([]*types.Log, len(taskReceipt.Logs))
for i, taskLog := range taskReceipt.Logs { for i, taskLog := range taskReceipt.Logs {
log := new(types.Log) log := new(types.Log)
receipt.Logs[i] = log receipt.Logs[i] = log
*log = *taskLog *log = *taskLog
log.BlockHash = hash log.BlockHash = hash
}
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( logs = append(logs, receipt.Logs...)
span, }
attribute.String("hash", hash.String()), // Commit block and state to database.
attribute.Int("number", int(block.Number().Uint64())), _, err = w.chain.WriteBlockAndSetHead(block, receipts, logs, task.state, true)
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),
)
})
if err != nil { if err != nil {
log.Error("Failed writing block to chain", "err", err) log.Error("Failed writing block to chain", "err", err)
@ -1301,80 +1269,13 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
return env, nil 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 // fillTransactions retrieves the pending transactions from the txpool and fills them
// into the given sealing block. The transaction selection and ordering strategy can // into the given sealing block. The transaction selection and ordering strategy can
// be customized with the plugin in the future. // be customized with the plugin in the future.
// //
//nolint:gocognit //nolint:gocognit
func (w *worker) fillTransactions(ctx context.Context, interrupt *atomic.Int32, env *environment, interruptCtx context.Context) error { func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment, interruptCtx context.Context) error {
ctx, span := tracing.StartSpan(ctx, "fillTransactions")
defer tracing.EndSpan(span)
w.mu.RLock() w.mu.RLock()
tip := w.tip tip := w.tip
w.mu.RUnlock() w.mu.RUnlock()
@ -1392,179 +1293,59 @@ func (w *worker) fillTransactions(ctx context.Context, interrupt *atomic.Int32,
filter.BlobFee = uint256.MustFromBig(eip4844.CalcBlobFee(*env.header.ExcessBlobGas)) 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 ( var (
localPlainTxs, remotePlainTxs, localBlobTxs, remoteBlobTxs map[common.Address][]*txpool.LazyTransaction localPlainTxs, remotePlainTxs, localBlobTxs, remoteBlobTxs map[common.Address][]*txpool.LazyTransaction
) )
tracing.Exec(ctx, "", "worker.SplittingTransactions", func(ctx context.Context, span trace.Span) { filter.OnlyPlainTxs, filter.OnlyBlobTxs = true, false
prePendingTime := time.Now() pendingPlainTxs := w.eth.TxPool().Pending(filter)
filter.OnlyPlainTxs, filter.OnlyBlobTxs = true, false filter.OnlyPlainTxs, filter.OnlyBlobTxs = false, true
pendingPlainTxs := w.eth.TxPool().Pending(filter) pendingBlobTxs := w.eth.TxPool().Pending(filter)
filter.OnlyPlainTxs, filter.OnlyBlobTxs = false, true // Split the pending transactions into locals and remotes.
pendingBlobTxs := w.eth.TxPool().Pending(filter) localPlainTxs, remotePlainTxs = make(map[common.Address][]*txpool.LazyTransaction), pendingPlainTxs
localBlobTxs, remoteBlobTxs = make(map[common.Address][]*txpool.LazyTransaction), pendingBlobTxs
// Split the pending transactions into locals and remotes. for _, account := range w.eth.TxPool().Locals() {
localPlainTxs, remotePlainTxs = make(map[common.Address][]*txpool.LazyTransaction), pendingPlainTxs if txs := remotePlainTxs[account]; len(txs) > 0 {
localBlobTxs, remoteBlobTxs = make(map[common.Address][]*txpool.LazyTransaction), pendingBlobTxs delete(remotePlainTxs, account)
localPlainTxs[account] = txs
postPendingTime := time.Now()
for _, account := range w.eth.TxPool().Locals() {
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
}
} }
if txs := remoteBlobTxs[account]; len(txs) > 0 {
postLocalsTime := time.Now() delete(remoteBlobTxs, account)
localBlobTxs[account] = txs
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. // Fill the block with all available pending transactions.
if len(localPlainTxs) > 0 || len(localBlobTxs) > 0 { if len(localPlainTxs) > 0 || len(localBlobTxs) > 0 {
var plainTxs, blobTxs *transactionsByPriceAndNonce var plainTxs, blobTxs *transactionsByPriceAndNonce
tracing.Exec(ctx, "", "worker.LocalTransactionsByPriceAndNonce", func(ctx context.Context, span trace.Span) { plainTxs = newTransactionsByPriceAndNonce(env.signer, localPlainTxs, env.header.BaseFee)
plainTxs = newTransactionsByPriceAndNonce(env.signer, localPlainTxs, env.header.BaseFee) blobTxs = newTransactionsByPriceAndNonce(env.signer, localBlobTxs, env.header.BaseFee)
blobTxs = newTransactionsByPriceAndNonce(env.signer, localBlobTxs, env.header.BaseFee)
tracing.SetAttributes( if err := w.commitTransactions(env, plainTxs, blobTxs, interrupt, new(uint256.Int), interruptCtx); err != nil {
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 {
return err return err
} }
localEnvTCount = env.tcount
} }
if len(remotePlainTxs) > 0 || len(remoteBlobTxs) > 0 { if len(remotePlainTxs) > 0 || len(remoteBlobTxs) > 0 {
var plainTxs, blobTxs *transactionsByPriceAndNonce var plainTxs, blobTxs *transactionsByPriceAndNonce
tracing.Exec(ctx, "", "worker.RemoteTransactionsByPriceAndNonce", func(ctx context.Context, span trace.Span) { plainTxs = newTransactionsByPriceAndNonce(env.signer, remotePlainTxs, env.header.BaseFee)
plainTxs = newTransactionsByPriceAndNonce(env.signer, remotePlainTxs, env.header.BaseFee) blobTxs = newTransactionsByPriceAndNonce(env.signer, remoteBlobTxs, env.header.BaseFee)
blobTxs = newTransactionsByPriceAndNonce(env.signer, remoteBlobTxs, env.header.BaseFee)
tracing.SetAttributes( if err := w.commitTransactions(env, plainTxs, blobTxs, interrupt, new(uint256.Int), interruptCtx); err != nil {
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 {
return err 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 return nil
} }
// generateWork generates a sealing block based on the given parameters. // 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) work, err := w.prepareWork(params)
if err != nil { if err != nil {
return &newPayloadResult{err: err} return &newPayloadResult{err: err}
@ -1582,7 +1363,7 @@ func (w *worker) generateWork(ctx context.Context, params *generateParams) *newP
}) })
defer timer.Stop() defer timer.Stop()
err := w.fillTransactions(ctx, interrupt, work, interruptCtx) err := w.fillTransactions(interrupt, work, interruptCtx)
if errors.Is(err, errBlockInterruptedByTimeout) { if errors.Is(err, errBlockInterruptedByTimeout) {
log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(w.newpayloadTimeout)) 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 // commitWork generates several new sealing tasks based on the parent block
// and submit them to the sealer. // 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 // Abort committing if node is still syncing
if w.syncing.Load() { if w.syncing.Load() {
return return
@ -1617,23 +1398,20 @@ func (w *worker) commitWork(ctx context.Context, interrupt *atomic.Int32, noempt
err error 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
// Set the coinbase if the worker is running or it's required var coinbase common.Address
var coinbase common.Address if w.IsRunning() {
if w.IsRunning() { coinbase = w.etherbase()
coinbase = w.etherbase() if coinbase == (common.Address{}) {
if coinbase == (common.Address{}) { log.Error("Refusing to mine without etherbase")
log.Error("Refusing to mine without etherbase") return
return
}
} }
}
work, err = w.prepareWork(&generateParams{ work, err = w.prepareWork(&generateParams{
timestamp: uint64(timestamp), timestamp: uint64(timestamp),
coinbase: coinbase, coinbase: coinbase,
})
}) })
if err != nil { if err != nil {
return return
} }
@ -1648,26 +1426,18 @@ func (w *worker) commitWork(ctx context.Context, interrupt *atomic.Int32, noempt
if !noempty && w.interruptCommitFlag { if !noempty && w.interruptCommitFlag {
block := w.chain.GetBlockByHash(w.chain.CurrentBlock().Hash()) block := w.chain.GetBlockByHash(w.chain.CurrentBlock().Hash())
interruptCtx, stopFn = getInterruptTimer(ctx, work, block) interruptCtx, stopFn = getInterruptTimer(work, block)
// nolint : staticcheck // nolint : staticcheck
interruptCtx = vm.PutCache(interruptCtx, w.interruptedTxCache) 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 // Create an empty block based on temporary copied state for
// sealing in advance without waiting block execution finished. // sealing in advance without waiting block execution finished.
if !noempty && !w.noempty.Load() { 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. // Fill pending transactions from the txpool into the block.
err = w.fillTransactions(ctx, interrupt, work, interruptCtx) err = w.fillTransactions(interrupt, work, interruptCtx)
switch { switch {
case err == nil: case err == nil:
@ -1698,7 +1468,7 @@ func (w *worker) commitWork(ctx context.Context, interrupt *atomic.Int32, noempt
return return
} }
// Submit the generated block for consensus sealing. // 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 // Swap out the old work with the new one, terminating any leftover
// prefetcher processes in the mean time and starting a new one. // 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 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)) delay := time.Until(time.Unix(int64(work.header.Time), 0))
interruptCtx, cancel := context.WithTimeout(context.Background(), delay) interruptCtx, cancel := context.WithTimeout(context.Background(), delay)
@ -1717,13 +1487,10 @@ func getInterruptTimer(ctx context.Context, work *environment, current *types.Bl
blockNumber := current.NumberU64() + 1 blockNumber := current.NumberU64() + 1
go func() { go func() {
select { <-interruptCtx.Done()
case <-interruptCtx.Done(): if interruptCtx.Err() != context.Canceled {
if interruptCtx.Err() != context.Canceled { log.Info("Commit Interrupt. Pre-committing the current block", "block", blockNumber)
log.Info("Commit Interrupt. Pre-committing the current block", "block", blockNumber) cancel()
cancel()
}
case <-ctx.Done(): // nothing to do
} }
}() }()
@ -1734,11 +1501,8 @@ func getInterruptTimer(ctx context.Context, work *environment, current *types.Bl
// and commits new work if consensus engine is running. // and commits new work if consensus engine is running.
// Note the assumption is held that the mutation is allowed to the passed env, do // Note the assumption is held that the mutation is allowed to the passed env, do
// the deep copy first. // 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() { if w.IsRunning() {
ctx, span := tracing.StartSpan(ctx, "commit")
defer tracing.EndSpan(span)
if interval != nil { if interval != nil {
interval() 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{ block, err := w.engine.FinalizeAndAssemble(w.chain, env.header, env.state, &types.Body{
Transactions: env.txs, Transactions: env.txs,
}, env.receipts) }, 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 { if err != nil {
return err return err
} }
select { 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) fees := totalFees(block, env.receipts)
feesInEther := new(big.Float).Quo(new(big.Float).SetInt(fees), big.NewFloat(params.Ether)) 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()), log.Info("Commit new sealing work", "number", block.Number(), "sealhash", w.engine.SealHash(block.Header()),

View file

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