From d0207ef954fd10d3ac1af6d021e992aad83e5d31 Mon Sep 17 00:00:00 2001 From: Jinsuk Park Date: Wed, 21 Aug 2024 21:13:21 +0900 Subject: [PATCH] Measure builder payload bytes --- op-node/metrics/metrics.go | 14 ++++++++++++++ op-node/node/builder.go | 10 +++++++++- op-node/rollup/builder/builder.go | 10 ++++++++-- op-node/rollup/derive/engine_update.go | 2 +- op-node/rollup/derive/pipeline.go | 1 + op-node/rollup/driver/sequencer.go | 1 + 6 files changed, 34 insertions(+), 4 deletions(-) diff --git a/op-node/metrics/metrics.go b/op-node/metrics/metrics.go index 5c100cb122eb..80817cba84b5 100644 --- a/op-node/metrics/metrics.go +++ b/op-node/metrics/metrics.go @@ -85,6 +85,7 @@ type Metricer interface { RecordBuilderRequestTime(duration time.Duration) RecordBuilderRequestFail() RecordBuilderRequestTimeout() + RecordBuilderPayloadBytes(num int) RecordSequencerProfit(profit float64, source PayloadSource) RecordSequencerPayloadInserted(source PayloadSource) RecordPayloadGas(gas float64, source string) @@ -131,6 +132,7 @@ type Metrics struct { SequencerBuilderRequestTotal prometheus.Counter SequencerBuilderRequestErrors prometheus.Counter SequencerBuilderRequestTimeouts prometheus.Counter + SequencerBuilderPayloadBytes prometheus.Gauge SequencerProfit *prometheus.GaugeVec @@ -423,6 +425,11 @@ func NewMetrics(procName string) *Metrics { Name: "sequencer_builder_request_timeout", Help: "Number of sequencer builder request timeouts", }), + SequencerBuilderPayloadBytes: factory.NewGauge(prometheus.GaugeOpts{ + Namespace: ns, + Name: "sequencer_builder_payload_bytes", + Help: "Size of sequencer builder payloads by source", + }), SequencerProfit: factory.NewGaugeVec(prometheus.GaugeOpts{ Namespace: ns, Name: "sequencer_profit", @@ -637,6 +644,10 @@ func (m *Metrics) RecordBuilderRequestTimeout() { m.SequencerBuilderRequestTimeouts.Inc() } +func (m *Metrics) RecordBuilderPayloadBytes(num int) { + m.SequencerBuilderPayloadBytes.Add(float64(num)) +} + // RecordSequencerProfit measures the profit made by the sequencer by source: engine and external builders. func (m *Metrics) RecordSequencerProfit(profit float64, source PayloadSource) { m.SequencerProfit.WithLabelValues(string(source)).Set(profit) @@ -828,6 +839,9 @@ func (n *noopMetricer) RecordBuilderRequestFail() { func (n *noopMetricer) RecordBuilderRequestTimeout() { } +func (n *noopMetricer) RecordBuilderPayloadBytes(num int) { +} + func (n *noopMetricer) RecordSequencerProfit(profit float64, source PayloadSource) { } diff --git a/op-node/node/builder.go b/op-node/node/builder.go index e00db845883d..2a3d2c55eafc 100644 --- a/op-node/node/builder.go +++ b/op-node/node/builder.go @@ -16,6 +16,7 @@ import ( "github.com/holiman/uint256" "github.com/ethereum-optimism/optimism/op-node/rollup" + "github.com/ethereum-optimism/optimism/op-node/rollup/builder" "github.com/ethereum-optimism/optimism/op-service/client" "github.com/ethereum-optimism/optimism/op-service/eth" "github.com/ethereum/go-ethereum/common" @@ -37,6 +38,10 @@ type BuilderAPIClient struct { httpClient *client.BasicHTTPClient } +type BuilderMetrics interface { + RecordBuilderPayloadBytes(num int) +} + func NewBuilderClient(log log.Logger, rollupCfg *rollup.Config, endpoint string, timeout time.Duration) *BuilderAPIClient { httpClient := client.NewBasicHTTPClient(endpoint, log) config := &BuilderAPIConfig{ @@ -60,12 +65,14 @@ func (s *BuilderAPIClient) Timeout() time.Duration { return s.config.Timeout } +var _ builder.PayloadBuilder = &BuilderAPIClient{} + type httpErrorResp struct { Code int `json:"code"` Message string `json:"message"` } -func (s *BuilderAPIClient) GetPayload(ctx context.Context, ref eth.L2BlockRef, log log.Logger) (*eth.ExecutionPayloadEnvelope, error) { +func (s *BuilderAPIClient) GetPayload(ctx context.Context, ref eth.L2BlockRef, log log.Logger, metrics builder.BuilderMetrics) (*eth.ExecutionPayloadEnvelope, error) { submitBlockRequest := new(builderSpec.VersionedSubmitBlockRequest) slot := ref.Number + 1 parentHash := ref.Hash @@ -85,6 +92,7 @@ func (s *BuilderAPIClient) GetPayload(ctx context.Context, ref eth.L2BlockRef, l } if resp.StatusCode != http.StatusOK { + metrics.RecordBuilderPayloadBytes(len(bodyBytes)) var errResp httpErrorResp if err := json.Unmarshal(bodyBytes, &errResp); err != nil { log.Warn("failed to unmarshal error response", "error", err, "response", string(bodyBytes)) diff --git a/op-node/rollup/builder/builder.go b/op-node/rollup/builder/builder.go index 0fec227ee5f8..26273bc08ec9 100644 --- a/op-node/rollup/builder/builder.go +++ b/op-node/rollup/builder/builder.go @@ -9,15 +9,19 @@ import ( "github.com/ethereum/go-ethereum/log" ) +type BuilderMetrics interface { + RecordBuilderPayloadBytes(num int) +} + type PayloadBuilder interface { Enabled() bool Timeout() time.Duration - GetPayload(ctx context.Context, ref eth.L2BlockRef, log log.Logger) (*eth.ExecutionPayloadEnvelope, error) + GetPayload(ctx context.Context, ref eth.L2BlockRef, log log.Logger, metrics BuilderMetrics) (*eth.ExecutionPayloadEnvelope, error) } type NoOpBuilder struct{} -func (n *NoOpBuilder) GetPayload(_ context.Context, _ eth.L2BlockRef, _ log.Logger) (*eth.ExecutionPayloadEnvelope, error) { +func (n *NoOpBuilder) GetPayload(_ context.Context, _ eth.L2BlockRef, _ log.Logger, _ BuilderMetrics) (*eth.ExecutionPayloadEnvelope, error) { return nil, errors.New("Builder not enabled") } @@ -28,3 +32,5 @@ func (n *NoOpBuilder) Enabled() bool { func (n *NoOpBuilder) Timeout() time.Duration { return 0 } + +var _ PayloadBuilder = &NoOpBuilder{} diff --git a/op-node/rollup/derive/engine_update.go b/op-node/rollup/derive/engine_update.go index 66a1f661224a..ccc30f4ba87c 100644 --- a/op-node/rollup/derive/engine_update.go +++ b/op-node/rollup/derive/engine_update.go @@ -128,7 +128,7 @@ type PayloadRequestResult struct { func requestPayloadFromBuilder(ctx context.Context, builder builder.PayloadBuilder, l2head eth.L2BlockRef, log log.Logger, metrics Metrics, results chan<- *PayloadRequestResult) { start := time.Now() - payload, err := builder.GetPayload(ctx, l2head, log) + payload, err := builder.GetPayload(ctx, l2head, log, metrics) metrics.RecordBuilderRequestTime(time.Since(start)) if err != nil { results <- &PayloadRequestResult{success: false, error: err} diff --git a/op-node/rollup/derive/pipeline.go b/op-node/rollup/derive/pipeline.go index d7acd5a4d0a1..0511d93a82ee 100644 --- a/op-node/rollup/derive/pipeline.go +++ b/op-node/rollup/derive/pipeline.go @@ -27,6 +27,7 @@ type Metrics interface { RecordBuilderRequestTime(duration time.Duration) RecordBuilderRequestFail() RecordBuilderRequestTimeout() + RecordBuilderPayloadBytes(num int) RecordSequencerProfit(profit float64, source metrics.PayloadSource) RecordSequencerPayloadInserted(source metrics.PayloadSource) RecordPayloadGas(gas float64, source string) diff --git a/op-node/rollup/driver/sequencer.go b/op-node/rollup/driver/sequencer.go index 9182c9c340d3..0db4c0788e30 100644 --- a/op-node/rollup/driver/sequencer.go +++ b/op-node/rollup/driver/sequencer.go @@ -34,6 +34,7 @@ type SequencerMetrics interface { RecordBuilderRequestTime(duration time.Duration) RecordBuilderRequestFail() RecordBuilderRequestTimeout() + RecordBuilderPayloadBytes(num int) RecordSequencerProfit(profit float64, source metrics.PayloadSource) RecordSequencerPayloadInserted(source metrics.PayloadSource) RecordPayloadGas(gas float64, source string)