From 3a629d9d04c370a9a068a199e2dac7824d95e2cd Mon Sep 17 00:00:00 2001 From: Luke Iannucci Date: Fri, 3 Jul 2026 14:10:52 -0400 Subject: [PATCH 1/4] address audit m3 --- op-batcher/batcher/driver.go | 15 ------------ op-batcher/batcher/espresso_driver.go | 17 ++++---------- op-batcher/batcher/fallback_auth.go | 29 ++++++------------------ op-batcher/batcher/fallback_auth_test.go | 18 +++++++-------- 4 files changed, 19 insertions(+), 60 deletions(-) diff --git a/op-batcher/batcher/driver.go b/op-batcher/batcher/driver.go index 1b0f4aa73b9..056e510684c 100644 --- a/op-batcher/batcher/driver.go +++ b/op-batcher/batcher/driver.go @@ -136,15 +136,6 @@ type BatchSubmitter struct { throttleController *throttler.ThrottleController publishSignal chan pubInfo - - // authGroup tracks the fallback batcher's receipt-watcher goroutines (one - // per auth+batch pair) so the publishing loop can drain them via - // waitForAuthGroup before closing receiptsCh. New watchers are back-pressured - // (not hard-bounded) by the txmgr Queue: queue.Send blocks at - // MaxPendingTransactions, so watchers are created no faster than txs drain, - // though a slow receipts loop can briefly leave more than that parked on their - // final receiptsCh send. - authGroup sync.WaitGroup } // NewBatchSubmitter initializes the BatchSubmitter driver from a preconfigured DriverSetup @@ -537,12 +528,6 @@ func (l *BatchSubmitter) publishingLoop(ctx context.Context, wg *sync.WaitGroup, } } - // Wait for all in-flight fallback-auth submissions to complete to prevent - // new transactions being queued. No-op when the rollup is not configured - // with a BatchAuthenticator or when the EspressoTime hardfork has not - // activated. - l.waitForAuthGroup() - // We _must_ wait for all senders on receiptsCh to finish before we can close it. if err := txQueue.Wait(); err != nil { if !errors.Is(err, context.Canceled) { diff --git a/op-batcher/batcher/espresso_driver.go b/op-batcher/batcher/espresso_driver.go index 3c2c6a31056..33512cb1a09 100644 --- a/op-batcher/batcher/espresso_driver.go +++ b/op-batcher/batcher/espresso_driver.go @@ -6,20 +6,11 @@ import ( "github.com/ethereum-optimism/optimism/op-service/txmgr" ) -// waitForAuthGroup blocks until all in-flight fallback-auth watcher goroutines -// have finished. publishingLoop calls it before closing receiptsCh: each watcher -// is a sender on receiptsCh, so the receipts loop must still be draining -// receiptsCh at this point or a watcher's final send would block forever. Each -// watcher always terminates because the txmgr Queue emits exactly one receipt per -// Send, even on context cancellation. -func (l *BatchSubmitter) waitForAuthGroup() { - l.authGroup.Wait() -} - // dispatchAuthenticatedSendTx routes sendTx through the fallback-batcher -// post-fork auth path, returning true when the tx has been handed off to -// authGroup. Returns false to mean "fall through to the upstream queue.Send -// path" — pre-fork operation and any cancel tx. +// post-fork auth path, returning true when the tx has been fully handled +// (sendTxWithFallbackAuth blocks until the pair is resolved and a receipt has +// been forwarded). Returns false to mean "fall through to the upstream +// queue.Send path" — pre-fork operation and any cancel tx. // // The fallback batcher consults isFallbackAuthRequired to gate authentication // behind the EspressoTime hardfork: pre-fork the verifier accepts plain diff --git a/op-batcher/batcher/fallback_auth.go b/op-batcher/batcher/fallback_auth.go index 61a3de51641..b5001e3b166 100644 --- a/op-batcher/batcher/fallback_auth.go +++ b/op-batcher/batcher/fallback_auth.go @@ -79,38 +79,18 @@ func (l *BatchSubmitter) sendTxWithFallbackAuth(txdata txData, isCancel bool, ca To: &l.RollupConfig.BatchAuthenticatorAddress, } - // Private buffered channels: queue.Send forwards exactly one receipt to each, so the watcher - // reads exactly once per channel (even on context cancellation, the queue still emits a - // ctx-error receipt). These never reach handleReceipt; only the synthetic receipt below does. - authReceiptCh := make(chan txmgr.TxReceipt[txRef], 1) - batchReceiptCh := make(chan txmgr.TxReceipt[txRef], 1) - l.Log.Debug( "Sending fallback authenticateBatchInfo transaction", "txRef", transactionReference, "commitment", hexutil.Encode(commitment[:]), "address", l.RollupConfig.BatchAuthenticatorAddress.String(), ) - // Submit the auth tx then the batch tx, in order, on the publishing-loop goroutine so their + // Submit the auth tx wait for receipt, then send the batch tx, on the publishing-loop goroutine so their // nonces are assigned in submission order. Each Send blocks here when the queue is at its // MaxPendingTransactions limit. + authReceiptCh := make(chan txmgr.TxReceipt[txRef], 1) queue.Send(transactionReference, verifyCandidate, authReceiptCh) - queue.Send(transactionReference, *candidate, batchReceiptCh) - - l.authGroup.Add(1) - go func() { - defer l.authGroup.Done() - l.watchFallbackAuthReceipts(transactionReference, authReceiptCh, batchReceiptCh, receiptsCh) - }() -} - -// watchFallbackAuthReceipts collects the auth and batch receipts for a fallback-auth pair, -// validates that the batch tx landed within the lookback window of the auth tx, and forwards a -// single synthetic receipt keyed to the batch txData onto receiptsCh. Any failure produces an -// error receipt so the channel manager rewinds and resubmits the frame set. -func (l *BatchSubmitter) watchFallbackAuthReceipts(transactionReference txRef, authReceiptCh, batchReceiptCh chan txmgr.TxReceipt[txRef], receiptsCh chan txmgr.TxReceipt[txRef]) { authResult := <-authReceiptCh - batchResult := <-batchReceiptCh if authResult.Err != nil { l.Log.Error("Failed to send fallback authenticateBatchInfo transaction", "txRef", transactionReference, "err", authResult.Err) @@ -135,6 +115,11 @@ func (l *BatchSubmitter) watchFallbackAuthReceipts(transactionReference txRef, a return } + // The auth tx is confirmed on L1. Now send the batch tx + batchReceiptCh := make(chan txmgr.TxReceipt[txRef], 1) + queue.Send(transactionReference, *candidate, batchReceiptCh) + batchResult := <-batchReceiptCh + if batchResult.Err != nil { l.Log.Error("Failed to send batch inbox transaction", "txRef", transactionReference, "err", batchResult.Err) receiptsCh <- txmgr.TxReceipt[txRef]{ diff --git a/op-batcher/batcher/fallback_auth_test.go b/op-batcher/batcher/fallback_auth_test.go index 0822f8a091f..c50dd6a69cd 100644 --- a/op-batcher/batcher/fallback_auth_test.go +++ b/op-batcher/batcher/fallback_auth_test.go @@ -80,7 +80,6 @@ func TestFallbackAuth_OrderingAndSuccess(t *testing.T) { receiptsCh := make(chan txmgr.TxReceipt[txRef], 1) l.sendTxWithFallbackAuth(txdata, false, candidate, queue, receiptsCh) - l.authGroup.Wait() require.Len(t, queue.sends, 2) // First send must target the BatchAuthenticator (the auth tx), giving it the @@ -103,18 +102,19 @@ func TestFallbackAuth_AuthFailureRetried(t *testing.T) { queue := &fakeTxSender{ responses: []txmgr.TxReceipt[txRef]{ - {Err: errSendFailed}, // auth fails - {Receipt: receiptWithBlock(101)}, // batch lands anyway + {Err: errSendFailed}, // auth fails. No batch response, it must never be sent }, } receiptsCh := make(chan txmgr.TxReceipt[txRef], 1) l.sendTxWithFallbackAuth(txdata, false, candidate, queue, receiptsCh) - l.authGroup.Wait() got := <-receiptsCh require.Error(t, got.Err) require.Equal(t, txdata.ID().String(), got.ID.id.String()) + // The batch tx must not be sent after an auth failure: it would be crafted at the + // next nonce while the failed auth tx resets the txmgr nonce, leaving a nonce gap. + require.Len(t, queue.sends, 1) } func TestFallbackAuth_BatchFailureRetried(t *testing.T) { @@ -131,7 +131,6 @@ func TestFallbackAuth_BatchFailureRetried(t *testing.T) { receiptsCh := make(chan txmgr.TxReceipt[txRef], 1) l.sendTxWithFallbackAuth(txdata, false, candidate, queue, receiptsCh) - l.authGroup.Wait() got := <-receiptsCh require.Error(t, got.Err) @@ -148,18 +147,19 @@ func TestFallbackAuth_AuthRevertedRetried(t *testing.T) { queue := &fakeTxSender{ responses: []txmgr.TxReceipt[txRef]{ - {Receipt: revertedReceiptWithBlock(100)}, // auth mined but reverted - {Receipt: receiptWithBlock(101)}, // batch lands + {Receipt: revertedReceiptWithBlock(100)}, // auth mined but reverted. Batch must never be sent }, } receiptsCh := make(chan txmgr.TxReceipt[txRef], 1) l.sendTxWithFallbackAuth(txdata, false, candidate, queue, receiptsCh) - l.authGroup.Wait() got := <-receiptsCh require.Error(t, got.Err) require.Equal(t, txdata.ID().String(), got.ID.id.String()) + // A reverted auth tx emits no BatchInfoAuthenticated event, so the batch data would be + // unverifiable so the batch tx must not be submitted at all. + require.Len(t, queue.sends, 1) } // TestFallbackAuth_WindowViolationRetried verifies that a batch tx landing @@ -180,7 +180,6 @@ func TestFallbackAuth_WindowViolationRetried(t *testing.T) { receiptsCh := make(chan txmgr.TxReceipt[txRef], 1) l.sendTxWithFallbackAuth(txdata, false, candidate, queue, receiptsCh) - l.authGroup.Wait() got := <-receiptsCh require.Error(t, got.Err) @@ -207,7 +206,6 @@ func TestFallbackAuth_WindowBoundaryAccepted(t *testing.T) { receiptsCh := make(chan txmgr.TxReceipt[txRef], 1) l.sendTxWithFallbackAuth(txdata, false, candidate, queue, receiptsCh) - l.authGroup.Wait() got := <-receiptsCh require.NoError(t, got.Err) From 5dbf252c8565c940e2bc107cae7f19e351db95da Mon Sep 17 00:00:00 2001 From: Luke Iannucci Date: Fri, 3 Jul 2026 14:15:03 -0400 Subject: [PATCH 2/4] update outdated comment --- op-batcher/batcher/fallback_auth.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/op-batcher/batcher/fallback_auth.go b/op-batcher/batcher/fallback_auth.go index b5001e3b166..50f87b0f2a9 100644 --- a/op-batcher/batcher/fallback_auth.go +++ b/op-batcher/batcher/fallback_auth.go @@ -85,9 +85,8 @@ func (l *BatchSubmitter) sendTxWithFallbackAuth(txdata txData, isCancel bool, ca "commitment", hexutil.Encode(commitment[:]), "address", l.RollupConfig.BatchAuthenticatorAddress.String(), ) - // Submit the auth tx wait for receipt, then send the batch tx, on the publishing-loop goroutine so their - // nonces are assigned in submission order. Each Send blocks here when the queue is at its - // MaxPendingTransactions limit. + // Submit the auth tx and wait for its receipt, then send the batch tx. Each Send + // blocks here when the queue is at its MaxPendingTransactions limit. authReceiptCh := make(chan txmgr.TxReceipt[txRef], 1) queue.Send(transactionReference, verifyCandidate, authReceiptCh) authResult := <-authReceiptCh From 9fe36d881024fc4f3b9d22272910204ca419030e Mon Sep 17 00:00:00 2001 From: piersy Date: Thu, 9 Jul 2026 15:11:30 +0100 Subject: [PATCH 3/4] op-batcher: report fallback auth-tx failures under a calldata-typed txRef (#469) The auth tx of a fallback pair was submitted and its failures forwarded under the batch txdata's txRef. With a blob batch, an auth-tx failure surfaced with isBlob=true, so an ErrAlreadyReserved failure (account reserved by a stuck blob tx, e.g. left in the blobpool across a restart) made cancelBlockingTx send a calldata cancel against a blobpool reservation. That cancel is rejected the same way, the txpool state resets to good on its receipt, and the cycle repeats: the blob cancel needed to replace the stuck tx is never sent and no batch ever lands. Derive a calldata-typed authReference for the auth tx's queue.Send and its failure receipts, keeping the batch txdata's id so failures still requeue the right frames. --- op-batcher/batcher/fallback_auth.go | 13 ++++-- op-batcher/batcher/fallback_auth_test.go | 55 ++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/op-batcher/batcher/fallback_auth.go b/op-batcher/batcher/fallback_auth.go index 50f87b0f2a9..5fc279f74ac 100644 --- a/op-batcher/batcher/fallback_auth.go +++ b/op-batcher/batcher/fallback_auth.go @@ -43,6 +43,13 @@ func computeCommitment(candidate *txmgr.TxCandidate) ([32]byte, error) { // separate signature is needed — the L1 transaction is already signed by the TxManager's key. func (l *BatchSubmitter) sendTxWithFallbackAuth(txdata txData, isCancel bool, candidate *txmgr.TxCandidate, queue TxSender[txRef], receiptsCh chan txmgr.TxReceipt[txRef]) { transactionReference := newTxRef(txdata, isCancel) + // The auth tx shares the batch txdata's identity (so a failure requeues the right frames) + // but is always a calldata tx. Auth failures must carry its real type: an ErrAlreadyReserved + // receipt labeled with the batch's blob type would make cancelBlockingTx cancel the wrong + // pool, leaving the reserving tx stuck. + authReference := transactionReference + authReference.isBlob = false + authReference.daType = DaTypeCalldata l.Log.Debug("Sending fallback-authenticated L1 transaction", "txRef", transactionReference) commitment, err := computeCommitment(candidate) @@ -88,13 +95,13 @@ func (l *BatchSubmitter) sendTxWithFallbackAuth(txdata txData, isCancel bool, ca // Submit the auth tx and wait for its receipt, then send the batch tx. Each Send // blocks here when the queue is at its MaxPendingTransactions limit. authReceiptCh := make(chan txmgr.TxReceipt[txRef], 1) - queue.Send(transactionReference, verifyCandidate, authReceiptCh) + queue.Send(authReference, verifyCandidate, authReceiptCh) authResult := <-authReceiptCh if authResult.Err != nil { l.Log.Error("Failed to send fallback authenticateBatchInfo transaction", "txRef", transactionReference, "err", authResult.Err) receiptsCh <- txmgr.TxReceipt[txRef]{ - ID: transactionReference, + ID: authReference, Err: fmt.Errorf("failed to send fallback authenticateBatchInfo transaction: %w", authResult.Err), } return @@ -108,7 +115,7 @@ func (l *BatchSubmitter) sendTxWithFallbackAuth(txdata txData, isCancel bool, ca if authResult.Receipt.Status != types.ReceiptStatusSuccessful { l.Log.Error("Fallback authenticateBatchInfo transaction reverted", "txRef", transactionReference, "txHash", authResult.Receipt.TxHash) receiptsCh <- txmgr.TxReceipt[txRef]{ - ID: transactionReference, + ID: authReference, Err: fmt.Errorf("fallback authenticateBatchInfo transaction reverted: %s", authResult.Receipt.TxHash), } return diff --git a/op-batcher/batcher/fallback_auth_test.go b/op-batcher/batcher/fallback_auth_test.go index c50dd6a69cd..51a40f1ffab 100644 --- a/op-batcher/batcher/fallback_auth_test.go +++ b/op-batcher/batcher/fallback_auth_test.go @@ -117,6 +117,61 @@ func TestFallbackAuth_AuthFailureRetried(t *testing.T) { require.Len(t, queue.sends, 1) } +// TestFallbackAuth_AuthFailureTxRefType verifies that an auth-tx failure is +// reported under a calldata-typed txRef even when the batch txdata is blob. +// The auth tx is always calldata; if its ErrAlreadyReserved failure were +// labeled with the batch's blob type, cancelBlockingTx would send a calldata +// cancel against a blobpool reservation, which is rejected the same way, +// looping forever without ever displacing the stuck blob tx. +func TestFallbackAuth_AuthFailureTxRefType(t *testing.T) { + l := newFallbackAuthSubmitter(t) + txdata := testFallbackTxData(t) + txdata.daType = DaTypeBlob + candidate := &txmgr.TxCandidate{TxData: []byte("batch-calldata")} + + queue := &fakeTxSender{ + responses: []txmgr.TxReceipt[txRef]{ + {Err: errSendFailed}, // auth fails. No batch response, it must never be sent + }, + } + receiptsCh := make(chan txmgr.TxReceipt[txRef], 1) + + l.sendTxWithFallbackAuth(txdata, false, candidate, queue, receiptsCh) + + got := <-receiptsCh + require.Error(t, got.Err) + require.Equal(t, txdata.ID().String(), got.ID.id.String()) + require.Len(t, queue.sends, 1) + require.False(t, got.ID.isBlob) + require.Equal(t, DaTypeCalldata, got.ID.daType) +} + +// TestFallbackAuth_BatchFailureTxRefType verifies the converse: a batch-tx +// failure keeps the batch txdata's own type on the forwarded receipt. +func TestFallbackAuth_BatchFailureTxRefType(t *testing.T) { + l := newFallbackAuthSubmitter(t) + txdata := testFallbackTxData(t) + txdata.daType = DaTypeBlob + candidate := &txmgr.TxCandidate{TxData: []byte("batch-calldata")} + + queue := &fakeTxSender{ + responses: []txmgr.TxReceipt[txRef]{ + {Receipt: receiptWithBlock(100)}, // auth lands + {Err: errSendFailed}, // batch fails + }, + } + receiptsCh := make(chan txmgr.TxReceipt[txRef], 1) + + l.sendTxWithFallbackAuth(txdata, false, candidate, queue, receiptsCh) + + got := <-receiptsCh + require.Error(t, got.Err) + require.Equal(t, txdata.ID().String(), got.ID.id.String()) + require.Len(t, queue.sends, 2) + require.True(t, got.ID.isBlob) + require.Equal(t, DaTypeBlob, got.ID.daType) +} + func TestFallbackAuth_BatchFailureRetried(t *testing.T) { l := newFallbackAuthSubmitter(t) txdata := testFallbackTxData(t) From 47cb2a1c3d46a414a781c70907c179991476b171 Mon Sep 17 00:00:00 2001 From: Luke Iannucci Date: Thu, 9 Jul 2026 15:43:48 -0400 Subject: [PATCH 4/4] add metric and config assertion --- op-batcher/batcher/config.go | 7 +++++++ op-batcher/batcher/config_test.go | 7 +++++++ op-batcher/batcher/fallback_auth.go | 1 + op-batcher/batcher/fallback_auth_test.go | 12 ++++++++++++ op-batcher/metrics/metrics.go | 18 +++++++++++++++--- op-batcher/metrics/noop.go | 1 + 6 files changed, 43 insertions(+), 3 deletions(-) diff --git a/op-batcher/batcher/config.go b/op-batcher/batcher/config.go index c5e608d7038..77ef2bb5e81 100644 --- a/op-batcher/batcher/config.go +++ b/op-batcher/batcher/config.go @@ -199,6 +199,13 @@ func (c *CLIConfig) Check() error { if c.FallbackAuthLeadTime <= 0 { return fmt.Errorf("FallbackAuthLeadTime must be positive: %v", c.FallbackAuthLeadTime) } + // The auth→batch distance (num-confirmations + inclusion delay) must fit within + // BatchAuthLookbackWindow, so reserve room for the batch to land or the safe head stalls. + const fallbackAuthInclusionReserve = 75 // blocks (~15 min at 12s L1 slots) + if authLookback := derive.BatchAuthLookbackWindow; authLookback < c.TxMgrConfig.NumConfirmations+fallbackAuthInclusionReserve { + return fmt.Errorf("NumConfirmations (%d) too high for BatchAuthLookbackWindow (%d): need %d blocks of inclusion headroom", + c.TxMgrConfig.NumConfirmations, authLookback, fallbackAuthInclusionReserve) + } // Most chains' L1s still have only Cancun active, but we don't want to // overcomplicate this check with a dynamic L1 query, so we just use maxBlobsPerBlock. // We want to check for both, blobs and auto da-type. diff --git a/op-batcher/batcher/config_test.go b/op-batcher/batcher/config_test.go index 5b0062a1261..d52460a2cf0 100644 --- a/op-batcher/batcher/config_test.go +++ b/op-batcher/batcher/config_test.go @@ -117,6 +117,13 @@ func TestBatcherConfig(t *testing.T) { override: func(c *batcher.CLIConfig) { c.FallbackAuthLeadTime = 0 }, errString: "FallbackAuthLeadTime must be positive", }, + { + name: "num-confirmations leaves too little batch auth lookback window", + override: func(c *batcher.CLIConfig) { + c.TxMgrConfig.NumConfirmations = derive.BatchAuthLookbackWindow + }, + errString: "too high for BatchAuthLookbackWindow", + }, { name: "zero TargetNumFrames", override: func(c *batcher.CLIConfig) { c.TargetNumFrames = 0 }, diff --git a/op-batcher/batcher/fallback_auth.go b/op-batcher/batcher/fallback_auth.go index 5fc279f74ac..4cd352299c4 100644 --- a/op-batcher/batcher/fallback_auth.go +++ b/op-batcher/batcher/fallback_auth.go @@ -138,6 +138,7 @@ func (l *BatchSubmitter) sendTxWithFallbackAuth(txdata txData, isCancel bool, ca distance := new(big.Int).Sub(batchResult.Receipt.BlockNumber, authResult.Receipt.BlockNumber) lookbackWindow := new(big.Int).SetUint64(derive.BatchAuthLookbackWindow) if distance.Sign() < 0 || distance.Cmp(lookbackWindow) > 0 { + l.Metr.RecordFallbackAuthWindowExceeded() l.Log.Error("authenticateBatchInfo transaction too far from batch inbox transaction", "txRef", transactionReference, "distance", distance) receiptsCh <- txmgr.TxReceipt[txRef]{ ID: transactionReference, diff --git a/op-batcher/batcher/fallback_auth_test.go b/op-batcher/batcher/fallback_auth_test.go index 51a40f1ffab..d9168174ca5 100644 --- a/op-batcher/batcher/fallback_auth_test.go +++ b/op-batcher/batcher/fallback_auth_test.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/stretchr/testify/require" + "github.com/ethereum-optimism/optimism/op-batcher/metrics" "github.com/ethereum-optimism/optimism/op-node/rollup" "github.com/ethereum-optimism/optimism/op-node/rollup/derive" "github.com/ethereum-optimism/optimism/op-service/eth" @@ -41,9 +42,17 @@ func (f *fakeTxSender) Send(id txRef, candidate txmgr.TxCandidate, receiptCh cha receiptCh <- resp } +type windowExceededSpy struct { + metrics.Metricer + count int +} + +func (s *windowExceededSpy) RecordFallbackAuthWindowExceeded() { s.count++ } + func newFallbackAuthSubmitter(t *testing.T) *BatchSubmitter { l := &BatchSubmitter{} l.Log = testlog.Logger(t, log.LevelDebug) + l.Metr = metrics.NoopMetrics l.RollupConfig = &rollup.Config{ BatchAuthenticatorAddress: common.HexToAddress("0x00000000000000000000000000000000000000aa"), } @@ -222,6 +231,8 @@ func TestFallbackAuth_AuthRevertedRetried(t *testing.T) { // channel manager rewinds and resubmits), rather than being confirmed. func TestFallbackAuth_WindowViolationRetried(t *testing.T) { l := newFallbackAuthSubmitter(t) + metr := &windowExceededSpy{Metricer: metrics.NoopMetrics} + l.Metr = metr txdata := testFallbackTxData(t) candidate := &txmgr.TxCandidate{TxData: []byte("batch-calldata")} @@ -239,6 +250,7 @@ func TestFallbackAuth_WindowViolationRetried(t *testing.T) { got := <-receiptsCh require.Error(t, got.Err) require.Equal(t, txdata.ID().String(), got.ID.id.String()) + require.Equal(t, 1, metr.count, "window violation should record the fallback_auth_window_exceeded metric") } // TestFallbackAuth_WindowBoundaryAccepted pins the inclusive bound of the lookback diff --git a/op-batcher/metrics/metrics.go b/op-batcher/metrics/metrics.go index 93c8efd2808..84057122a0b 100644 --- a/op-batcher/metrics/metrics.go +++ b/op-batcher/metrics/metrics.go @@ -69,6 +69,8 @@ type Metricer interface { RecordBatchDataSizeBytes(daType string, size int) RecordFailoverToEthDA() + RecordFallbackAuthWindowExceeded() + Document() []opmetrics.DocumentedMetric PendingDABytes() float64 @@ -110,9 +112,10 @@ type Metrics struct { channelOutputBytesTotal prometheus.Counter channelQueueLength prometheus.Gauge - batchSentDATypeTotal prometheus.CounterVec - batchStoredDataSizeBytesTotal prometheus.CounterVec - altDaFailoverTotal prometheus.Counter + batchSentDATypeTotal prometheus.CounterVec + batchStoredDataSizeBytesTotal prometheus.CounterVec + altDaFailoverTotal prometheus.Counter + fallbackAuthWindowExceededTotal prometheus.Counter batcherTxEvs opmetrics.EventVec @@ -255,6 +258,11 @@ func NewMetrics(procName string) *Metrics { Name: "alt_da_failover_total", Help: "Total number of batches that could not be stored in AltDA and were sent to L1 instead", }), + fallbackAuthWindowExceededTotal: factory.NewCounter(prometheus.CounterOpts{ + Namespace: ns, + Name: "fallback_auth_window_exceeded_total", + Help: "Total number of fallback-auth submissions dropped because the batch tx landed beyond BatchAuthLookbackWindow blocks after its auth tx", + }), blobUsedBytes: factory.NewHistogram(prometheus.HistogramOpts{ Namespace: ns, Name: "blob_used_bytes", @@ -483,6 +491,10 @@ func (m *Metrics) RecordFailoverToEthDA() { m.altDaFailoverTotal.Inc() } +func (m *Metrics) RecordFallbackAuthWindowExceeded() { + m.fallbackAuthWindowExceededTotal.Inc() +} + func (m *Metrics) RecordChannelQueueLength(len int) { m.channelQueueLength.Set(float64(len)) } diff --git a/op-batcher/metrics/noop.go b/op-batcher/metrics/noop.go index 31002349fe2..b44bb8950f1 100644 --- a/op-batcher/metrics/noop.go +++ b/op-batcher/metrics/noop.go @@ -64,6 +64,7 @@ func (*noopMetrics) RecordBlobUsedBytes(int) {} func (*noopMetrics) RecordBatchDaType(string) {} func (*noopMetrics) RecordBatchDataSizeBytes(string, int) {} func (*noopMetrics) RecordFailoverToEthDA() {} +func (*noopMetrics) RecordFallbackAuthWindowExceeded() {} func (*noopMetrics) StartBalanceMetrics(log.Logger, *ethclient.Client, common.Address) io.Closer { return nil