Skip to content

Commit aa725dc

Browse files
authored
fix(e2e): give token_bridge_tutorial its own L1 account to avoid sequencer nonce race (#24386)
## Root cause `e2e_token_bridge_tutorial_test` flakes with `WaitForTransactionReceiptTimeoutError: Timed out while waiting for transaction … to be confirmed` ([example](http://ci.aztec-labs.com/1643e817d7242e0e)). It is **not** caused by #24378 — that PR only touches `forge_broadcast.js` (the L1 *contract deploy*), which succeeds in the failing run; the timeout is ~3.5 min later on one of the test's own L1 txs. The test runs against `aztec start --local-network`, whose `AutomineSequencer` continuously publishes checkpoint txs to L1. In `local-network.ts` the sequencer-publisher and validator keys are derived from `DefaultMnemonic` (`'test test … junk'`) at **address index 0** — `0xf39Fd6…` (visible as the publisher in the log). The test's L1 client was created with the **same** mnemonic and the **same** default index 0: ```ts const l1Client = createExtendedL1Client(ETHEREUM_HOSTS.split(','), MNEMONIC); // → account index 0 ``` So the test and the node's sequencer send L1 txs from one account, sharing a single nonce sequence. Against an automining anvil they race: a test tx can land with a nonce the sequencer just consumed (dropped / "already known"), or with a future-nonce gap that automine won't mine until the gap fills. Either way the tx gets a hash but never confirms, and viem's per-tx confirmation timeout fires. This is intermittent because it only bites when a test tx and a sequencer publish overlap. ## Fix Derive the test's L1 client from a **different** address index so its nonce space is independent of the sequencer's: ```ts const l1Client = createExtendedL1Client(ETHEREUM_HOSTS.split(','), mnemonicToAccount(MNEMONIC, { addressIndex: 1 })); ``` Index 1 (`0x70997970…`) is funded by anvil's default mnemonic and is unused by the local-network node (publisher/validator = index 0; index 2 is the prover and 3+ are attesters by the existing `setup.ts` / `setup_p2p_test.ts` convention, none of which run in local-network). The test is fully self-contained on its own L1 account — it deploys and owns the `TestERC20`, `FeeAssetHandler` and `TokenPortal`, and bridges to/from `l1Client.account.address` — so nothing requires it to be account 0. All of the test's L1 txs (including the `L1TokenManager` / `L1TokenPortalManager`, built from `l1Client`) now go through index 1. ## Verification This is an `compose` e2e test that needs docker + a full network; the container here is a source-only checkout (no `node_modules`, no docker), so I could not run the test or `./bootstrap.sh ci` locally — flagging that explicitly per the repo's red/green policy. The fix is verified by analysis: the timed-out tx is one of the test's own L1 txs, the shared-account nonce race is the established cause of this exact viem symptom, and account index 0 vs 1 are the well-known distinct anvil accounts (idx 0 = `0xf39Fd6…`, the publisher in the log; idx 1 = `0x70997970…`). ## Relationship to #24385 #24385 broadened this test's `.test_patterns.yml` flake pattern to keep CI from going red on the residual flake. This PR removes the underlying cause. The flake entry can stay as a safety net, or be narrowed back to the jest-timeout-only form once this has soaked — happy to follow up either way. --- *Created by [claudebox](https://claudebox.work/v2/sessions/c01cbe3dd422bf00) · group: `slackbot`*
1 parent 1ac6046 commit aa725dc

1 file changed

Lines changed: 7 additions & 1 deletion

File tree

yarn-project/end-to-end/src/composed/e2e_token_bridge_tutorial_test.test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,19 @@ import { AuthRegistryArtifact, getStandardAuthRegistry } from '@aztec/standard-c
2525
import { registerInitialLocalNetworkAccountsInWallet } from '@aztec/wallets/testing';
2626

2727
import { getContract } from 'viem';
28+
import { mnemonicToAccount } from 'viem/accounts';
2829

2930
import { TestWallet } from '../test-wallet/test_wallet.js';
3031

3132
const MNEMONIC = 'test test test test test test test test test test test junk';
3233
const { ETHEREUM_HOSTS = 'http://localhost:8545' } = process.env;
3334

34-
const l1Client = createExtendedL1Client(ETHEREUM_HOSTS.split(','), MNEMONIC);
35+
// The local-network sequencer publishes its checkpoint txs to L1 from the default mnemonic's account
36+
// 0 (the account viem hands out by default). Sharing that account here would interleave this test's
37+
// L1 txs with the sequencer's on a single nonce sequence, so a deploy/bridge tx can be stranded in
38+
// anvil's pool and never confirm (surfacing as a WaitForTransactionReceiptTimeoutError). Derive this
39+
// client from a different index to give the test an independent L1 nonce space.
40+
const l1Client = createExtendedL1Client(ETHEREUM_HOSTS.split(','), mnemonicToAccount(MNEMONIC, { addressIndex: 1 }));
3541
const ownerEthAddress = l1Client.account.address;
3642

3743
const MINT_AMOUNT = BigInt(1e15);

0 commit comments

Comments
 (0)