Skip to content

Commit 1476179

Browse files
authored
test(e2e): instrument and diagnose bot suite setup cost (#24534)
## What / why Round-4 e2e speedup, PR 3 of the effort. The `single-node/bot` suite's file-level `beforeAll` costs ~178s on CI with 97% untagged, and the residual proven-chain waits in the `private_payments`/`failures` fees suites (~32s/shard) were also invisible. This PR instruments both so the cost is attributable, and diagnoses the bot residual. Spans are pure passthrough when `TEST_TIMING_FILE` is unset (see `fixtures/timing.ts`), so this is zero behavior change for normal runs and CI. ## Commit - `test(e2e): instrument bot suite setup and fees proven-chain residuals` - Bot suite (`single-node/bot/bot.test.ts`): `setup:wallet` around `EmbeddedWallet.create`, `wallet:create` around `createSchnorrInitializerlessAccount`, and `setup:bot` around the four nested `describe` beforeAll hooks (`Bot.create` / `AmmBot.create` / `CrossChainBot.create` / `BotStore`). - Fees harness (`single-node/fees`): `wait:proven-checkpoint` around `catchUpProvenChain`'s poll loop, and `warp:proven-checkpoint-epoch` around `advanceToNextEpoch` via a new instrumented `FeesTest.advanceToNextEpoch()` wrapper; `waitForEpochProven` and the direct call sites in `failures`/`private_payments` now route through it. - Reuses existing tags where the concept matches (`wallet:create` is already what `createFundedInitializerlessAccounts` fires; `warp:proven-checkpoint-epoch` is already what `advanceToNextEpoch` fires in `block-production/setup.ts`) rather than minting near-duplicates. ## Diagnosis The timing environment (`shared/timing_env.mjs`) folds *every* `beforeAll` in a file — the file-level one plus each nested `describe`'s — into a single suite-scoped `beforeHooksMs`, and every span fired during any beforeAll lands on that same suite line. The shortlist read the whole number as the file-level hook and, seeing only `setup:env:*` tagged, attributed the rest to the one visible untagged file-level call (`createSchnorrInitializerlessAccount`). It is actually the nested hooks. Local read (`TEST_TIMING_SPANS=1`, `PIPELINING_SETUP_OPTS` = 12s L2 slots, production sequencer, fake prover), suite `beforeHooksMs = 153,733 ms`: - `setup:env:*` (file-level `setup()`): ~4.6s — already tagged - `setup:wallet` (`EmbeddedWallet.create`, ephemeral): **137 ms** — the PXE has `autoSync:false`, no genesis walk - `wallet:create` (`createSchnorrInitializerlessAccount`): **69 ms** — initializerless, no deploy tx, as designed - `setup:bot` (4 nested hooks): **149,582 ms = 97.3%** of the file's beforeAll - transaction-bot `Bot.create`: 32.2s (token deploy class+instance, then private+public mint) - bridge-resume `new BotStore(...)`: 0.9 ms - amm-bot `AmmBot.create`: 73.9s (deploys 4 contracts + set_minter + mint + add_liquidity) - cross-chain-bot `CrossChainBot.create`: 43.5s (TestContract deploy + seed 2 L1→L2 msgs + wait ready) **Root cause: structural, not a bug.** The bot suite runs the production Sequencer to exercise CHECKPOINTED/PROPOSED follow modes and L1 fee-juice bridging, so each `Bot.create` deploys real contracts and mints serially at slot cadence (`bot/src/factory.ts`). The two calls the shortlist suspected are ~0.1s each. No fix is shipped here because there is no safe one-liner: speeding this up means batching/parallelizing the `bot/src/factory.ts` deploy/mint paths (production code, PR-6-shaped), genesis-seeding (PR 1/2), or cutting the CI slot time (PR 5) — none belong in the instrumentation PR. Tracked as a round-5 item; the new `setup:bot` span makes that win measurable. Full write-up in `tmp/SPEEDUP_ROUND4_FINDINGS.md`. ## Expected effect No wall-clock change (passthrough spans). The deliverable is visibility: the previously-invisible `setup:bot` / `setup:wallet` / `wallet:create` decomposition of the bot beforeAll, and the `wait:proven-checkpoint` / `warp:proven-checkpoint-epoch` residual in the fees suites. Measured numbers from a full green CI run will be appended below once available. ## Measured impact Both runs are full CI runs. PR run: `ci/x-fast` on head `1f7898cd2b` (CI 1783345614459429, 1,799 test lines). Baseline: `ci/x-full-no-test-cache` on the exact merge-base `a8cfa93df5` (CI 1783341726388943, 1,863 test lines). No wall-clock change claimed (spans are passthrough; suite-level noise floor is ~11s median / ~52s p90) — the deliverable is attribution, measured as span `busyMs`. Bot suite (`suite` line, beforeAll = 181.5s on the PR run vs 182.1s baseline): - Baseline: 7.4s tagged (`setup:env:*` only) → **174.8s / 96% invisible**. - PR run: `setup:bot` **174,203 ms** (4 occurrences, max 86,961 ms = the amm-bot hook), `setup:wallet` **250 ms**, `wallet:create` **144 ms**; residual now **−1.5s ≈ 0** → **100% of the beforeAll is attributed**. - This confirms the diagnosis: `EmbeddedWallet.create` + `createSchnorrInitializerlessAccount` are ~0.4s combined; the "invisible 178s" is the four nested describes' bot-factory setup (deploys + mints at production 12s-slot cadence), folded into the file's suite line by the hook accounting. Fees suites (`private_payments.parallel` × 8 shards + `failures`): - Baseline: avg **32.3s/shard untagged residual** (zero `wait:proven-checkpoint` / `warp:proven-checkpoint-epoch` lines on these suites). - PR run: `wait:proven-checkpoint` fires on all 9 suite hooks, **293,888 ms total** (avg 32.7s/shard — matches the residual exactly), plus one in-test occurrence (32.1s); `warp:proven-checkpoint-epoch` 19 occurrences, 361 ms total (the warp RPC itself is near-free — the cost is entirely the proven-chain poll that follows). Per-shard residual is now ≈ −1s, i.e. fully attributed. Net: **~469s/run of previously invisible setup/wait cost is now tagged and attributable** (174.2s `setup:bot` + 0.4s wallet spans + 294.3s fees proven-chain waits), with no behavior or wall-clock change. Fixes A-1407
1 parent 1cc5f91 commit 1476179

4 files changed

Lines changed: 31 additions & 21 deletions

File tree

yarn-project/end-to-end/src/single-node/bot/bot.test.ts

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { EmbeddedWallet } from '@aztec/wallets/embedded';
2222
import { jest } from '@jest/globals';
2323

2424
import { PIPELINED_FEE_PADDING, PIPELINING_SETUP_OPTS } from '../../fixtures/fixtures.js';
25+
import { testSpan } from '../../fixtures/timing.js';
2526
import { getPrivateKeyFromIndex, setup } from '../../fixtures/utils.js';
2627
import { NO_REORG_SUBMISSION_EPOCHS } from '../setup.js';
2728

@@ -54,8 +55,10 @@ describe('single-node/bot/bot', () => {
5455
cheatCodes,
5556
config: { l1RpcUrls },
5657
} = setupResult);
57-
wallet = await EmbeddedWallet.create(aztecNode, { ephemeral: true });
58-
await wallet.createSchnorrInitializerlessAccount(botAccount.secret, botAccount.salt, botAccount.signingKey);
58+
wallet = await testSpan('setup:wallet', () => EmbeddedWallet.create(aztecNode, { ephemeral: true }));
59+
await testSpan('wallet:create', () =>
60+
wallet.createSchnorrInitializerlessAccount(botAccount.secret, botAccount.salt, botAccount.signingKey),
61+
);
5962
});
6063

6164
afterAll(() => teardown());
@@ -73,7 +76,9 @@ describe('single-node/bot/bot', () => {
7376
botMode: 'transfer',
7477
minFeePadding: PIPELINED_FEE_PADDING,
7578
};
76-
bot = await Bot.create(config, wallet, aztecNode, undefined, new BotStore(await openTmpStore('bot')));
79+
bot = await testSpan('setup:bot', async () =>
80+
Bot.create(config, wallet, aztecNode, undefined, new BotStore(await openTmpStore('bot'))),
81+
);
7782
});
7883

7984
// Runs bot.run() once and asserts recipient private and public balances each increase by 1.
@@ -131,7 +136,7 @@ describe('single-node/bot/bot', () => {
131136
let store: BotStore;
132137

133138
beforeAll(async () => {
134-
store = new BotStore(await openTmpStore('bot'));
139+
store = await testSpan('setup:bot', async () => new BotStore(await openTmpStore('bot')));
135140
});
136141

137142
afterAll(async () => {
@@ -238,7 +243,9 @@ describe('single-node/bot/bot', () => {
238243
followChain: 'CHECKPOINTED',
239244
botMode: 'amm',
240245
};
241-
bot = await AmmBot.create(config, wallet, aztecNode, undefined, new BotStore(await openTmpStore('bot')));
246+
bot = await testSpan('setup:bot', async () =>
247+
AmmBot.create(config, wallet, aztecNode, undefined, new BotStore(await openTmpStore('bot'))),
248+
);
242249
});
243250

244251
// Runs the AMM bot once and asserts one of the two private token balances decreased and
@@ -302,12 +309,8 @@ describe('single-node/bot/bot', () => {
302309
flushSetupTransactions: true,
303310
l1ToL2SeedCount: 2,
304311
};
305-
bot = await CrossChainBot.create(
306-
config,
307-
wallet,
308-
aztecNode,
309-
aztecNodeAdmin,
310-
new BotStore(await openTmpStore('bot')),
312+
bot = await testSpan('setup:bot', async () =>
313+
CrossChainBot.create(config, wallet, aztecNode, aztecNodeAdmin, new BotStore(await openTmpStore('bot'))),
311314
);
312315
}, 600_000);
313316

yarn-project/end-to-end/src/single-node/fees/failures.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ describe('single-node/fees/failures', () => {
5757
aztecNode = t.aztecNode;
5858

5959
// Prove up until the current state by advancing the epoch and waiting for the prover node.
60-
await t.cheatCodes.rollup.advanceToNextEpoch();
60+
await t.advanceToNextEpoch();
6161
await t.catchUpProvenChain();
6262
});
6363

@@ -123,7 +123,7 @@ describe('single-node/fees/failures', () => {
123123

124124
// @note There is a potential race condition here if other tests send transactions that get into the same
125125
// epoch and thereby pays out fees at the same time (when proven).
126-
await t.cheatCodes.rollup.advanceToNextEpoch();
126+
await t.advanceToNextEpoch();
127127
const provenTimeout =
128128
(t.context.config.aztecProofSubmissionEpochs + 1) *
129129
t.context.config.aztecEpochDuration *
@@ -362,7 +362,7 @@ describe('single-node/fees/failures', () => {
362362
);
363363

364364
// Prove the block containing the teardown-reverted tx (revert_code = 2).
365-
await t.cheatCodes.rollup.advanceToNextEpoch();
365+
await t.advanceToNextEpoch();
366366
const provenTimeout =
367367
(t.context.config.aztecProofSubmissionEpochs + 1) *
368368
t.context.config.aztecEpochDuration *
@@ -389,7 +389,7 @@ describe('single-node/fees/failures', () => {
389389
expect(receipt.executionResult).toBe(TxExecutionResult.REVERTED);
390390
expect(receipt.transactionFee).toBeGreaterThan(0n);
391391

392-
await t.cheatCodes.rollup.advanceToNextEpoch();
392+
await t.advanceToNextEpoch();
393393
const provenTimeout =
394394
(t.context.config.aztecProofSubmissionEpochs + 1) *
395395
t.context.config.aztecEpochDuration *

yarn-project/end-to-end/src/single-node/fees/fees_test.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,15 +131,22 @@ export class FeesTest extends SingleNodeTestContext {
131131
}
132132

133133
async catchUpProvenChain() {
134-
const bn = await this.aztecNode.getBlockNumber();
135-
while ((await this.aztecNode.getBlockNumber('proven')) < bn) {
136-
await sleep(1000);
137-
}
134+
await testSpan('wait:proven-checkpoint', async () => {
135+
const bn = await this.aztecNode.getBlockNumber();
136+
while ((await this.aztecNode.getBlockNumber('proven')) < bn) {
137+
await sleep(1000);
138+
}
139+
});
140+
}
141+
142+
/** Warps L1 to the next epoch boundary so the current epoch closes and can be proven. */
143+
async advanceToNextEpoch() {
144+
await testSpan('warp:proven-checkpoint-epoch', () => this.cheatCodes.rollup.advanceToNextEpoch());
138145
}
139146

140147
/** Advances to the next epoch and waits for the proven chain to catch up, so all prior fees are paid out. */
141148
async waitForEpochProven() {
142-
await this.cheatCodes.rollup.advanceToNextEpoch();
149+
await this.advanceToNextEpoch();
143150
await this.catchUpProvenChain();
144151
}
145152

yarn-project/end-to-end/src/single-node/fees/private_payments.parallel.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ describe('single-node/fees/private_payments', () => {
140140
const provenCheckpointBefore = await t.rollupContract.getProvenCheckpointNumber();
141141

142142
const receipt = await localTx.send({ timeout: 300, interval: 10 });
143-
await t.cheatCodes.rollup.advanceToNextEpoch();
143+
await t.advanceToNextEpoch();
144144

145145
await waitForProven(aztecNode, receipt, { provenTimeout: 300 });
146146

0 commit comments

Comments
 (0)