diff --git a/internal/telemetry/telemetry.go b/internal/telemetry/telemetry.go index 27fe9b0a7a..0b07006a8a 100644 --- a/internal/telemetry/telemetry.go +++ b/internal/telemetry/telemetry.go @@ -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)) diff --git a/miner/miner.go b/miner/miner.go index ee890b5e54..f642ed0170 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -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(), diff --git a/miner/payload_building.go b/miner/payload_building.go index 2398e675af..61f163ce9c 100644 --- a/miner/payload_building.go +++ b/miner/payload_building.go @@ -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 } diff --git a/miner/worker.go b/miner/worker.go index b5fb7a344d..5fa3d4da6e 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -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