Skip to content

feat(loadtest): nonce-too-low fast-forward and --reverse-nonce-order - #997

Open
praetoriansentry wants to merge 3 commits into
mainfrom
feat/loadtest-nonce-too-low-fastforward
Open

feat(loadtest): nonce-too-low fast-forward and --reverse-nonce-order#997
praetoriansentry wants to merge 3 commits into
mainfrom
feat/loadtest-nonce-too-low-fastforward

Conversation

@praetoriansentry

Copy link
Copy Markdown
Member

Description

Two nonce-management features for polycli loadtest:

1. Fast-forward account nonce on nonce-too-low errors

When a send fails with a geth-style nonce too low: next nonce X, tx nonce Y error, the account's local nonce is fast-forwarded to the next nonce value parsed from the message, instead of grinding through stale nonces one failed transaction at a time. Only this exact message format is parsed; anything else keeps the existing increment behavior (no RefreshNonce fallback). The nonce is never rewound, so stale error messages from concurrent in-flight transactions can't undo progress, and reusable nonces below the new value are dropped since the network already considers them consumed.

2. --reverse-nonce-order flag

Each sending account computes its planned nonce range from the test parameters (concurrency × requests / number of accounts) and sends transactions in descending nonce order, from the top of the range down to its current nonce. All txs except the last per account land in the queued pool, and the final tx at the base nonce promotes the whole chain to pending at once — useful for stressing queued vs pending txpool dynamics.

Constraints enforced at startup, before any funding or sending:

  • total requests must divide evenly across sending accounts
  • requires --fire-and-forget (waiting for receipts of queued txs would deadlock)
  • incompatible with --wait-for-receipt, --eth-call-only, --duplicate-nonce-rate, and --adaptive-rate-limit (its pending-tx probe assumes ascending nonces)

The nonce-too-low fast-forward is skipped in reverse mode since jumping the counter forward would corrupt the descending sequence. Failed nonces are re-sent as-is via the existing reusable-nonce queue without moving the descending counter. --time-limit is allowed but logs a warning, since stopping early strands queued transactions.

No breaking changes; both features are additive and default-off.

Jira / Linear Tickets

  • N/A

Testing

  • go test -race ./loadtest/... — new unit tests cover the nonce-too-low regex parsing, FastForwardNonce (fast-forward, no-rewind, reusable-nonce pruning), PrepareReverseNonces (offsets, overflow, not-ready), reverse round-robin Next() sequencing and exhaustion, reusable-nonce retry in reverse mode, the per-account divisibility math, and all flag-combination validations
  • make build, go vet, shadow pass; docs regenerated via docutil
  • Smoke-tested the built binary: --reverse-nonce-order without --fire-and-forget and with --adaptive-rate-limit are rejected at startup with clear errors

🤖 Generated with Claude Code

praetoriansentry and others added 3 commits August 24, 2026 08:35
When a send fails with a geth-style "nonce too low: next nonce X, tx
nonce Y" error, parse the next nonce from the message and fast-forward
the account's local nonce to it instead of grinding through stale
nonces one failed transaction at a time. The nonce is never rewound, so
stale error messages can't undo progress made by concurrent in-flight
transactions, and reusable nonces below the new value are dropped. If
the message doesn't match this exact format, behavior is unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… txpool dynamics

Each sending account computes its planned nonce range from the test
parameters (concurrency * requests / number of accounts) and sends
transactions in descending nonce order, from the top of the range down
to its current nonce. All txs except the last per account land in the
queued pool, and the final tx at the base nonce promotes the whole
chain to pending at once.

Constraints enforced at startup:
- total requests must divide evenly across sending accounts
- requires --fire-and-forget (waiting for receipts of queued txs would
  deadlock)
- incompatible with --wait-for-receipt, --eth-call-only,
  --duplicate-nonce-rate, and --adaptive-rate-limit (its pending-tx
  probe assumes ascending nonces)

The nonce-too-low fast-forward is skipped in reverse mode since jumping
the counter forward would corrupt the descending sequence. Failed
nonces are re-sent as-is via the existing reusable-nonce queue without
moving the descending counter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@praetoriansentry
praetoriansentry requested a review from a team August 24, 2026 14:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants