Skip to content

Commit ee217b3

Browse files
committed
tests/shadow-testing: adopt new relayer flags in follow mode
- relayer.json.template: disable_l2_watcher + chain_nonce_only - 10-follow-up.sh --reset: TRUNCATE pending_transaction (stale rows poison sender nonces and can replay old calldata on a fresh fork) - mark Traps 26/7/9 as fixed upstream; document the new config knobs in follow/GUIDE.md
1 parent 2a2a89f commit ee217b3

5 files changed

Lines changed: 19 additions & 3 deletions

File tree

tests/shadow-testing/docs/COMMON-TROUBLESHOOTING.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ Before executing a single command:
7373
- **Rule**: Use **internal** L2 RPC proxies only.
7474

7575
### Trap 7: Relayer Nonce Desync
76+
77+
> **Fixed upstream / harness**: the relayer sender config now supports `chain_nonce_only` (default false), which initializes the nonce from the chain pending nonce only, ignoring `pending_transaction` — the shadow relayer config template sets it. Additionally `10-follow-up.sh --reset` now TRUNCATEs `pending_transaction` (the rows are not chain/fork-scoped and can also replay old calldata onto a fresh fork). The manual fix below is only needed if you run a relayer without those.
78+
7679
- **Symptom**: Tx sent but never mined; `eth_getTransactionReceipt` returns null forever.
7780
- **Cause**: `pending_transaction` table retains nonces from previous runs that were never confirmed. Relayer initializes nonce from `maxDbNonce + 1`, which is ahead of the on-chain nonce.
7881
- **Rule**: After any relayer crash or Anvil restart:
@@ -82,6 +85,9 @@ Before executing a single command:
8285
Then restart the relayer.
8386

8487
### Trap 9: Anvil `eth_estimateGas` Rejects Fee Caps
88+
89+
> **Fixed upstream**: `rollup/internal/controller/sender/estimategas.go` now sends an explicit non-zero gas cap in the estimation `CallMsg`, so Anvil no longer rejects fee-capped estimate calls. This entry is kept for reference when running older relayer builds.
90+
8591
- **Symptom**: `failed to get fee data, err: Out of gas: gas required exceeds allowance: 0`.
8692
- **Cause**: Anvil's `eth_estimateGas` fails when `CallMsg` has `GasFeeCap`/`GasTipCap` set but `Gas` is 0 (Go Ethereum client's default).
8793
- **Rule**: If you hit this on a shadow fork, the correct fix belongs in the upstream `rollup/internal/controller/sender/estimategas.go` (do not maintain a local patch in this branch). Verify with the latest `develop` code and, if still present, fix it there so all shadow tests benefit.

