Skip to content

Commit 4bd6fa5

Browse files
piersylukeiannucci
authored andcommitted
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.
1 parent 9eab3cb commit 4bd6fa5

2 files changed

Lines changed: 65 additions & 3 deletions

File tree

op-batcher/batcher/fallback_auth.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ func computeCommitment(candidate *txmgr.TxCandidate) ([32]byte, error) {
4343
// separate signature is needed — the L1 transaction is already signed by the TxManager's key.
4444
func (l *BatchSubmitter) sendTxWithFallbackAuth(txdata txData, isCancel bool, candidate *txmgr.TxCandidate, queue TxSender[txRef], receiptsCh chan txmgr.TxReceipt[txRef]) {
4545
transactionReference := newTxRef(txdata, isCancel)
46+
// The auth tx shares the batch txdata's identity (so a failure requeues the right frames)
47+
// but is always a calldata tx. Auth failures must carry its real type: an ErrAlreadyReserved
48+
// receipt labeled with the batch's blob type would make cancelBlockingTx cancel the wrong
49+
// pool, leaving the reserving tx stuck.
50+
authReference := transactionReference
51+
authReference.isBlob = false
52+
authReference.daType = DaTypeCalldata
4653
l.Log.Debug("Sending fallback-authenticated L1 transaction", "txRef", transactionReference)
4754

4855
commitment, err := computeCommitment(candidate)
@@ -88,13 +95,13 @@ func (l *BatchSubmitter) sendTxWithFallbackAuth(txdata txData, isCancel bool, ca
8895
// Submit the auth tx and wait for its receipt, then send the batch tx. Each Send
8996
// blocks here when the queue is at its MaxPendingTransactions limit.
9097
authReceiptCh := make(chan txmgr.TxReceipt[txRef], 1)
91-
queue.Send(transactionReference, verifyCandidate, authReceiptCh)
98+
queue.Send(authReference, verifyCandidate, authReceiptCh)
9299
authResult := <-authReceiptCh
93100

94101
if authResult.Err != nil {
95102
l.Log.Error("Failed to send fallback authenticateBatchInfo transaction", "txRef", transactionReference, "err", authResult.Err)
96103
receiptsCh <- txmgr.TxReceipt[txRef]{
97-
ID: transactionReference,
104+
ID: authReference,
98105
Err: fmt.Errorf("failed to send fallback authenticateBatchInfo transaction: %w", authResult.Err),
99106
}
100107
return
@@ -108,7 +115,7 @@ func (l *BatchSubmitter) sendTxWithFallbackAuth(txdata txData, isCancel bool, ca
108115
if authResult.Receipt.Status != types.ReceiptStatusSuccessful {
109116
l.Log.Error("Fallback authenticateBatchInfo transaction reverted", "txRef", transactionReference, "txHash", authResult.Receipt.TxHash)
110117
receiptsCh <- txmgr.TxReceipt[txRef]{
111-
ID: transactionReference,
118+
ID: authReference,
112119
Err: fmt.Errorf("fallback authenticateBatchInfo transaction reverted: %s", authResult.Receipt.TxHash),
113120
}
114121
return

op-batcher/batcher/fallback_auth_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,61 @@ func TestFallbackAuth_AuthFailureRetried(t *testing.T) {
117117
require.Len(t, queue.sends, 1)
118118
}
119119

120+
// TestFallbackAuth_AuthFailureTxRefType verifies that an auth-tx failure is
121+
// reported under a calldata-typed txRef even when the batch txdata is blob.
122+
// The auth tx is always calldata; if its ErrAlreadyReserved failure were
123+
// labeled with the batch's blob type, cancelBlockingTx would send a calldata
124+
// cancel against a blobpool reservation, which is rejected the same way,
125+
// looping forever without ever displacing the stuck blob tx.
126+
func TestFallbackAuth_AuthFailureTxRefType(t *testing.T) {
127+
l := newFallbackAuthSubmitter(t)
128+
txdata := testFallbackTxData(t)
129+
txdata.daType = DaTypeBlob
130+
candidate := &txmgr.TxCandidate{TxData: []byte("batch-calldata")}
131+
132+
queue := &fakeTxSender{
133+
responses: []txmgr.TxReceipt[txRef]{
134+
{Err: errSendFailed}, // auth fails. No batch response, it must never be sent
135+
},
136+
}
137+
receiptsCh := make(chan txmgr.TxReceipt[txRef], 1)
138+
139+
l.sendTxWithFallbackAuth(txdata, false, candidate, queue, receiptsCh)
140+
141+
got := <-receiptsCh
142+
require.Error(t, got.Err)
143+
require.Equal(t, txdata.ID().String(), got.ID.id.String())
144+
require.Len(t, queue.sends, 1)
145+
require.False(t, got.ID.isBlob)
146+
require.Equal(t, DaTypeCalldata, got.ID.daType)
147+
}
148+
149+
// TestFallbackAuth_BatchFailureTxRefType verifies the converse: a batch-tx
150+
// failure keeps the batch txdata's own type on the forwarded receipt.
151+
func TestFallbackAuth_BatchFailureTxRefType(t *testing.T) {
152+
l := newFallbackAuthSubmitter(t)
153+
txdata := testFallbackTxData(t)
154+
txdata.daType = DaTypeBlob
155+
candidate := &txmgr.TxCandidate{TxData: []byte("batch-calldata")}
156+
157+
queue := &fakeTxSender{
158+
responses: []txmgr.TxReceipt[txRef]{
159+
{Receipt: receiptWithBlock(100)}, // auth lands
160+
{Err: errSendFailed}, // batch fails
161+
},
162+
}
163+
receiptsCh := make(chan txmgr.TxReceipt[txRef], 1)
164+
165+
l.sendTxWithFallbackAuth(txdata, false, candidate, queue, receiptsCh)
166+
167+
got := <-receiptsCh
168+
require.Error(t, got.Err)
169+
require.Equal(t, txdata.ID().String(), got.ID.id.String())
170+
require.Len(t, queue.sends, 2)
171+
require.True(t, got.ID.isBlob)
172+
require.Equal(t, DaTypeBlob, got.ID.daType)
173+
}
174+
120175
func TestFallbackAuth_BatchFailureRetried(t *testing.T) {
121176
l := newFallbackAuthSubmitter(t)
122177
txdata := testFallbackTxData(t)

0 commit comments

Comments
 (0)