mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 10:50:44 +00:00
miner: add OpenTelemetry tracing spans to block building
Add tracing instrumentation to the payload building pipeline so operators can identify where time is spent during block construction. This adds four spans: - miner.buildPayload (root span per build iteration) - miner.prepareWork (header + state setup) - miner.fillTransactions (transaction selection + execution) - miner.finalizeAndAssemble (block finalization) The root span is created via StartRootSpan since the background build goroutine has no parent RPC context. Context is threaded through generateWork → prepareWork/fillTransactions to enable child spans. This complements the existing RPC-level tracing (jsonrpc.engine/getPayloadV* server spans with rpc.encodeJSONResponse children) by providing visibility into the block building phase itself. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d318e8eba9
commit
42fe582e44
4 changed files with 39 additions and 9 deletions
|
|
@ -88,6 +88,13 @@ func StartServerSpan(ctx context.Context, tracer trace.Tracer, rpc RPCInfo, othe
|
|||
return ctx, end
|
||||
}
|
||||
|
||||
// StartRootSpan creates a SpanKind=INTERNAL root span that does not require
|
||||
// a parent span in the context. Use this for background operations that are
|
||||
// not triggered by an incoming RPC request.
|
||||
func StartRootSpan(spanName string, attributes ...Attribute) (context.Context, trace.Span, func(*error)) {
|
||||
return startSpan(context.Background(), otel.Tracer(""), trace.SpanKindInternal, spanName, attributes...)
|
||||
}
|
||||
|
||||
// startSpan creates a span with the given kind.
|
||||
func startSpan(ctx context.Context, tracer trace.Tracer, kind trace.SpanKind, spanName string, attributes ...Attribute) (context.Context, trace.Span, func(*error)) {
|
||||
ctx, span := tracer.Start(ctx, spanName, trace.WithSpanKind(kind))
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
package miner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sync"
|
||||
|
|
@ -156,7 +157,7 @@ func (miner *Miner) getPending() *newPayloadResult {
|
|||
if miner.chainConfig.IsShanghai(new(big.Int).Add(header.Number, big.NewInt(1)), timestamp) {
|
||||
withdrawal = []*types.Withdrawal{}
|
||||
}
|
||||
ret := miner.generateWork(&generateParams{
|
||||
ret := miner.generateWork(context.Background(), &generateParams{
|
||||
timestamp: timestamp,
|
||||
forceTime: false,
|
||||
parentHash: header.Hash(),
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package miner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"math/big"
|
||||
|
|
@ -28,6 +29,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/stateless"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/internal/telemetry"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
|
|
@ -225,7 +227,7 @@ func (miner *Miner) buildPayload(args *BuildPayloadArgs, witness bool) (*Payload
|
|||
slotNum: args.SlotNum,
|
||||
noTxs: true,
|
||||
}
|
||||
empty := miner.generateWork(emptyParams, witness)
|
||||
empty := miner.generateWork(context.Background(), emptyParams, witness)
|
||||
if empty.err != nil {
|
||||
return nil, empty.err
|
||||
}
|
||||
|
|
@ -261,11 +263,17 @@ func (miner *Miner) buildPayload(args *BuildPayloadArgs, witness bool) (*Payload
|
|||
select {
|
||||
case <-timer.C:
|
||||
start := time.Now()
|
||||
r := miner.generateWork(fullParams, witness)
|
||||
ctx, _, spanEnd := telemetry.StartRootSpan("miner.buildPayload",
|
||||
telemetry.Int64Attribute("block.number", int64(args.Timestamp)),
|
||||
telemetry.StringAttribute("payload.id", args.Id().String()),
|
||||
)
|
||||
r := miner.generateWork(ctx, fullParams, witness)
|
||||
if r.err == nil {
|
||||
payload.update(r, time.Since(start))
|
||||
spanEnd(nil)
|
||||
} else {
|
||||
log.Info("Error while generating work", "id", payload.id, "err", r.err)
|
||||
spanEnd(&r.err)
|
||||
}
|
||||
timer.Reset(max(0, miner.config.Recommit-time.Since(start)))
|
||||
case <-payload.stop:
|
||||
|
|
@ -296,7 +304,7 @@ func (miner *Miner) BuildTestingPayload(args *BuildPayloadArgs, transactions []*
|
|||
overrideExtraData: extraData,
|
||||
overrideTxs: transactions,
|
||||
}
|
||||
res := miner.generateWork(fullParams, false)
|
||||
res := miner.generateWork(context.Background(), fullParams, false)
|
||||
if res.err != nil {
|
||||
return nil, res.err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package miner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
|
@ -32,6 +33,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/txpool"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/internal/telemetry"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/holiman/uint256"
|
||||
|
|
@ -120,8 +122,8 @@ type generateParams struct {
|
|||
}
|
||||
|
||||
// generateWork generates a sealing block based on the given parameters.
|
||||
func (miner *Miner) generateWork(genParam *generateParams, witness bool) *newPayloadResult {
|
||||
work, err := miner.prepareWork(genParam, witness)
|
||||
func (miner *Miner) generateWork(ctx context.Context, genParam *generateParams, witness bool) *newPayloadResult {
|
||||
work, err := miner.prepareWork(ctx, genParam, witness)
|
||||
if err != nil {
|
||||
return &newPayloadResult{err: err}
|
||||
}
|
||||
|
|
@ -157,7 +159,7 @@ func (miner *Miner) generateWork(genParam *generateParams, witness bool) *newPay
|
|||
})
|
||||
defer timer.Stop()
|
||||
|
||||
err := miner.fillTransactions(interrupt, work)
|
||||
err := miner.fillTransactions(ctx, interrupt, work)
|
||||
if errors.Is(err, errBlockInterruptedByTimeout) {
|
||||
log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(miner.config.Recommit))
|
||||
}
|
||||
|
|
@ -192,10 +194,16 @@ func (miner *Miner) generateWork(genParam *generateParams, witness bool) *newPay
|
|||
work.header.RequestsHash = &reqHash
|
||||
}
|
||||
|
||||
var finalizeErr error
|
||||
_, _, spanEnd := telemetry.StartSpan(ctx, "miner.finalizeAndAssemble")
|
||||
block, err := miner.engine.FinalizeAndAssemble(miner.chain, work.header, work.state, &body, work.receipts)
|
||||
if err != nil {
|
||||
finalizeErr = err
|
||||
spanEnd(&finalizeErr)
|
||||
return &newPayloadResult{err: err}
|
||||
}
|
||||
spanEnd(&finalizeErr)
|
||||
|
||||
return &newPayloadResult{
|
||||
block: block,
|
||||
fees: totalFees(block, work.receipts),
|
||||
|
|
@ -210,7 +218,10 @@ func (miner *Miner) generateWork(genParam *generateParams, witness bool) *newPay
|
|||
// prepareWork constructs the sealing task according to the given parameters,
|
||||
// either based on the last chain head or specified parent. In this function
|
||||
// the pending transactions are not filled yet, only the empty task returned.
|
||||
func (miner *Miner) prepareWork(genParams *generateParams, witness bool) (*environment, error) {
|
||||
func (miner *Miner) prepareWork(ctx context.Context, genParams *generateParams, witness bool) (_ *environment, err error) {
|
||||
_, _, spanEnd := telemetry.StartSpan(ctx, "miner.prepareWork")
|
||||
defer spanEnd(&err)
|
||||
|
||||
miner.confMu.RLock()
|
||||
defer miner.confMu.RUnlock()
|
||||
|
||||
|
|
@ -502,7 +513,10 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran
|
|||
// 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.
|
||||
func (miner *Miner) fillTransactions(interrupt *atomic.Int32, env *environment) error {
|
||||
func (miner *Miner) fillTransactions(ctx context.Context, interrupt *atomic.Int32, env *environment) (err error) {
|
||||
_, _, spanEnd := telemetry.StartSpan(ctx, "miner.fillTransactions")
|
||||
defer spanEnd(&err)
|
||||
|
||||
miner.confMu.RLock()
|
||||
tip := miner.config.GasPrice
|
||||
prio := miner.prio
|
||||
|
|
|
|||
Loading…
Reference in a new issue