From 31e49d91355dbc85808bf1c9115f8a47e261c924 Mon Sep 17 00:00:00 2001 From: geoknee Date: Thu, 23 Oct 2025 13:15:30 +0100 Subject: [PATCH 1/5] core: add gauge metric for block gas used and blob gas used This can be used to track the DA footprint per block --- core/blockchain.go | 19 ++++++++++++++++++- core/headerchain.go | 16 ++++++++++++++++ metrics/gauge.go | 10 ++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/core/blockchain.go b/core/blockchain.go index 8f4eb804ee..4ba8381a80 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -64,7 +64,12 @@ var ( headFastBlockGauge = metrics.NewRegisteredGauge("chain/head/receipt", nil) headFinalizedBlockGauge = metrics.NewRegisteredGauge("chain/head/finalized", nil) headSafeBlockGauge = metrics.NewRegisteredGauge("chain/head/safe", nil) - headBaseFeeGauge = metrics.NewRegisteredGauge("chain/head/basefee", nil) + + // (BEGIN) OPStack additions + headBaseFeeGauge = metrics.NewRegisteredGauge("chain/head/basefee", nil) + headGasUsedGauge = metrics.NewRegisteredGauge("chain/head/gas_used", nil) + headBlobGasUsedGauge = metrics.NewRegisteredGauge("chain/head/blob_gas_used", nil) + // (END) OPStack additions chainInfoGauge = metrics.NewRegisteredGaugeInfo("chain/info", nil) chainMgaspsMeter = metrics.NewRegisteredResettingTimer("chain/mgasps", nil) @@ -1230,7 +1235,11 @@ func (bc *BlockChain) writeHeadBlock(block *types.Block) { bc.currentBlock.Store(block.Header()) headBlockGauge.Update(int64(block.NumberU64())) + + // OPStack additions headBaseFeeGauge.TryUpdate(block.Header().BaseFee) + headGasUsedGauge.Update(int64(block.Header().GasUsed)) + headBlobGasUsedGauge.TryUpdateUint64(block.Header().BlobGasUsed) } // stopWithoutSaving stops the blockchain service. If any imports are currently in progress @@ -1398,7 +1407,11 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ bc.currentSnapBlock.Store(header) headHeaderGauge.Update(header.Number.Int64()) headFastBlockGauge.Update(header.Number.Int64()) + + // OPStack additions headBaseFeeGauge.TryUpdate(header.BaseFee) + headGasUsedGauge.Update(int64(header.GasUsed)) + headBlobGasUsedGauge.TryUpdateUint64(header.BlobGasUsed) return nil } // writeAncient writes blockchain and corresponding receipt chain into ancient store. @@ -2771,7 +2784,11 @@ func (bc *BlockChain) InsertHeadersBeforeCutoff(headers []*types.Header) (int, e bc.currentSnapBlock.Store(last) headHeaderGauge.Update(last.Number.Int64()) headFastBlockGauge.Update(last.Number.Int64()) + + // OPStack additions headBaseFeeGauge.TryUpdate(last.BaseFee) + headGasUsedGauge.Update(int64(last.GasUsed)) + headBlobGasUsedGauge.TryUpdateUint64(last.BlobGasUsed) return 0, nil } diff --git a/core/headerchain.go b/core/headerchain.go index 4174aadef1..25a6037743 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -92,7 +92,11 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c } hc.currentHeaderHash = hc.CurrentHeader().Hash() headHeaderGauge.Update(hc.CurrentHeader().Number.Int64()) + + // OPStack additions headBaseFeeGauge.TryUpdate(hc.CurrentHeader().BaseFee) + headGasUsedGauge.Update(int64(hc.CurrentHeader().GasUsed)) + headBlobGasUsedGauge.TryUpdateUint64(hc.CurrentHeader().BlobGasUsed) return hc, nil } @@ -183,7 +187,11 @@ func (hc *HeaderChain) Reorg(headers []*types.Header) error { hc.currentHeaderHash = last.Hash() hc.currentHeader.Store(types.CopyHeader(last)) headHeaderGauge.Update(last.Number.Int64()) + + // OPStack additions headBaseFeeGauge.TryUpdate(last.BaseFee) + headGasUsedGauge.Update(int64(last.GasUsed)) + headBlobGasUsedGauge.TryUpdateUint64(last.BlobGasUsed) return nil } @@ -486,7 +494,11 @@ func (hc *HeaderChain) SetCurrentHeader(head *types.Header) { hc.currentHeader.Store(head) hc.currentHeaderHash = head.Hash() headHeaderGauge.Update(head.Number.Int64()) + + // OPStack additions headBaseFeeGauge.TryUpdate(head.BaseFee) + headGasUsedGauge.Update(int64(head.GasUsed)) + headBlobGasUsedGauge.TryUpdateUint64(head.BlobGasUsed) } type ( @@ -573,7 +585,11 @@ func (hc *HeaderChain) setHead(headBlock uint64, headTime uint64, updateFn Updat hc.currentHeader.Store(parent) hc.currentHeaderHash = parentHash headHeaderGauge.Update(parent.Number.Int64()) + + // OPStack additions headBaseFeeGauge.TryUpdate(parent.BaseFee) + headGasUsedGauge.Update(int64(parent.GasUsed)) + headBlobGasUsedGauge.TryUpdateUint64(parent.BlobGasUsed) // If this is the first iteration, wipe any leftover data upwards too so // we don't end up with dangling daps in the database diff --git a/metrics/gauge.go b/metrics/gauge.go index 909fca1304..54166ea6f0 100644 --- a/metrics/gauge.go +++ b/metrics/gauge.go @@ -45,6 +45,7 @@ func (g *Gauge) Update(v int64) { (*atomic.Int64)(g).Store(v) } +// OPStack additon // TryUpdate updates the gauge if the value is non-nil, converting it to int64. func (g *Gauge) TryUpdate(v *big.Int) { if v == nil { @@ -53,6 +54,15 @@ func (g *Gauge) TryUpdate(v *big.Int) { (*atomic.Int64)(g).Store(v.Int64()) } +// OPStack additon +// TryUpdate updates the gauge if the value is non-nil, converting it to int64. +func (g *Gauge) TryUpdateUint64(v *uint64) { + if v == nil { + return + } + (*atomic.Int64)(g).Store(int64(*v)) +} + // UpdateIfGt updates the gauge's value if v is larger then the current value. func (g *Gauge) UpdateIfGt(v int64) { value := (*atomic.Int64)(g) From 72329760e9188770ffa7fbcf690ce743ffd3cfa6 Mon Sep 17 00:00:00 2001 From: geoknee Date: Thu, 23 Oct 2025 21:05:36 +0100 Subject: [PATCH 2/5] encapsulate OPStack additions into new file and function --- core/blockchain.go | 24 ++++++------------------ core/blockchain_optimism.go | 20 ++++++++++++++++++++ core/headerchain.go | 22 +++++++--------------- 3 files changed, 33 insertions(+), 33 deletions(-) create mode 100644 core/blockchain_optimism.go diff --git a/core/blockchain.go b/core/blockchain.go index 4ba8381a80..365b864dc0 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -65,12 +65,6 @@ var ( headFinalizedBlockGauge = metrics.NewRegisteredGauge("chain/head/finalized", nil) headSafeBlockGauge = metrics.NewRegisteredGauge("chain/head/safe", nil) - // (BEGIN) OPStack additions - headBaseFeeGauge = metrics.NewRegisteredGauge("chain/head/basefee", nil) - headGasUsedGauge = metrics.NewRegisteredGauge("chain/head/gas_used", nil) - headBlobGasUsedGauge = metrics.NewRegisteredGauge("chain/head/blob_gas_used", nil) - // (END) OPStack additions - chainInfoGauge = metrics.NewRegisteredGaugeInfo("chain/info", nil) chainMgaspsMeter = metrics.NewRegisteredResettingTimer("chain/mgasps", nil) @@ -1236,10 +1230,8 @@ func (bc *BlockChain) writeHeadBlock(block *types.Block) { bc.currentBlock.Store(block.Header()) headBlockGauge.Update(int64(block.NumberU64())) - // OPStack additions - headBaseFeeGauge.TryUpdate(block.Header().BaseFee) - headGasUsedGauge.Update(int64(block.Header().GasUsed)) - headBlobGasUsedGauge.TryUpdateUint64(block.Header().BlobGasUsed) + // OPStack addition + updateOptimismBlockMetrics(block.Header()) } // stopWithoutSaving stops the blockchain service. If any imports are currently in progress @@ -1408,10 +1400,8 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ headHeaderGauge.Update(header.Number.Int64()) headFastBlockGauge.Update(header.Number.Int64()) - // OPStack additions - headBaseFeeGauge.TryUpdate(header.BaseFee) - headGasUsedGauge.Update(int64(header.GasUsed)) - headBlobGasUsedGauge.TryUpdateUint64(header.BlobGasUsed) + // OPStack addition + updateOptimismBlockMetrics(header) return nil } // writeAncient writes blockchain and corresponding receipt chain into ancient store. @@ -2785,10 +2775,8 @@ func (bc *BlockChain) InsertHeadersBeforeCutoff(headers []*types.Header) (int, e headHeaderGauge.Update(last.Number.Int64()) headFastBlockGauge.Update(last.Number.Int64()) - // OPStack additions - headBaseFeeGauge.TryUpdate(last.BaseFee) - headGasUsedGauge.Update(int64(last.GasUsed)) - headBlobGasUsedGauge.TryUpdateUint64(last.BlobGasUsed) + // OPStack addition + updateOptimismBlockMetrics(last) return 0, nil } diff --git a/core/blockchain_optimism.go b/core/blockchain_optimism.go new file mode 100644 index 0000000000..d0ab9d002e --- /dev/null +++ b/core/blockchain_optimism.go @@ -0,0 +1,20 @@ +package core + +import ( + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/metrics" +) + +// OPStack additions +var ( + headBaseFeeGauge = metrics.NewRegisteredGauge("chain/head/basefee", nil) + headGasUsedGauge = metrics.NewRegisteredGauge("chain/head/gas_used", nil) + headBlobGasUsedGauge = metrics.NewRegisteredGauge("chain/head/blob_gas_used", nil) +) + +func updateOptimismBlockMetrics(header *types.Header) error { + headBaseFeeGauge.TryUpdate(header.BaseFee) + headGasUsedGauge.Update(int64(header.GasUsed)) + headBlobGasUsedGauge.TryUpdateUint64(header.BlobGasUsed) + return nil +} diff --git a/core/headerchain.go b/core/headerchain.go index 25a6037743..cc8d6299ef 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -94,9 +94,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c headHeaderGauge.Update(hc.CurrentHeader().Number.Int64()) // OPStack additions - headBaseFeeGauge.TryUpdate(hc.CurrentHeader().BaseFee) - headGasUsedGauge.Update(int64(hc.CurrentHeader().GasUsed)) - headBlobGasUsedGauge.TryUpdateUint64(hc.CurrentHeader().BlobGasUsed) + updateOptimismBlockMetrics(hc.CurrentHeader()) return hc, nil } @@ -188,10 +186,8 @@ func (hc *HeaderChain) Reorg(headers []*types.Header) error { hc.currentHeader.Store(types.CopyHeader(last)) headHeaderGauge.Update(last.Number.Int64()) - // OPStack additions - headBaseFeeGauge.TryUpdate(last.BaseFee) - headGasUsedGauge.Update(int64(last.GasUsed)) - headBlobGasUsedGauge.TryUpdateUint64(last.BlobGasUsed) + // OPStack addition + updateOptimismBlockMetrics(last) return nil } @@ -495,10 +491,8 @@ func (hc *HeaderChain) SetCurrentHeader(head *types.Header) { hc.currentHeaderHash = head.Hash() headHeaderGauge.Update(head.Number.Int64()) - // OPStack additions - headBaseFeeGauge.TryUpdate(head.BaseFee) - headGasUsedGauge.Update(int64(head.GasUsed)) - headBlobGasUsedGauge.TryUpdateUint64(head.BlobGasUsed) + // OPStack addition + updateOptimismBlockMetrics(head) } type ( @@ -586,10 +580,8 @@ func (hc *HeaderChain) setHead(headBlock uint64, headTime uint64, updateFn Updat hc.currentHeaderHash = parentHash headHeaderGauge.Update(parent.Number.Int64()) - // OPStack additions - headBaseFeeGauge.TryUpdate(parent.BaseFee) - headGasUsedGauge.Update(int64(parent.GasUsed)) - headBlobGasUsedGauge.TryUpdateUint64(parent.BlobGasUsed) + // OPStack addition + updateOptimismBlockMetrics(parent) // If this is the first iteration, wipe any leftover data upwards too so // we don't end up with dangling daps in the database From 2d72fff9907e67a3fcf73e6f3249eb679426e467 Mon Sep 17 00:00:00 2001 From: geoknee Date: Thu, 23 Oct 2025 21:22:14 +0100 Subject: [PATCH 3/5] add histogram metrics for (blob)GasUsed --- core/blockchain_optimism.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/blockchain_optimism.go b/core/blockchain_optimism.go index d0ab9d002e..fa7ee47390 100644 --- a/core/blockchain_optimism.go +++ b/core/blockchain_optimism.go @@ -10,11 +10,18 @@ var ( headBaseFeeGauge = metrics.NewRegisteredGauge("chain/head/basefee", nil) headGasUsedGauge = metrics.NewRegisteredGauge("chain/head/gas_used", nil) headBlobGasUsedGauge = metrics.NewRegisteredGauge("chain/head/blob_gas_used", nil) + + headGasUsedHist = metrics.NewRegisteredHistogram("chain/head/gas_used_hist", nil, metrics.NewExpDecaySample(1028, 0.015)) + headBlobGasUsedHist = metrics.NewRegisteredHistogram("chain/head/blob_gas_used_hist", nil, metrics.NewExpDecaySample(1028, 0.015)) ) func updateOptimismBlockMetrics(header *types.Header) error { headBaseFeeGauge.TryUpdate(header.BaseFee) headGasUsedGauge.Update(int64(header.GasUsed)) headBlobGasUsedGauge.TryUpdateUint64(header.BlobGasUsed) + headGasUsedHist.Update(int64(header.GasUsed)) + if header.BlobGasUsed != nil { + headBlobGasUsedHist.Update(int64(*header.BlobGasUsed)) + } return nil } From 3d70e8613d9ec228129b58f7a22682c9b1a4affa Mon Sep 17 00:00:00 2001 From: geoknee Date: Fri, 24 Oct 2025 10:34:19 +0100 Subject: [PATCH 4/5] update fork.yaml --- fork.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fork.yaml b/fork.yaml index 7957643d17..a0af43cd66 100644 --- a/fork.yaml +++ b/fork.yaml @@ -199,7 +199,10 @@ def: - title: Warn on missing hardfork data and emit additional metrics globs: - "core/blockchain.go" - - title: Additional metrics + - title: Define additional header-based metrics + globs: + - "core/blockchain_optimism.go" + - title: Add hooks for additional header-chain metrics globs: - "core/headerchain.go" - title: Optional Engine API extensions From 80fc55fd6376ab7c32378bd8f1594c7ff6353d12 Mon Sep 17 00:00:00 2001 From: geoknee Date: Fri, 24 Oct 2025 10:35:47 +0100 Subject: [PATCH 5/5] typos --- core/headerchain.go | 2 +- metrics/gauge.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/headerchain.go b/core/headerchain.go index cc8d6299ef..ca403535e1 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -93,7 +93,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c hc.currentHeaderHash = hc.CurrentHeader().Hash() headHeaderGauge.Update(hc.CurrentHeader().Number.Int64()) - // OPStack additions + // OPStack addition updateOptimismBlockMetrics(hc.CurrentHeader()) return hc, nil } diff --git a/metrics/gauge.go b/metrics/gauge.go index 54166ea6f0..4f93e22487 100644 --- a/metrics/gauge.go +++ b/metrics/gauge.go @@ -45,7 +45,7 @@ func (g *Gauge) Update(v int64) { (*atomic.Int64)(g).Store(v) } -// OPStack additon +// OPStack addition // TryUpdate updates the gauge if the value is non-nil, converting it to int64. func (g *Gauge) TryUpdate(v *big.Int) { if v == nil {