Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

A dropped transaction can leave a nonce gap that blocks every later transaction

Aperta
#5,678 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 2 giorni

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
35/100
Tipo di issue
Bug
Chiarezza
Abbastanza chiara
Stato di attività
Attiva
Stack tecnologico
go
Ambito
backend, databases

Direzione di ricerca

Start by tracing nextNonce, SendWithRetry, resumeRetryTransactions, and waitForPendingRetry in the transaction service, then inspect the retry session state and nonce tests. Reproduce the case where a retry session ends without a receipt and its final transaction disappears from the mempool. Done means the missing nonce can be recovered and later transactions can proceed without relying on manual cancellation or eventual eviction.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

A dropped transaction can leave a nonce gap that blocks every later transaction

Summary

The transaction service never re-sends a nonce once its transaction has dropped out of the mempools. If a later nonce has already been handed out by then, the account gets a nonce gap at N. Transactions N+1, N+2, … cannot execute, and every later transaction queues behind them: redistribution commit/reveal/claim, postage, cashout, staking. Nothing in the node closes the gap on its own.

SendWithRetry (#5464) closes some paths to the gap, but its nonce reservation makes the gap easier to reach and harder to clear by itself.

Background: nonces must be contiguous

To simplify: mempool has pending transactions and queued transactions. If there is nonce gap on N, all transactions will be queued.

A pending transaction can still disappear from a pool:

  • it is discarded as the cheapest one when the pool is full, especially once maxFeePerGas is below the base fee;
  • the account balance no longer covers it;
  • the RPC node restarts without a journal;
  • the RPC sits behind a load balancer and the transaction never reached the other backends.
The problem on master

nextNonce returns max(PendingNonceAt - 1, nonces of stored pending txs that TransactionByHash still finds) + 1.

  • Tx N and Tx N+1 were sent, and N disappears later. , N+1 sits in the queue and TransactionByHash still finds it, so the next nonce is N+2. Nothing sends N again:
    • Send does not rebroadcast;
    • the monitor only reads BlockNumber, TransactionReceipt and NonceAt. While N is unconsumed, none of its signals can fire: no receipt, no cancellation (it needs nonce < NonceAt(head - cancellationDepth)), no nonce-mined event. Every watch on N and above waits until shutdown;
    • a restart does not help, because waitForAllPendingTx drops NotFound hashes and resends nothing.

The account recovers only after the RPC evicts the queued transactions (about 3h on geth, depends on the client) or an operator cancels N manually.

How SendWithRetry changes the picture

It reduces the gap in some cases:

  • an active session rebroadcasts N every txRetryDelay, so if N drops out mid-session it comes back within one attempt;
  • on restart, resumeRetryTransactions resumes every session whose nonce is not confirmed and rebroadcasts it. For retry transactions a restart now clears the gap, which it does not do on master.

It amplifies the gap in others:

  1. #5464 makes nextNonce reserve the nonces held in transaction_retry_* state. This stops a live session's nonce from being handed out again when the RPC returns NotFound for its hash. The reservation also holds for sessions that ended without a receipt (ErrAllAttemptsExhausted, ErrTxMaxPriceExceeded). Such sessions wait in waitForPendingRetry without a timeout and do not rebroadcast. If their last transaction drops out of the pools:

    • the master path that closes the gap by itself (reuse N) is gone, so the very next transaction creates the gap; no N+1 sent earlier is needed;
    • eviction no longer clears it: after the queued transactions are evicted, nextNonce still skips N.
  2. Sessions end without a receipt because their fees fell behind the market, which is especially true for ErrTxMaxPriceExceeded. Their last transaction is therefore the one most likely to be discarded.

  3. A full node sends redistribution transactions every round, so a new transaction before a restart is close to certain.

Lingua principale
Go
Stelle
1.5k
Fork
390
Merge medio
3g 58m
PR unite (30g)
25

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di ethersphere/bee

Tutte le issue di ethersphere/bee

Issue simili

Altre issue su Go

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.