tests/shadow-testing/follow/GUIDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ One command brings up the entire follow-mode stack (`scripts/10-follow-up.sh`):
6868
3. **Verifier wrapper** — deploy/register the `ZkEvmVerifierPostFeynman` wrapper matching the guest under test (manual procedure: "Real Verifier Deployment" in the [Snapshot Replay Mode Guide](../snapshot/GUIDE.md#real-verifier-deployment)).
6969
4. **Coordinator** — start `coordinator_api` + `coordinator_cron` against the shadow DB.
7070
5. **Provers** — start one prover per GPU.
71-
6. **Relayer** — start the rollup relayer with local proposers **disabled** (`l2_config.{chunk,batch,bundle}_proposer_config.disable = true`): the relayer then only commits/finalizes what the DB contains, instead of synthesizing bundles at an unrealistic rate.
71+
6. **Relayer** — start the rollup relayer with local proposers **disabled** (`l2_config.{chunk,batch,bundle}_proposer_config.disable = true`): the relayer then only commits/finalizes what the DB contains, instead of synthesizing bundles at an unrealistic rate. The shadow relayer config template (`lib/configs/relayer.json.template`) additionally sets `l2_config.disable_l2_watcher = true` (the poll sync, not the relayer's L2 watcher, keeps `l2_block` populated — Trap 26) and `sender_config.chain_nonce_only = true` (sender nonces initialize from the fork, never from stale `pending_transaction` rows — Trap 7/27).
7272
7. **Background daemons** — poll-sync, sweeper, hourly monitor (plain background processes with pidfiles in `.work/`; no agent/session cron is required).
7373

7474
The run window is recorded in `.work/follow-run.env` (`SHADOW_REPORT_START`, `FOLLOW_RUN_HOURS=48`). Tear down with `make follow-stop` (`scripts/11-follow-stop.sh`, supports `--keep-anvil`).

tests/shadow-testing/follow/TROUBLESHOOTING.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ see also the [Follow Mode Guide](./GUIDE.md). Trap numbers are stable across the
7878

7979
### Trap 26: Relayer L2 Watcher Genesis-Crawls an Empty `l2_block` [follow mode]
8080

81+
> **Fixed upstream**: the relayer now supports `l2_config.disable_l2_watcher` (default false = production behavior unchanged), which skips the watcher loop entirely. The shadow relayer config template (`lib/configs/relayer.json.template`) sets it — in follow mode the poll sync is what keeps `l2_block` populated for newly synced chunks, so the watcher is redundant. The harness ordering below remains as defense-in-depth.
82+
8183
- **Symptom**: `l2_block` fills with rows numbered 1, 2, 3, … at ~30–60 blocks/s, `chunk_hash = NULL`, `withdraw_root = 0x0000…` — a full L2 history crawl that would take days and tens of GB, while relayer logs show `retrieved block height=…` climbing from genesis.
8284
- **Cause**: `rollup_relayer` always runs an L2 watcher loop (`rollup/cmd/rollup_relayer/app/app.go``TryFetchRunningMissingBlocks` every 2 s) that fetches **all** blocks from `MAX(l2_block.number)+1` up to the L2 tip — reading the max **once** at loop entry. If the relayer is alive while `--reset` TRUNCATEs `l2_block` (or the table is empty for any other reason), the watcher sees `MAX = 0` and starts crawling from block 1; the in-flight call keeps going for days even after the baseline repopulates the window.
8385
- **Fix (in place)**: `10-follow-up.sh --reset` now runs `11-follow-stop.sh` **before** the TRUNCATE, so no writer survives into the reset. Never TRUNCATE `l2_block` (or let it go empty) while a relayer is running.

tests/shadow-testing/follow/scripts/10-follow-up.sh

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,16 @@ if $RESET_DB; then
178178
if ! $DRY_RUN; then
179179
bash "${SCRIPT_DIR}/11-follow-stop.sh" || log_warn " 11-follow-stop returned non-zero (continuing)"
180180
fi
181-
log_warn " --reset: truncating chunk/batch/bundle/l2_block/l1_message"
181+
log_warn " --reset: truncating chunk/batch/bundle/l2_block/l1_message/pending_transaction"
182182
if ! $DRY_RUN; then
183183
psql "$SHADOW_DSN" -Atq --set ON_ERROR_STOP=1 -c "TRUNCATE chunk, batch, bundle, l2_block, l1_message" >/dev/null \
184184
|| { log_error "TRUNCATE failed — aborting before baseline"; exit 1; }
185+
# Trap 7/27: pending_transaction rows are not chain/fork-scoped. Stale
186+
# rows from a previous run poison the relayer sender's nonce
187+
# (initializeNonce = max(db_max+1, chain_nonce)) and can replay old
188+
# calldata onto the fresh fork. Wipe them on every reset.
189+
psql "$SHADOW_DSN" -Atq --set ON_ERROR_STOP=1 -c "TRUNCATE pending_transaction" >/dev/null \
190+
|| { log_error "TRUNCATE pending_transaction failed — aborting"; exit 1; }
185191
# Trap 21: wipe prover-local proof caches; they hold proofs from the
186192
# previous run/circuit version and get replayed as VData mismatches.
187193
rm -rf "${WORK_DIR}"/prover-*/db

tests/shadow-testing/lib/configs/relayer.json.template

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"l2_config": {
33
"endpoint": "{{L2_ENDPOINT}}",
4+
"disable_l2_watcher": true,
45
"relayer_config": {
56
"sender_config": {
67
"endpoint": "{{ANVIL_RPC}}",
@@ -16,7 +17,8 @@
1617
"min_gas_tip": 0,
1718
"check_pending_time": 60,
1819
"max_pending_blob_txs": 3,
19-
"fusaka_timestamp": 9999999999
20+
"fusaka_timestamp": 9999999999,
21+
"chain_nonce_only": true
2022
},
2123
"commit_sender_signer_config": {
2224
"signer_type": "PrivateKey",

0 commit comments

Comments
 (0)