Skip to content

feat(l1_sender): replace L1SenderLoop with Submitter + Watcher tasks#1105

Open
Artemka374-claude wants to merge 11 commits intomatter-labs:mainfrom
Artemka374-claude:feat/l1-sender-task-decomp
Open

feat(l1_sender): replace L1SenderLoop with Submitter + Watcher tasks#1105
Artemka374-claude wants to merge 11 commits intomatter-labs:mainfrom
Artemka374-claude:feat/l1-sender-task-decomp

Conversation

@Artemka374-claude
Copy link
Copy Markdown
Contributor

Summary

  • Replaces the single-loop L1SenderLoop with two independent async tasks: Submitter (provider interaction, fee estimation, tx submission) and Watcher (FuturesOrdered concurrent receipt polling, downstream forwarding)
  • Eliminates phase-blocking: a submission error no longer prevents receipt checking for already in-flight txs; a receipt timeout no longer prevents forwarding already-confirmed txs
  • Adds concurrent receipt polling via FuturesOrdered (previously sequential with first_mut())
  • Raises max_priority_fee_per_gas default from 1 gwei to 10 gwei

Design doc

docs/superpowers/specs/2026-03-27-l1-sender-task-decomposition.md

Testing

Existing integration tests cover the full commit/prove/execute pipeline. Integration test failures on this branch pre-exist on the base branch (feat/l1-sender-error-handling) and are caused by an anvil JSON parsing incompatibility unrelated to this change.

No new tests added — the behaviour is already covered by existing integration tests.

🤖 Generated with Claude Code

Artemka374 and others added 11 commits March 26, 2026 14:20
Replace the monolithic `run_l1_sender` function with `L1SenderLoop`,
a phase-based struct that categorizes all errors and handles them
appropriately instead of crashing the binary.

Error categories:
- Transient (RPC timeouts, rate limits) → exponential backoff, retry
- Recoverable (GasBlocked, BlobFeeBlocked, TxTimeout, NonceTooLow) →
  wait for external condition, retry with 30s sleep
- Fatal (tx revert, data corruption, channel closed) → crash as before

Key changes:
- `L1SenderLoop` tracks three collections: `pending_commands`,
  `in_flight`, and `completed`. Commands are never lost on errors —
  partial send progress survives transient RPC failures.
- Gas and blob fee caps are checked before any tx is submitted.
  Exceeding the cap now returns `GasBlocked`/`BlobFeeBlocked` instead
  of warning and sending a doomed tx.
- Pending block fallback: replace `.expect("no pending block")` with
  a fallback to `BlockId::latest()` to fix the known Infura crash.
- Metrics: add `GasBlocked`, `BlobFeeBlocked`, `TransientBackoff`
  states; add `transient_errors` counter and `recoverable_errors`
  labeled counter. Make `report_tx_receipt` / `report_blob_base_fee` /
  `report_l1_eip_1559_estimation` non-fatal (log on parse error).
- Informational calls (`get_balance`, `get_transaction_count`) after
  inclusion are now non-fatal — log warning and continue.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
These docs were added for planning purposes and belong in the docs repo,
not in the server codebase.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wire the Submitter and Watcher tasks together in lib.rs under
tokio::try_join!, removing the old sequential L1SenderLoop struct.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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