feat(tests): opt-in background activity mode for chains [concept]#22
Draft
antonbaliasnikov wants to merge 6 commits into
Draft
feat(tests): opt-in background activity mode for chains [concept]#22antonbaliasnikov wants to merge 6 commits into
antonbaliasnikov wants to merge 6 commits into
Conversation
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>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add a "noisy" mode alongside the default silent mode: when enabled, a chain continuously fires L2 self-transfers and L1→L2 deposits in the background while a test runs, so tests exercise a live, moving chain instead of an idle one — surfacing ordering/interleaving bugs across the sequencer, L1 watcher, priority queue and batch pipeline. New `tests/src/activity.rs` owns the noise: - private `ACTIVITY_WALLET_KEYS` pool (Anvil HD accounts #10-#19), funded on L1 via `--accounts 20` and with a small L2 gas balance in the fixture cache-miss path so the deposits land in the cached snapshot - `ActivityConfig` (per-flow `Option<Duration>`; `transfers_only`/ `deposits_only` presets) - `ActivityHandle` with `pause`/`resume`/`stop` and a single `stats()` accessor returning an `ActivityStats` near-snapshot (independent relaxed loads over one shared `Arc`, not an atomic read) - crash-safe flow loops with a bounded error budget and start-to-start pacing Wiring: - `Chain::start_background_activity` with a double-start guard and a per-chain dedicated L1 deposit wallet (no nonce races) - `Ecosystem::start_background_activity` fan-out with a chain-count guard; waits for each enabled flow's first successful tick so a fixture-driven test can't pass against a silently-dead noise loop - `ecosystem` fixture gains an `activity: Option<ActivityConfig>` param that auto-starts noise from setup Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
antonbaliasnikov
force-pushed
the
aba-background-activity-mode
branch
from
June 22, 2026 19:59
5be1e3b to
38e4a5b
Compare
Replace the original background-activity design (10-wallet round-robin
pool, raw ActivityStats polling, ping/self_transfer duplication) with a
simpler, verdict-based model owned by Chain.
- Per-flow config: ActivityConfig { l2_transfers, l1_deposits } where
each flow is Option<FlowConfig { interval, target }>. None switches a
flow off, giving transfers-only / deposits-only / both. Target is
Count(n) | Duration(d) | Unbounded.
- Two dedicated wallets per chain (transfer = pool[2i], deposit =
pool[2i+1]), so neither flow shares a nonce sequence. Pool serves
max_activity_chains = pool/2 chains. Index derived from chain position;
test authors never set it.
- Single finalized-on-L1 verdict via ActivityReport: transfers tracked by
hash (all must finalize with success receipts); deposits via the
deposit wallet's finalized L2 balance delta >= count*amount (>= because
the deposit also collects its own gas refund as refundRecipient).
- Activity is part of Chain: chain.start_activity / pause_activity /
resume_activity / finish_activity (bounded) / stop_activity
(unbounded/early). Chain owns the run in a Mutex<Option<ActivityHandle>>
that doubles as the single-run guard. Ecosystem no longer keeps an
activity_handles field — chains drop before servers and abort their
tasks at teardown.
- ping() and the transfer loop now share one self_transfer() primitive.
- Fund only each chain's transfer wallet on L2 (deposit wallet never
sends L2 txs).
- Collapse the integration tests to one feature-demo test that runs
short Count/Duration activities and asserts each reaches a passing
verdict.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Concept — for review, not merge
This is a concept PR exploring a "noisy" run mode for test chains, opened in draft. It's working and fully tested, but the API surface is up for discussion before we commit to it.
Motivation
Today every chain runs in silent mode: after setup it sits idle until a test explicitly calls
ping()/send_tx()/transfer(). Tests therefore always run against a perfectly still chain, which hides race conditions and ordering bugs between the sequencer, L1 watcher, priority queue, and batch pipeline.This adds an opt-in background activity mode: a chain continuously fires L2 self-transfers and L1→L2 deposits in the background while a test runs, so the test executes inside a live, moving chain. Inspired by the production
matter-labs/watchdogservice (flow-per-activity-type, crash-safe restart, start-to-start pacing).What's here
New
tests/src/activity.rsowns the noise:ACTIVITY_WALLET_KEYS— a private pool (Anvil HD accounts feat: test proper migration support #10–fix: enforce Anvil block gas limit to catch oversized server blocks #19), separate from test wallets so the two never share nonces. Funded on L1 via--accounts 20and on L2 during the fixture's cache-miss path, so the deposits land in the cached snapshot (zero cost on cache hit).ActivityConfig— per-flowOption<Duration>(None= disabled).transfers_only()/deposits_only()presets for targeted race tests.ActivityHandle—pause()/resume()/stop().await/is_alive()plustxs_sent()/deposits_sent()counters.MAX_CONSECUTIVE_ERRORS), then the task sets afailedflag and exits sois_alive()flips (a broken loop is detectable, not silent). Start-to-start interval pacing avoids drift under slow RPC.Wiring:
Chain::start_background_activity(config)— double-start guard (panics if already running) + per-chain dedicated L1 deposit wallet (chain_index % pool_len), so no two chains share an L1 signer.Ecosystem::start_background_activity(config)— fan-out across all chains, panics ifchain_count > pool_len.ecosystemfixture gainsactivity: Option<ActivityConfig>that auto-starts noise from setup.Usage
Semantics worth a look during review
pause()stops new submissions; an in-flight L1→L2 deposit may still land. Not an exact quiesce.stop().awaitis the only restart-safe teardown;Dropaborts without awaiting.txs_sentcounts RPC-accepted hashes (mempool),deposits_sentcounts L1-confirmed deposits — neither implies mining/finalization.Testing
chain_executes_a_batch,two_chains_settle_on_l1, and the v30→v31 upgrade test — no regressions.Possible follow-ups (out of scope here)
lib/activitycrate if we ever want to replace the TS watchdog with a Rust one.🤖 Generated with Claude Code