@aztec/end-to-end 0.0.1-commit.3895657bc → 0.0.1-commit.3e3d0c9cd
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/e2e_epochs/epochs_test.d.ts +1 -1
- package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
- package/dest/e2e_epochs/epochs_test.js +2 -1
- package/dest/e2e_p2p/reqresp/utils.d.ts +1 -1
- package/dest/e2e_p2p/reqresp/utils.d.ts.map +1 -1
- package/dest/e2e_p2p/reqresp/utils.js +15 -2
- package/dest/e2e_p2p/shared.d.ts +12 -6
- package/dest/e2e_p2p/shared.d.ts.map +1 -1
- package/dest/e2e_p2p/shared.js +17 -9
- package/dest/fixtures/setup.d.ts +6 -1
- package/dest/fixtures/setup.d.ts.map +1 -1
- package/dest/fixtures/setup.js +2 -1
- package/dest/shared/uniswap_l1_l2.d.ts +1 -1
- package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
- package/dest/shared/uniswap_l1_l2.js +9 -12
- package/dest/spartan/setup_test_wallets.d.ts +4 -2
- package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
- package/dest/spartan/setup_test_wallets.js +19 -7
- package/dest/spartan/utils/config.d.ts +4 -1
- package/dest/spartan/utils/config.d.ts.map +1 -1
- package/dest/spartan/utils/config.js +1 -0
- package/dest/spartan/utils/index.d.ts +2 -1
- package/dest/spartan/utils/index.d.ts.map +1 -1
- package/dest/spartan/utils/index.js +2 -0
- package/dest/spartan/utils/pod_logs.d.ts +25 -0
- package/dest/spartan/utils/pod_logs.d.ts.map +1 -0
- package/dest/spartan/utils/pod_logs.js +74 -0
- package/package.json +39 -40
- package/src/e2e_epochs/epochs_test.ts +1 -0
- package/src/e2e_p2p/reqresp/utils.ts +23 -2
- package/src/e2e_p2p/shared.ts +20 -10
- package/src/fixtures/setup.ts +6 -0
- package/src/shared/uniswap_l1_l2.ts +29 -24
- package/src/spartan/setup_test_wallets.ts +44 -6
- package/src/spartan/utils/config.ts +1 -0
- package/src/spartan/utils/index.ts +3 -0
- package/src/spartan/utils/pod_logs.ts +99 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Logger } from '@aztec/foundation/log';
|
|
2
|
+
/** Parsed l2-block-built stats from a sequencer pod log line. */
|
|
3
|
+
export type BlockBuiltLogEntry = {
|
|
4
|
+
blockNumber: number;
|
|
5
|
+
txCount: number;
|
|
6
|
+
duration: number;
|
|
7
|
+
publicProcessDuration: number;
|
|
8
|
+
manaPerSec: number;
|
|
9
|
+
privateLogCount: number;
|
|
10
|
+
publicLogCount: number;
|
|
11
|
+
contractClassLogCount: number;
|
|
12
|
+
contractClassLogSize: number;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Fetches l2-block-built log entries from sequencer pods for given block numbers.
|
|
16
|
+
* Queries all validator pods (only the proposer will have the log for a given block).
|
|
17
|
+
*
|
|
18
|
+
* @param namespace - Kubernetes namespace
|
|
19
|
+
* @param sinceTime - ISO 8601 timestamp to limit log search (e.g., from before block building was re-enabled)
|
|
20
|
+
* @param blockNumbers - Set of block numbers to filter for
|
|
21
|
+
* @param logger - Logger instance
|
|
22
|
+
* @returns Array of parsed BlockBuiltLogEntry, de-duplicated by blockNumber, sorted ascending
|
|
23
|
+
*/
|
|
24
|
+
export declare function fetchBlockBuiltLogs(namespace: string, sinceTime: string, blockNumbers: Set<number>, logger: Logger): Promise<BlockBuiltLogEntry[]>;
|
|
25
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicG9kX2xvZ3MuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zcGFydGFuL3V0aWxzL3BvZF9sb2dzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBU3BELGlFQUFpRTtBQUNqRSxNQUFNLE1BQU0sa0JBQWtCLEdBQUc7SUFDL0IsV0FBVyxFQUFFLE1BQU0sQ0FBQztJQUNwQixPQUFPLEVBQUUsTUFBTSxDQUFDO0lBQ2hCLFFBQVEsRUFBRSxNQUFNLENBQUM7SUFDakIscUJBQXFCLEVBQUUsTUFBTSxDQUFDO0lBQzlCLFVBQVUsRUFBRSxNQUFNLENBQUM7SUFDbkIsZUFBZSxFQUFFLE1BQU0sQ0FBQztJQUN4QixjQUFjLEVBQUUsTUFBTSxDQUFDO0lBQ3ZCLHFCQUFxQixFQUFFLE1BQU0sQ0FBQztJQUM5QixvQkFBb0IsRUFBRSxNQUFNLENBQUM7Q0FDOUIsQ0FBQztBQWNGOzs7Ozs7Ozs7R0FTRztBQUNILHdCQUFzQixtQkFBbUIsQ0FDdkMsU0FBUyxFQUFFLE1BQU0sRUFDakIsU0FBUyxFQUFFLE1BQU0sRUFDakIsWUFBWSxFQUFFLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFDekIsTUFBTSxFQUFFLE1BQU0sR0FDYixPQUFPLENBQUMsa0JBQWtCLEVBQUUsQ0FBQyxDQWlEL0IifQ==
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pod_logs.d.ts","sourceRoot":"","sources":["../../../src/spartan/utils/pod_logs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AASpD,iEAAiE;AACjE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,oBAAoB,EAAE,MAAM,CAAC;CAC9B,CAAC;AAcF;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,EACzB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAiD/B"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { exec } from 'child_process';
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
import { getSequencers } from './nodes.js';
|
|
4
|
+
const execAsync = promisify(exec);
|
|
5
|
+
const FIELDS = [
|
|
6
|
+
'blockNumber',
|
|
7
|
+
'txCount',
|
|
8
|
+
'duration',
|
|
9
|
+
'publicProcessDuration',
|
|
10
|
+
'manaPerSec',
|
|
11
|
+
'privateLogCount',
|
|
12
|
+
'publicLogCount',
|
|
13
|
+
'contractClassLogCount',
|
|
14
|
+
'contractClassLogSize'
|
|
15
|
+
];
|
|
16
|
+
/**
|
|
17
|
+
* Fetches l2-block-built log entries from sequencer pods for given block numbers.
|
|
18
|
+
* Queries all validator pods (only the proposer will have the log for a given block).
|
|
19
|
+
*
|
|
20
|
+
* @param namespace - Kubernetes namespace
|
|
21
|
+
* @param sinceTime - ISO 8601 timestamp to limit log search (e.g., from before block building was re-enabled)
|
|
22
|
+
* @param blockNumbers - Set of block numbers to filter for
|
|
23
|
+
* @param logger - Logger instance
|
|
24
|
+
* @returns Array of parsed BlockBuiltLogEntry, de-duplicated by blockNumber, sorted ascending
|
|
25
|
+
*/ export async function fetchBlockBuiltLogs(namespace, sinceTime, blockNumbers, logger) {
|
|
26
|
+
const pods = await getSequencers(namespace);
|
|
27
|
+
const entriesByBlock = new Map();
|
|
28
|
+
// Subtract 60s from sinceTime to account for clock skew between test runner and k8s pods.
|
|
29
|
+
// Block number filtering ensures we only match the right blocks, so extra lines are harmless.
|
|
30
|
+
const sinceDate = new Date(new Date(sinceTime).getTime() - 60_000);
|
|
31
|
+
const sinceFlag = sinceDate.toISOString();
|
|
32
|
+
for (const pod of pods){
|
|
33
|
+
try {
|
|
34
|
+
const cmd = `kubectl logs ${pod} -n ${namespace} -c aztec --since-time=${sinceFlag}`;
|
|
35
|
+
logger.info(`Fetching logs: ${cmd}`);
|
|
36
|
+
const { stdout } = await execAsync(cmd, {
|
|
37
|
+
maxBuffer: 10 * 1024 * 1024
|
|
38
|
+
});
|
|
39
|
+
const lines = stdout.split('\n');
|
|
40
|
+
const matchingLines = lines.filter((l)=>l.includes('l2-block-built'));
|
|
41
|
+
logger.info(`Pod ${pod}: ${lines.length} log lines, ${matchingLines.length} contain l2-block-built`);
|
|
42
|
+
for (const line of matchingLines){
|
|
43
|
+
try {
|
|
44
|
+
const parsed = JSON.parse(line);
|
|
45
|
+
if (parsed.eventName !== 'l2-block-built' || !blockNumbers.has(parsed.blockNumber)) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (entriesByBlock.has(parsed.blockNumber)) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const entry = {};
|
|
52
|
+
for (const field of FIELDS){
|
|
53
|
+
entry[field] = parsed[field] ?? 0;
|
|
54
|
+
}
|
|
55
|
+
entriesByBlock.set(entry.blockNumber, entry);
|
|
56
|
+
logger.verbose(`Parsed l2-block-built log for block ${entry.blockNumber}`, entry);
|
|
57
|
+
} catch {
|
|
58
|
+
// Not valid JSON, skip
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
} catch (err) {
|
|
62
|
+
logger.warn(`Failed to fetch logs from pod ${pod}: ${err}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (entriesByBlock.size < blockNumbers.size) {
|
|
66
|
+
const missing = [
|
|
67
|
+
...blockNumbers
|
|
68
|
+
].filter((bn)=>!entriesByBlock.has(bn));
|
|
69
|
+
logger.warn(`Missing l2-block-built logs for block(s): ${missing.join(', ')}`);
|
|
70
|
+
}
|
|
71
|
+
return [
|
|
72
|
+
...entriesByBlock.values()
|
|
73
|
+
].sort((a, b)=>a.blockNumber - b.blockNumber);
|
|
74
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/end-to-end",
|
|
3
|
-
"version": "0.0.1-commit.
|
|
3
|
+
"version": "0.0.1-commit.3e3d0c9cd",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": "./dest/index.js",
|
|
6
6
|
"inherits": [
|
|
@@ -26,45 +26,44 @@
|
|
|
26
26
|
"formatting": "run -T prettier --check ./src && run -T eslint ./src"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@aztec/accounts": "0.0.1-commit.
|
|
30
|
-
"@aztec/archiver": "0.0.1-commit.
|
|
31
|
-
"@aztec/aztec": "0.0.1-commit.
|
|
32
|
-
"@aztec/aztec-node": "0.0.1-commit.
|
|
33
|
-
"@aztec/aztec.js": "0.0.1-commit.
|
|
34
|
-
"@aztec/bb-prover": "0.0.1-commit.
|
|
35
|
-
"@aztec/bb.js": "0.0.1-commit.
|
|
36
|
-
"@aztec/blob-client": "0.0.1-commit.
|
|
37
|
-
"@aztec/blob-lib": "0.0.1-commit.
|
|
38
|
-
"@aztec/bot": "0.0.1-commit.
|
|
39
|
-
"@aztec/cli": "0.0.1-commit.
|
|
40
|
-
"@aztec/constants": "0.0.1-commit.
|
|
41
|
-
"@aztec/entrypoints": "0.0.1-commit.
|
|
42
|
-
"@aztec/epoch-cache": "0.0.1-commit.
|
|
43
|
-
"@aztec/ethereum": "0.0.1-commit.
|
|
44
|
-
"@aztec/foundation": "0.0.1-commit.
|
|
45
|
-
"@aztec/kv-store": "0.0.1-commit.
|
|
46
|
-
"@aztec/l1-artifacts": "0.0.1-commit.
|
|
47
|
-
"@aztec/
|
|
48
|
-
"@aztec/
|
|
49
|
-
"@aztec/noir-
|
|
50
|
-
"@aztec/noir-
|
|
51
|
-
"@aztec/noir-
|
|
52
|
-
"@aztec/
|
|
53
|
-
"@aztec/
|
|
54
|
-
"@aztec/
|
|
55
|
-
"@aztec/prover-
|
|
56
|
-
"@aztec/
|
|
57
|
-
"@aztec/
|
|
58
|
-
"@aztec/
|
|
59
|
-
"@aztec/
|
|
60
|
-
"@aztec/
|
|
61
|
-
"@aztec/
|
|
62
|
-
"@aztec/
|
|
63
|
-
"@aztec/validator-
|
|
64
|
-
"@aztec/
|
|
65
|
-
"@aztec/
|
|
66
|
-
"@aztec/
|
|
67
|
-
"@aztec/world-state": "0.0.1-commit.3895657bc",
|
|
29
|
+
"@aztec/accounts": "0.0.1-commit.3e3d0c9cd",
|
|
30
|
+
"@aztec/archiver": "0.0.1-commit.3e3d0c9cd",
|
|
31
|
+
"@aztec/aztec": "0.0.1-commit.3e3d0c9cd",
|
|
32
|
+
"@aztec/aztec-node": "0.0.1-commit.3e3d0c9cd",
|
|
33
|
+
"@aztec/aztec.js": "0.0.1-commit.3e3d0c9cd",
|
|
34
|
+
"@aztec/bb-prover": "0.0.1-commit.3e3d0c9cd",
|
|
35
|
+
"@aztec/bb.js": "0.0.1-commit.3e3d0c9cd",
|
|
36
|
+
"@aztec/blob-client": "0.0.1-commit.3e3d0c9cd",
|
|
37
|
+
"@aztec/blob-lib": "0.0.1-commit.3e3d0c9cd",
|
|
38
|
+
"@aztec/bot": "0.0.1-commit.3e3d0c9cd",
|
|
39
|
+
"@aztec/cli": "0.0.1-commit.3e3d0c9cd",
|
|
40
|
+
"@aztec/constants": "0.0.1-commit.3e3d0c9cd",
|
|
41
|
+
"@aztec/entrypoints": "0.0.1-commit.3e3d0c9cd",
|
|
42
|
+
"@aztec/epoch-cache": "0.0.1-commit.3e3d0c9cd",
|
|
43
|
+
"@aztec/ethereum": "0.0.1-commit.3e3d0c9cd",
|
|
44
|
+
"@aztec/foundation": "0.0.1-commit.3e3d0c9cd",
|
|
45
|
+
"@aztec/kv-store": "0.0.1-commit.3e3d0c9cd",
|
|
46
|
+
"@aztec/l1-artifacts": "0.0.1-commit.3e3d0c9cd",
|
|
47
|
+
"@aztec/node-keystore": "0.0.1-commit.3e3d0c9cd",
|
|
48
|
+
"@aztec/noir-contracts.js": "0.0.1-commit.3e3d0c9cd",
|
|
49
|
+
"@aztec/noir-noirc_abi": "0.0.1-commit.3e3d0c9cd",
|
|
50
|
+
"@aztec/noir-protocol-circuits-types": "0.0.1-commit.3e3d0c9cd",
|
|
51
|
+
"@aztec/noir-test-contracts.js": "0.0.1-commit.3e3d0c9cd",
|
|
52
|
+
"@aztec/p2p": "0.0.1-commit.3e3d0c9cd",
|
|
53
|
+
"@aztec/protocol-contracts": "0.0.1-commit.3e3d0c9cd",
|
|
54
|
+
"@aztec/prover-client": "0.0.1-commit.3e3d0c9cd",
|
|
55
|
+
"@aztec/prover-node": "0.0.1-commit.3e3d0c9cd",
|
|
56
|
+
"@aztec/pxe": "0.0.1-commit.3e3d0c9cd",
|
|
57
|
+
"@aztec/sequencer-client": "0.0.1-commit.3e3d0c9cd",
|
|
58
|
+
"@aztec/simulator": "0.0.1-commit.3e3d0c9cd",
|
|
59
|
+
"@aztec/slasher": "0.0.1-commit.3e3d0c9cd",
|
|
60
|
+
"@aztec/stdlib": "0.0.1-commit.3e3d0c9cd",
|
|
61
|
+
"@aztec/telemetry-client": "0.0.1-commit.3e3d0c9cd",
|
|
62
|
+
"@aztec/validator-client": "0.0.1-commit.3e3d0c9cd",
|
|
63
|
+
"@aztec/validator-ha-signer": "0.0.1-commit.3e3d0c9cd",
|
|
64
|
+
"@aztec/wallet-sdk": "0.0.1-commit.3e3d0c9cd",
|
|
65
|
+
"@aztec/wallets": "0.0.1-commit.3e3d0c9cd",
|
|
66
|
+
"@aztec/world-state": "0.0.1-commit.3e3d0c9cd",
|
|
68
67
|
"@iarna/toml": "^2.2.5",
|
|
69
68
|
"@jest/globals": "^30.0.0",
|
|
70
69
|
"@noble/curves": "=1.0.0",
|
|
@@ -181,6 +181,7 @@ export class EpochsTestContext {
|
|
|
181
181
|
ethereumSlotDuration,
|
|
182
182
|
proofSubmissionEpochs: Number(await this.rollup.getProofSubmissionEpochs()),
|
|
183
183
|
targetCommitteeSize: await this.rollup.getTargetCommitteeSize(),
|
|
184
|
+
rollupManaLimit: Number(await this.rollup.getManaLimit()),
|
|
184
185
|
};
|
|
185
186
|
|
|
186
187
|
this.logger.info(
|
|
@@ -149,6 +149,13 @@ export async function runReqrespTxTest(params: {
|
|
|
149
149
|
const submittedTxs = await Promise.all(
|
|
150
150
|
txBatches.map(async (batch, batchIndex) => {
|
|
151
151
|
const proposerNode = nodes[proposerIndexes[batchIndex]];
|
|
152
|
+
for (const tx of batch) {
|
|
153
|
+
t.logger.info(`Tx ${tx.getTxHash().toString()} base64: ${tx.toBuffer().toString('base64')}`);
|
|
154
|
+
}
|
|
155
|
+
const txHashes = batch.map(tx => tx.getTxHash().toString());
|
|
156
|
+
t.logger.info(
|
|
157
|
+
`Sending batch ${batchIndex} to proposer ${getNodePort(proposerIndexes[batchIndex])}: ${txHashes.join(', ')}`,
|
|
158
|
+
);
|
|
152
159
|
await Promise.all(
|
|
153
160
|
batch.map(async tx => {
|
|
154
161
|
try {
|
|
@@ -163,6 +170,12 @@ export async function runReqrespTxTest(params: {
|
|
|
163
170
|
}),
|
|
164
171
|
);
|
|
165
172
|
|
|
173
|
+
// Log pool state per node after sending
|
|
174
|
+
for (let i = 0; i < NUM_VALIDATORS; i++) {
|
|
175
|
+
const count = await nodes[i].getPendingTxCount();
|
|
176
|
+
t.logger.info(`Node ${getNodePort(i)} pool has ${count} pending txs`);
|
|
177
|
+
}
|
|
178
|
+
|
|
166
179
|
t.logger.info('Waiting for all transactions to be mined');
|
|
167
180
|
await Promise.all(
|
|
168
181
|
submittedTxs.flatMap((batch, batchIndex) =>
|
|
@@ -178,8 +191,16 @@ export async function runReqrespTxTest(params: {
|
|
|
178
191
|
|
|
179
192
|
// Assert that multiple blocks were built for at least one slot
|
|
180
193
|
t.logger.info('Verifying multiple blocks for at least one checkpoint');
|
|
181
|
-
|
|
182
|
-
|
|
194
|
+
// Wait for L1 checkpoint sync, which may lag behind P2P block propagation.
|
|
195
|
+
const checkpoints = await retryUntil(
|
|
196
|
+
async () => {
|
|
197
|
+
const cps = await nodes[0].getCheckpoints(CheckpointNumber(1), 50);
|
|
198
|
+
return cps.length > 0 && cps.some(cp => cp.checkpoint.blocks.length >= 2) ? cps : undefined;
|
|
199
|
+
},
|
|
200
|
+
'waiting for multi-block checkpoint to sync from L1',
|
|
201
|
+
30,
|
|
202
|
+
1,
|
|
203
|
+
);
|
|
183
204
|
|
|
184
205
|
let mbpsFound = false;
|
|
185
206
|
let expectedBlockNumber = checkpoints[0].checkpoint.blocks[0].number;
|
package/src/e2e_p2p/shared.ts
CHANGED
|
@@ -152,11 +152,14 @@ export async function awaitCommitteeExists({
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
/**
|
|
155
|
-
* Advance epochs until we find one where the target proposer is selected for at least one slot
|
|
156
|
-
*
|
|
157
|
-
*
|
|
155
|
+
* Advance epochs until we find one where the target proposer is selected for at least one slot,
|
|
156
|
+
* then stop one epoch before it. This leaves time for the caller to start sequencers before
|
|
157
|
+
* warping to the target epoch, avoiding the race where the target epoch passes before sequencers
|
|
158
|
+
* are ready.
|
|
159
|
+
*
|
|
160
|
+
* Returns the target epoch number so the caller can warp to it after starting sequencers.
|
|
158
161
|
*/
|
|
159
|
-
export async function
|
|
162
|
+
export async function advanceToEpochBeforeProposer({
|
|
160
163
|
epochCache,
|
|
161
164
|
cheatCodes,
|
|
162
165
|
targetProposer,
|
|
@@ -168,25 +171,32 @@ export async function awaitEpochWithProposer({
|
|
|
168
171
|
targetProposer: EthAddress;
|
|
169
172
|
logger: Logger;
|
|
170
173
|
maxAttempts?: number;
|
|
171
|
-
}): Promise<
|
|
174
|
+
}): Promise<{ targetEpoch: EpochNumber }> {
|
|
172
175
|
const { epochDuration } = await cheatCodes.getConfig();
|
|
173
176
|
|
|
174
177
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
175
178
|
const currentEpoch = await cheatCodes.getEpoch();
|
|
176
|
-
|
|
179
|
+
// Check the NEXT epoch's slots so we stay one epoch before the target,
|
|
180
|
+
// giving the caller time to start sequencers before the target epoch arrives.
|
|
181
|
+
const nextEpoch = Number(currentEpoch) + 1;
|
|
182
|
+
const startSlot = nextEpoch * Number(epochDuration);
|
|
177
183
|
const endSlot = startSlot + Number(epochDuration);
|
|
178
184
|
|
|
179
|
-
logger.info(
|
|
185
|
+
logger.info(
|
|
186
|
+
`Checking next epoch ${nextEpoch} (slots ${startSlot}-${endSlot - 1}) for proposer ${targetProposer} (current epoch: ${currentEpoch})`,
|
|
187
|
+
);
|
|
180
188
|
|
|
181
189
|
for (let s = startSlot; s < endSlot; s++) {
|
|
182
190
|
const proposer = await epochCache.getProposerAttesterAddressInSlot(SlotNumber(s));
|
|
183
191
|
if (proposer && proposer.equals(targetProposer)) {
|
|
184
|
-
logger.warn(
|
|
185
|
-
|
|
192
|
+
logger.warn(
|
|
193
|
+
`Found target proposer ${targetProposer} in slot ${s} of epoch ${nextEpoch}. Staying at epoch ${currentEpoch} to allow sequencer startup.`,
|
|
194
|
+
);
|
|
195
|
+
return { targetEpoch: EpochNumber(nextEpoch) };
|
|
186
196
|
}
|
|
187
197
|
}
|
|
188
198
|
|
|
189
|
-
logger.info(`Target proposer not found in epoch ${
|
|
199
|
+
logger.info(`Target proposer not found in epoch ${nextEpoch}, advancing to next epoch`);
|
|
190
200
|
await cheatCodes.advanceToNextEpoch();
|
|
191
201
|
}
|
|
192
202
|
|
package/src/fixtures/setup.ts
CHANGED
|
@@ -185,6 +185,11 @@ export type SetupOptions = {
|
|
|
185
185
|
anvilAccounts?: number;
|
|
186
186
|
/** Port to start anvil (defaults to 8545) */
|
|
187
187
|
anvilPort?: number;
|
|
188
|
+
/**
|
|
189
|
+
* Number of slots per epoch for Anvil's finality simulation.
|
|
190
|
+
* Anvil reports `finalized = latest - slotsInAnEpoch * 2`.
|
|
191
|
+
*/
|
|
192
|
+
anvilSlotsInAnEpoch?: number;
|
|
188
193
|
/** Key to use for publishing L1 contracts */
|
|
189
194
|
l1PublisherKey?: SecretValue<`0x${string}`>;
|
|
190
195
|
/** ZkPassport configuration (domain, scope, mock verifier) */
|
|
@@ -305,6 +310,7 @@ export async function setup(
|
|
|
305
310
|
l1BlockTime: opts.ethereumSlotDuration,
|
|
306
311
|
accounts: opts.anvilAccounts,
|
|
307
312
|
port: opts.anvilPort ?? (process.env.ANVIL_PORT ? parseInt(process.env.ANVIL_PORT) : undefined),
|
|
313
|
+
slotsInAnEpoch: opts.anvilSlotsInAnEpoch,
|
|
308
314
|
});
|
|
309
315
|
anvil = res.anvil;
|
|
310
316
|
config.l1RpcUrls = [res.rpcUrl];
|
|
@@ -252,8 +252,12 @@ export const uniswapL1L2TestSuite = (
|
|
|
252
252
|
await wethCrossChainHarness.expectPublicBalanceOnL2(uniswapL2Contract.address, 0n);
|
|
253
253
|
|
|
254
254
|
// Since the outbox is only consumable when the epoch is proven, we need to advance to the next epoch.
|
|
255
|
-
const
|
|
256
|
-
|
|
255
|
+
const swapResult = (await computeL2ToL1MembershipWitness(
|
|
256
|
+
aztecNode,
|
|
257
|
+
swapPrivateLeaf,
|
|
258
|
+
l2UniswapInteractionReceipt.txHash,
|
|
259
|
+
))!;
|
|
260
|
+
const { epochNumber: epoch } = swapResult;
|
|
257
261
|
await cheatCodes.rollup.advanceToEpoch(EpochNumber(epoch + 1));
|
|
258
262
|
await waitForProven(aztecNode, l2UniswapInteractionReceipt, { provenTimeout: 300 });
|
|
259
263
|
|
|
@@ -262,14 +266,17 @@ export const uniswapL1L2TestSuite = (
|
|
|
262
266
|
const daiL1BalanceOfPortalBeforeSwap = await daiCrossChainHarness.getL1BalanceOf(
|
|
263
267
|
daiCrossChainHarness.tokenPortalAddress,
|
|
264
268
|
);
|
|
265
|
-
const
|
|
266
|
-
|
|
269
|
+
const withdrawResult = (await computeL2ToL1MembershipWitness(
|
|
270
|
+
aztecNode,
|
|
271
|
+
withdrawLeaf,
|
|
272
|
+
l2UniswapInteractionReceipt.txHash,
|
|
273
|
+
))!;
|
|
267
274
|
|
|
268
|
-
const swapPrivateL2MessageIndex = swapResult
|
|
269
|
-
const swapPrivateSiblingPath = swapResult
|
|
275
|
+
const swapPrivateL2MessageIndex = swapResult.leafIndex;
|
|
276
|
+
const swapPrivateSiblingPath = swapResult.siblingPath;
|
|
270
277
|
|
|
271
|
-
const withdrawL2MessageIndex = withdrawResult
|
|
272
|
-
const withdrawSiblingPath = withdrawResult
|
|
278
|
+
const withdrawL2MessageIndex = withdrawResult.leafIndex;
|
|
279
|
+
const withdrawSiblingPath = withdrawResult.siblingPath;
|
|
273
280
|
|
|
274
281
|
const withdrawMessageMetadata = {
|
|
275
282
|
_epoch: BigInt(epoch),
|
|
@@ -840,16 +847,15 @@ export const uniswapL1L2TestSuite = (
|
|
|
840
847
|
chainId: new Fr(l1Client.chain.id),
|
|
841
848
|
});
|
|
842
849
|
|
|
843
|
-
const
|
|
844
|
-
const epoch =
|
|
845
|
-
const
|
|
846
|
-
const withdrawResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, withdrawLeaf);
|
|
850
|
+
const swapResult = (await computeL2ToL1MembershipWitness(aztecNode, swapPrivateLeaf, withdrawReceipt.txHash))!;
|
|
851
|
+
const { epochNumber: epoch } = swapResult;
|
|
852
|
+
const withdrawResult = (await computeL2ToL1MembershipWitness(aztecNode, withdrawLeaf, withdrawReceipt.txHash))!;
|
|
847
853
|
|
|
848
|
-
const swapPrivateL2MessageIndex = swapResult
|
|
849
|
-
const swapPrivateSiblingPath = swapResult
|
|
854
|
+
const swapPrivateL2MessageIndex = swapResult.leafIndex;
|
|
855
|
+
const swapPrivateSiblingPath = swapResult.siblingPath;
|
|
850
856
|
|
|
851
|
-
const withdrawL2MessageIndex = withdrawResult
|
|
852
|
-
const withdrawSiblingPath = withdrawResult
|
|
857
|
+
const withdrawL2MessageIndex = withdrawResult.leafIndex;
|
|
858
|
+
const withdrawSiblingPath = withdrawResult.siblingPath;
|
|
853
859
|
|
|
854
860
|
const withdrawMessageMetadata = {
|
|
855
861
|
_epoch: BigInt(epoch),
|
|
@@ -973,16 +979,15 @@ export const uniswapL1L2TestSuite = (
|
|
|
973
979
|
chainId: new Fr(l1Client.chain.id),
|
|
974
980
|
});
|
|
975
981
|
|
|
976
|
-
const
|
|
977
|
-
const epoch =
|
|
978
|
-
const
|
|
979
|
-
const withdrawResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, withdrawLeaf);
|
|
982
|
+
const swapResult = (await computeL2ToL1MembershipWitness(aztecNode, swapPublicLeaf, withdrawReceipt.txHash))!;
|
|
983
|
+
const { epochNumber: epoch } = swapResult;
|
|
984
|
+
const withdrawResult = (await computeL2ToL1MembershipWitness(aztecNode, withdrawLeaf, withdrawReceipt.txHash))!;
|
|
980
985
|
|
|
981
|
-
const swapPublicL2MessageIndex = swapResult
|
|
982
|
-
const swapPublicSiblingPath = swapResult
|
|
986
|
+
const swapPublicL2MessageIndex = swapResult.leafIndex;
|
|
987
|
+
const swapPublicSiblingPath = swapResult.siblingPath;
|
|
983
988
|
|
|
984
|
-
const withdrawL2MessageIndex = withdrawResult
|
|
985
|
-
const withdrawSiblingPath = withdrawResult
|
|
989
|
+
const withdrawL2MessageIndex = withdrawResult.leafIndex;
|
|
990
|
+
const withdrawSiblingPath = withdrawResult.siblingPath;
|
|
986
991
|
|
|
987
992
|
const withdrawMessageMetadata = {
|
|
988
993
|
_epoch: BigInt(epoch),
|
|
@@ -129,16 +129,27 @@ export async function deploySponsoredTestAccountsWithTokens(
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
async function deployAccountWithDiagnostics(
|
|
132
|
-
account: { getDeployMethod: () => Promise<{ send: (opts: any) => any }>; address: any },
|
|
132
|
+
account: { getDeployMethod: () => Promise<{ simulate: (opts: any) => any; send: (opts: any) => any }>; address: any },
|
|
133
133
|
paymentMethod: SponsoredFeePaymentMethod,
|
|
134
134
|
aztecNode: AztecNode,
|
|
135
135
|
logger: Logger,
|
|
136
136
|
accountLabel: string,
|
|
137
|
+
estimateGas?: boolean,
|
|
137
138
|
): Promise<void> {
|
|
138
139
|
const deployMethod = await account.getDeployMethod();
|
|
139
140
|
let txHash;
|
|
140
141
|
try {
|
|
141
|
-
|
|
142
|
+
let gasSettings;
|
|
143
|
+
if (estimateGas) {
|
|
144
|
+
const sim = await deployMethod.simulate({ from: AztecAddress.ZERO, fee: { paymentMethod } });
|
|
145
|
+
gasSettings = sim.estimatedGas;
|
|
146
|
+
logger.info(`${accountLabel} estimated gas: DA=${gasSettings.gasLimits.daGas} L2=${gasSettings.gasLimits.l2Gas}`);
|
|
147
|
+
}
|
|
148
|
+
const deployResult = await deployMethod.send({
|
|
149
|
+
from: AztecAddress.ZERO,
|
|
150
|
+
fee: { paymentMethod, gasSettings },
|
|
151
|
+
wait: NO_WAIT,
|
|
152
|
+
});
|
|
142
153
|
txHash = deployResult.txHash;
|
|
143
154
|
await waitForTx(aztecNode, txHash, { timeout: 2400 });
|
|
144
155
|
logger.info(`${accountLabel} deployed at ${account.address}`);
|
|
@@ -161,18 +172,29 @@ async function deployAccountWithDiagnostics(
|
|
|
161
172
|
}
|
|
162
173
|
|
|
163
174
|
async function deployAccountsInBatches(
|
|
164
|
-
accounts: {
|
|
175
|
+
accounts: {
|
|
176
|
+
getDeployMethod: () => Promise<{ simulate: (opts: any) => any; send: (opts: any) => any }>;
|
|
177
|
+
address: any;
|
|
178
|
+
}[],
|
|
165
179
|
paymentMethod: SponsoredFeePaymentMethod,
|
|
166
180
|
aztecNode: AztecNode,
|
|
167
181
|
logger: Logger,
|
|
168
182
|
labelPrefix: string,
|
|
169
183
|
batchSize = 2,
|
|
184
|
+
estimateGas?: boolean,
|
|
170
185
|
): Promise<void> {
|
|
171
186
|
for (let i = 0; i < accounts.length; i += batchSize) {
|
|
172
187
|
const batch = accounts.slice(i, i + batchSize);
|
|
173
188
|
await Promise.all(
|
|
174
189
|
batch.map((account, idx) =>
|
|
175
|
-
deployAccountWithDiagnostics(
|
|
190
|
+
deployAccountWithDiagnostics(
|
|
191
|
+
account,
|
|
192
|
+
paymentMethod,
|
|
193
|
+
aztecNode,
|
|
194
|
+
logger,
|
|
195
|
+
`${labelPrefix}${i + idx + 1}`,
|
|
196
|
+
estimateGas,
|
|
197
|
+
),
|
|
176
198
|
),
|
|
177
199
|
);
|
|
178
200
|
}
|
|
@@ -183,6 +205,7 @@ export async function deploySponsoredTestAccounts(
|
|
|
183
205
|
aztecNode: AztecNode,
|
|
184
206
|
logger: Logger,
|
|
185
207
|
numberOfFundedWallets = 1,
|
|
208
|
+
opts?: { estimateGas?: boolean },
|
|
186
209
|
): Promise<TestAccountsWithoutTokens> {
|
|
187
210
|
const [recipient, ...funded] = await generateSchnorrAccounts(numberOfFundedWallets + 1);
|
|
188
211
|
const recipientAccount = await wallet.createSchnorrAccount(recipient.secret, recipient.salt);
|
|
@@ -192,8 +215,23 @@ export async function deploySponsoredTestAccounts(
|
|
|
192
215
|
|
|
193
216
|
const paymentMethod = new SponsoredFeePaymentMethod(await getSponsoredFPCAddress());
|
|
194
217
|
|
|
195
|
-
await deployAccountWithDiagnostics(
|
|
196
|
-
|
|
218
|
+
await deployAccountWithDiagnostics(
|
|
219
|
+
recipientAccount,
|
|
220
|
+
paymentMethod,
|
|
221
|
+
aztecNode,
|
|
222
|
+
logger,
|
|
223
|
+
'Recipient account',
|
|
224
|
+
opts?.estimateGas,
|
|
225
|
+
);
|
|
226
|
+
await deployAccountsInBatches(
|
|
227
|
+
fundedAccounts,
|
|
228
|
+
paymentMethod,
|
|
229
|
+
aztecNode,
|
|
230
|
+
logger,
|
|
231
|
+
'Funded account ',
|
|
232
|
+
2,
|
|
233
|
+
opts?.estimateGas,
|
|
234
|
+
);
|
|
197
235
|
|
|
198
236
|
return {
|
|
199
237
|
aztecNode,
|
|
@@ -8,6 +8,7 @@ const logger = createLogger('e2e:k8s-utils');
|
|
|
8
8
|
const testConfigSchema = z.object({
|
|
9
9
|
NAMESPACE: z.string().default('scenario'),
|
|
10
10
|
REAL_VERIFIER: schemas.Boolean.optional().default(true),
|
|
11
|
+
DEBUG_FORCE_TX_PROOF_VERIFICATION: schemas.Boolean.optional().default(true),
|
|
11
12
|
CREATE_ETH_DEVNET: schemas.Boolean.optional().default(false),
|
|
12
13
|
L1_RPC_URLS_JSON: z.string().optional(),
|
|
13
14
|
L1_ACCOUNT_MNEMONIC: z.string().optional(),
|
|
@@ -66,3 +66,6 @@ export { getPublicViemClient, getL1DeploymentAddresses, getNodeClient } from './
|
|
|
66
66
|
|
|
67
67
|
// Health checks
|
|
68
68
|
export { ChainHealth, type ChainHealthSnapshot } from './health.js';
|
|
69
|
+
|
|
70
|
+
// Pod log extraction
|
|
71
|
+
export { type BlockBuiltLogEntry, fetchBlockBuiltLogs } from './pod_logs.js';
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { Logger } from '@aztec/foundation/log';
|
|
2
|
+
|
|
3
|
+
import { exec } from 'child_process';
|
|
4
|
+
import { promisify } from 'util';
|
|
5
|
+
|
|
6
|
+
import { getSequencers } from './nodes.js';
|
|
7
|
+
|
|
8
|
+
const execAsync = promisify(exec);
|
|
9
|
+
|
|
10
|
+
/** Parsed l2-block-built stats from a sequencer pod log line. */
|
|
11
|
+
export type BlockBuiltLogEntry = {
|
|
12
|
+
blockNumber: number;
|
|
13
|
+
txCount: number;
|
|
14
|
+
duration: number;
|
|
15
|
+
publicProcessDuration: number;
|
|
16
|
+
manaPerSec: number;
|
|
17
|
+
privateLogCount: number;
|
|
18
|
+
publicLogCount: number;
|
|
19
|
+
contractClassLogCount: number;
|
|
20
|
+
contractClassLogSize: number;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const FIELDS: (keyof BlockBuiltLogEntry)[] = [
|
|
24
|
+
'blockNumber',
|
|
25
|
+
'txCount',
|
|
26
|
+
'duration',
|
|
27
|
+
'publicProcessDuration',
|
|
28
|
+
'manaPerSec',
|
|
29
|
+
'privateLogCount',
|
|
30
|
+
'publicLogCount',
|
|
31
|
+
'contractClassLogCount',
|
|
32
|
+
'contractClassLogSize',
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Fetches l2-block-built log entries from sequencer pods for given block numbers.
|
|
37
|
+
* Queries all validator pods (only the proposer will have the log for a given block).
|
|
38
|
+
*
|
|
39
|
+
* @param namespace - Kubernetes namespace
|
|
40
|
+
* @param sinceTime - ISO 8601 timestamp to limit log search (e.g., from before block building was re-enabled)
|
|
41
|
+
* @param blockNumbers - Set of block numbers to filter for
|
|
42
|
+
* @param logger - Logger instance
|
|
43
|
+
* @returns Array of parsed BlockBuiltLogEntry, de-duplicated by blockNumber, sorted ascending
|
|
44
|
+
*/
|
|
45
|
+
export async function fetchBlockBuiltLogs(
|
|
46
|
+
namespace: string,
|
|
47
|
+
sinceTime: string,
|
|
48
|
+
blockNumbers: Set<number>,
|
|
49
|
+
logger: Logger,
|
|
50
|
+
): Promise<BlockBuiltLogEntry[]> {
|
|
51
|
+
const pods = await getSequencers(namespace);
|
|
52
|
+
const entriesByBlock = new Map<number, BlockBuiltLogEntry>();
|
|
53
|
+
|
|
54
|
+
// Subtract 60s from sinceTime to account for clock skew between test runner and k8s pods.
|
|
55
|
+
// Block number filtering ensures we only match the right blocks, so extra lines are harmless.
|
|
56
|
+
const sinceDate = new Date(new Date(sinceTime).getTime() - 60_000);
|
|
57
|
+
const sinceFlag = sinceDate.toISOString();
|
|
58
|
+
|
|
59
|
+
for (const pod of pods) {
|
|
60
|
+
try {
|
|
61
|
+
const cmd = `kubectl logs ${pod} -n ${namespace} -c aztec --since-time=${sinceFlag}`;
|
|
62
|
+
logger.info(`Fetching logs: ${cmd}`);
|
|
63
|
+
const { stdout } = await execAsync(cmd, { maxBuffer: 10 * 1024 * 1024 });
|
|
64
|
+
|
|
65
|
+
const lines = stdout.split('\n');
|
|
66
|
+
const matchingLines = lines.filter(l => l.includes('l2-block-built'));
|
|
67
|
+
logger.info(`Pod ${pod}: ${lines.length} log lines, ${matchingLines.length} contain l2-block-built`);
|
|
68
|
+
|
|
69
|
+
for (const line of matchingLines) {
|
|
70
|
+
try {
|
|
71
|
+
const parsed = JSON.parse(line);
|
|
72
|
+
if (parsed.eventName !== 'l2-block-built' || !blockNumbers.has(parsed.blockNumber)) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (entriesByBlock.has(parsed.blockNumber)) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const entry: BlockBuiltLogEntry = {} as BlockBuiltLogEntry;
|
|
79
|
+
for (const field of FIELDS) {
|
|
80
|
+
entry[field] = parsed[field] ?? 0;
|
|
81
|
+
}
|
|
82
|
+
entriesByBlock.set(entry.blockNumber, entry);
|
|
83
|
+
logger.verbose(`Parsed l2-block-built log for block ${entry.blockNumber}`, entry);
|
|
84
|
+
} catch {
|
|
85
|
+
// Not valid JSON, skip
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
} catch (err) {
|
|
89
|
+
logger.warn(`Failed to fetch logs from pod ${pod}: ${err}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (entriesByBlock.size < blockNumbers.size) {
|
|
94
|
+
const missing = [...blockNumbers].filter(bn => !entriesByBlock.has(bn));
|
|
95
|
+
logger.warn(`Missing l2-block-built logs for block(s): ${missing.join(', ')}`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return [...entriesByBlock.values()].sort((a, b) => a.blockNumber - b.blockNumber);
|
|
99
|
+
}
|