@aztec/end-to-end 0.0.1-commit.5daedc8 → 0.0.1-commit.6230efd
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/bench/client_flows/client_flows_benchmark.d.ts +3 -3
- package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -1
- package/dest/bench/client_flows/client_flows_benchmark.js +5 -3
- package/dest/bench/utils.d.ts +2 -2
- package/dest/bench/utils.d.ts.map +1 -1
- package/dest/bench/utils.js +10 -6
- package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts +5 -4
- package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts.map +1 -1
- package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.js +2 -1
- package/dest/e2e_epochs/epochs_test.d.ts +11 -9
- package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
- package/dest/e2e_epochs/epochs_test.js +13 -11
- package/dest/e2e_fees/bridging_race.notest.js +1 -1
- package/dest/e2e_fees/fees_test.d.ts +8 -4
- package/dest/e2e_fees/fees_test.d.ts.map +1 -1
- package/dest/e2e_fees/fees_test.js +4 -1
- package/dest/e2e_multi_validator/utils.js +1 -1
- package/dest/e2e_p2p/inactivity_slash_test.d.ts +2 -2
- package/dest/e2e_p2p/inactivity_slash_test.d.ts.map +1 -1
- package/dest/e2e_p2p/inactivity_slash_test.js +3 -6
- package/dest/e2e_p2p/p2p_network.d.ts +7 -6
- package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
- package/dest/e2e_p2p/p2p_network.js +10 -8
- package/dest/e2e_p2p/shared.d.ts +2 -2
- package/dest/e2e_p2p/shared.d.ts.map +1 -1
- package/dest/fixtures/e2e_prover_test.d.ts +3 -5
- package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
- package/dest/fixtures/e2e_prover_test.js +6 -9
- package/dest/fixtures/fixtures.d.ts +2 -3
- package/dest/fixtures/fixtures.d.ts.map +1 -1
- package/dest/fixtures/fixtures.js +2 -3
- package/dest/fixtures/get_acvm_config.js +1 -1
- package/dest/fixtures/l1_to_l2_messaging.d.ts +4 -3
- package/dest/fixtures/l1_to_l2_messaging.d.ts.map +1 -1
- package/dest/fixtures/l1_to_l2_messaging.js +2 -2
- package/dest/fixtures/setup_p2p_test.js +3 -3
- package/dest/fixtures/snapshot_manager.d.ts +6 -8
- package/dest/fixtures/snapshot_manager.d.ts.map +1 -1
- package/dest/fixtures/snapshot_manager.js +34 -46
- package/dest/fixtures/utils.d.ts +20 -463
- package/dest/fixtures/utils.d.ts.map +1 -1
- package/dest/fixtures/utils.js +50 -78
- package/dest/fixtures/web3signer.js +1 -1
- package/dest/fixtures/with_telemetry_utils.d.ts +2 -2
- package/dest/fixtures/with_telemetry_utils.d.ts.map +1 -1
- package/dest/fixtures/with_telemetry_utils.js +2 -2
- package/dest/shared/cross_chain_test_harness.d.ts +5 -3
- package/dest/shared/cross_chain_test_harness.d.ts.map +1 -1
- package/dest/shared/cross_chain_test_harness.js +1 -1
- package/dest/shared/gas_portal_test_harness.d.ts +2 -2
- package/dest/shared/gas_portal_test_harness.d.ts.map +1 -1
- package/dest/shared/uniswap_l1_l2.d.ts +4 -3
- package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
- package/dest/shared/uniswap_l1_l2.js +4 -2
- package/dest/simulators/lending_simulator.d.ts +2 -2
- package/dest/simulators/lending_simulator.d.ts.map +1 -1
- package/dest/simulators/lending_simulator.js +1 -1
- package/dest/spartan/setup_test_wallets.d.ts +1 -1
- package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
- package/dest/spartan/setup_test_wallets.js +2 -1
- package/dest/spartan/tx_metrics.d.ts +39 -0
- package/dest/spartan/tx_metrics.d.ts.map +1 -0
- package/dest/spartan/tx_metrics.js +95 -0
- package/dest/spartan/utils.d.ts +43 -10
- package/dest/spartan/utils.d.ts.map +1 -1
- package/dest/spartan/utils.js +148 -38
- package/package.json +40 -40
- package/src/bench/client_flows/client_flows_benchmark.ts +7 -4
- package/src/bench/utils.ts +11 -7
- package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +13 -9
- package/src/e2e_epochs/epochs_test.ts +33 -20
- package/src/e2e_fees/bridging_race.notest.ts +1 -1
- package/src/e2e_fees/fees_test.ts +10 -4
- package/src/e2e_multi_validator/utils.ts +1 -1
- package/src/e2e_p2p/inactivity_slash_test.ts +4 -7
- package/src/e2e_p2p/p2p_network.ts +9 -16
- package/src/e2e_p2p/shared.ts +5 -1
- package/src/fixtures/e2e_prover_test.ts +8 -10
- package/src/fixtures/fixtures.ts +2 -5
- package/src/fixtures/get_acvm_config.ts +1 -1
- package/src/fixtures/l1_to_l2_messaging.ts +4 -2
- package/src/fixtures/setup_p2p_test.ts +3 -3
- package/src/fixtures/snapshot_manager.ts +51 -65
- package/src/fixtures/utils.ts +79 -138
- package/src/fixtures/web3signer.ts +1 -1
- package/src/fixtures/with_telemetry_utils.ts +2 -2
- package/src/shared/cross_chain_test_harness.ts +5 -2
- package/src/shared/gas_portal_test_harness.ts +1 -1
- package/src/shared/uniswap_l1_l2.ts +8 -10
- package/src/simulators/lending_simulator.ts +2 -2
- package/src/spartan/DEVELOP.md +7 -0
- package/src/spartan/setup_test_wallets.ts +2 -1
- package/src/spartan/tx_metrics.ts +130 -0
- package/src/spartan/utils.ts +207 -31
- package/dest/fixtures/setup_l1_contracts.d.ts +0 -477
- package/dest/fixtures/setup_l1_contracts.d.ts.map +0 -1
- package/dest/fixtures/setup_l1_contracts.js +0 -17
- package/src/fixtures/setup_l1_contracts.ts +0 -26
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import type { AztecNode } from '@aztec/aztec.js/node';
|
|
2
|
+
import type { L2Block } from '@aztec/stdlib/block';
|
|
3
|
+
import { Tx, type TxReceipt, TxStatus } from '@aztec/stdlib/tx';
|
|
4
|
+
|
|
5
|
+
import { createHistogram } from 'perf_hooks';
|
|
6
|
+
|
|
7
|
+
export type TxInclusionData = {
|
|
8
|
+
txHash: string;
|
|
9
|
+
sentAt: number;
|
|
10
|
+
minedAt: number;
|
|
11
|
+
attestedAt: number;
|
|
12
|
+
blocknumber: number;
|
|
13
|
+
priorityFee: number;
|
|
14
|
+
totalFee: number;
|
|
15
|
+
positionInBlock: number;
|
|
16
|
+
group: string;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export class TxInclusionMetrics {
|
|
20
|
+
private data = new Map<string, TxInclusionData>();
|
|
21
|
+
private groups = new Set<string>();
|
|
22
|
+
private blocks = new Map<number, Promise<L2Block>>();
|
|
23
|
+
|
|
24
|
+
constructor(private aztecNode: AztecNode) {}
|
|
25
|
+
|
|
26
|
+
recordSentTx(tx: Tx, group: string): void {
|
|
27
|
+
const txHash = tx.getTxHash().toString();
|
|
28
|
+
const priorityFees = tx.getGasSettings().maxPriorityFeesPerGas;
|
|
29
|
+
|
|
30
|
+
this.data.set(txHash, {
|
|
31
|
+
txHash,
|
|
32
|
+
sentAt: Math.trunc(Date.now() / 1000),
|
|
33
|
+
minedAt: -1,
|
|
34
|
+
attestedAt: -1,
|
|
35
|
+
blocknumber: -1,
|
|
36
|
+
priorityFee: Number(priorityFees.feePerDaGas + priorityFees.feePerL2Gas),
|
|
37
|
+
totalFee: -1,
|
|
38
|
+
positionInBlock: -1,
|
|
39
|
+
group,
|
|
40
|
+
});
|
|
41
|
+
this.groups.add(group);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async recordMinedTx(txReceipt: TxReceipt): Promise<void> {
|
|
45
|
+
const { status, txHash, blockNumber } = txReceipt;
|
|
46
|
+
if (status !== TxStatus.SUCCESS || !blockNumber) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!this.blocks.has(blockNumber)) {
|
|
51
|
+
this.blocks.set(blockNumber, this.aztecNode.getBlock(blockNumber) as Promise<L2Block>);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const block = await this.blocks.get(blockNumber)!;
|
|
55
|
+
const data = this.data.get(txHash.toString())!;
|
|
56
|
+
data.blocknumber = blockNumber;
|
|
57
|
+
data.minedAt = Number(block.header.globalVariables.timestamp);
|
|
58
|
+
data.attestedAt = -1;
|
|
59
|
+
data.totalFee = Number(txReceipt.transactionFee ?? 0n);
|
|
60
|
+
data.positionInBlock = block.body.txEffects.findIndex(txEffect => txEffect.txHash.equals(txHash));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public inclusionTimeInSeconds(group: string): {
|
|
64
|
+
count: number;
|
|
65
|
+
group: string;
|
|
66
|
+
min: number;
|
|
67
|
+
mean: number;
|
|
68
|
+
max: number;
|
|
69
|
+
median: number;
|
|
70
|
+
p99: number;
|
|
71
|
+
} {
|
|
72
|
+
const histogram = createHistogram({});
|
|
73
|
+
for (const tx of this.data.values()) {
|
|
74
|
+
if (!tx.blocknumber || tx.group !== group) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
histogram.record(tx.minedAt - tx.sentAt);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (histogram.count === 0) {
|
|
82
|
+
return {
|
|
83
|
+
group,
|
|
84
|
+
count: 0,
|
|
85
|
+
mean: 0,
|
|
86
|
+
max: 0,
|
|
87
|
+
median: 0,
|
|
88
|
+
min: 0,
|
|
89
|
+
p99: 0,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
group,
|
|
95
|
+
count: histogram.count,
|
|
96
|
+
mean: histogram.mean,
|
|
97
|
+
max: histogram.max,
|
|
98
|
+
median: histogram.percentile(50),
|
|
99
|
+
min: histogram.min,
|
|
100
|
+
p99: histogram.percentile(99),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
toGithubActionBenchmarkJSON(): Array<{ name: string; unit: string; value: number; range?: number; extra?: string }> {
|
|
105
|
+
const data: Array<{ name: string; unit: string; value: number; range?: number; extra?: string }> = [];
|
|
106
|
+
for (const group of this.groups) {
|
|
107
|
+
const stats = this.inclusionTimeInSeconds(group);
|
|
108
|
+
|
|
109
|
+
data.push(
|
|
110
|
+
{
|
|
111
|
+
name: `${group}/avg_inclusion`,
|
|
112
|
+
unit: 's',
|
|
113
|
+
value: stats.mean,
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: `${group}/median_inclusion`,
|
|
117
|
+
unit: 's',
|
|
118
|
+
value: stats.median,
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: `${group}/p99_inclusion`,
|
|
122
|
+
unit: 's',
|
|
123
|
+
value: stats.p99,
|
|
124
|
+
},
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return data;
|
|
129
|
+
}
|
|
130
|
+
}
|
package/src/spartan/utils.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { createLogger } from '@aztec/aztec.js/log';
|
|
2
2
|
import type { RollupCheatCodes } from '@aztec/aztec/testing';
|
|
3
|
-
import type { L1ContractAddresses
|
|
3
|
+
import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
|
|
4
|
+
import type { ViemPublicClient } from '@aztec/ethereum/types';
|
|
5
|
+
import type { CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
4
6
|
import type { Logger } from '@aztec/foundation/log';
|
|
5
7
|
import { promiseWithResolvers } from '@aztec/foundation/promise';
|
|
6
8
|
import { makeBackoff, retry } from '@aztec/foundation/retry';
|
|
@@ -30,6 +32,7 @@ const testConfigSchema = z.object({
|
|
|
30
32
|
L1_RPC_URLS_JSON: z.string().optional(),
|
|
31
33
|
L1_ACCOUNT_MNEMONIC: z.string().optional(),
|
|
32
34
|
AZTEC_SLOT_DURATION: z.coerce.number().optional().default(24),
|
|
35
|
+
AZTEC_EPOCH_DURATION: z.coerce.number().optional().default(32),
|
|
33
36
|
AZTEC_PROOF_SUBMISSION_WINDOW: z.coerce.number().optional().default(5),
|
|
34
37
|
});
|
|
35
38
|
|
|
@@ -194,9 +197,9 @@ export function getExternalIP(namespace: string, serviceName: string): Promise<s
|
|
|
194
197
|
return promise;
|
|
195
198
|
}
|
|
196
199
|
|
|
197
|
-
export function startPortForwardForRPC(namespace: string,
|
|
200
|
+
export function startPortForwardForRPC(namespace: string, index = 0) {
|
|
198
201
|
return startPortForward({
|
|
199
|
-
resource:
|
|
202
|
+
resource: `pod/${namespace}-rpc-aztec-node-${index}`,
|
|
200
203
|
namespace,
|
|
201
204
|
containerPort: 8080,
|
|
202
205
|
});
|
|
@@ -242,11 +245,11 @@ export async function deleteResourceByLabel({
|
|
|
242
245
|
timeout?: string;
|
|
243
246
|
force?: boolean;
|
|
244
247
|
}) {
|
|
245
|
-
// Check if the resource type exists before attempting to delete
|
|
246
248
|
try {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
)
|
|
249
|
+
// Match both plain and group-qualified names (e.g., "podchaos" or "podchaos.chaos-mesh.org")
|
|
250
|
+
const escaped = resource.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
251
|
+
const regex = `(^|\\.)${escaped}(\\.|$)`;
|
|
252
|
+
await execAsync(`kubectl api-resources --no-headers -o name | grep -Eq '${regex}'`);
|
|
250
253
|
} catch (error) {
|
|
251
254
|
logger.warn(`Resource type '${resource}' not found in cluster, skipping deletion ${error}`);
|
|
252
255
|
return '';
|
|
@@ -279,6 +282,58 @@ export async function waitForResourceByLabel({
|
|
|
279
282
|
return stdout;
|
|
280
283
|
}
|
|
281
284
|
|
|
285
|
+
export async function waitForResourceByName({
|
|
286
|
+
resource,
|
|
287
|
+
name,
|
|
288
|
+
namespace,
|
|
289
|
+
condition = 'Ready',
|
|
290
|
+
timeout = '10m',
|
|
291
|
+
}: {
|
|
292
|
+
resource: string;
|
|
293
|
+
name: string;
|
|
294
|
+
namespace: string;
|
|
295
|
+
condition?: string;
|
|
296
|
+
timeout?: string;
|
|
297
|
+
}) {
|
|
298
|
+
const command = `kubectl wait ${resource}/${name} --for=condition=${condition} -n ${namespace} --timeout=${timeout}`;
|
|
299
|
+
logger.info(`command: ${command}`);
|
|
300
|
+
const { stdout } = await execAsync(command);
|
|
301
|
+
return stdout;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export async function waitForResourcesByName({
|
|
305
|
+
resource,
|
|
306
|
+
names,
|
|
307
|
+
namespace,
|
|
308
|
+
condition = 'Ready',
|
|
309
|
+
timeout = '10m',
|
|
310
|
+
}: {
|
|
311
|
+
resource: string;
|
|
312
|
+
names: string[];
|
|
313
|
+
namespace: string;
|
|
314
|
+
condition?: string;
|
|
315
|
+
timeout?: string;
|
|
316
|
+
}) {
|
|
317
|
+
if (!names.length) {
|
|
318
|
+
throw new Error(`No ${resource} names provided to waitForResourcesByName`);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Wait all in parallel; if any fails, surface which one.
|
|
322
|
+
await Promise.all(
|
|
323
|
+
names.map(async name => {
|
|
324
|
+
try {
|
|
325
|
+
await waitForResourceByName({ resource, name, namespace, condition, timeout });
|
|
326
|
+
} catch (err) {
|
|
327
|
+
throw new Error(
|
|
328
|
+
`Failed waiting for ${resource}/${name} condition=${condition} timeout=${timeout} namespace=${namespace}: ${String(
|
|
329
|
+
err,
|
|
330
|
+
)}`,
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
}),
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
|
|
282
337
|
export function getChartDir(spartanDir: string, chartName: string) {
|
|
283
338
|
return path.join(spartanDir.trim(), chartName);
|
|
284
339
|
}
|
|
@@ -329,7 +384,36 @@ async function execHelmCommand(args: Parameters<typeof createHelmCommand>[0]) {
|
|
|
329
384
|
return stdout;
|
|
330
385
|
}
|
|
331
386
|
|
|
332
|
-
|
|
387
|
+
async function getHelmReleaseStatus(instanceName: string, namespace: string): Promise<string | undefined> {
|
|
388
|
+
try {
|
|
389
|
+
const { stdout } = await execAsync(
|
|
390
|
+
`helm list --namespace ${namespace} --all --filter '^${instanceName}$' --output json | cat`,
|
|
391
|
+
);
|
|
392
|
+
const parsed = JSON.parse(stdout) as Array<{ name?: string; status?: string }>;
|
|
393
|
+
const row = parsed.find(r => r.name === instanceName);
|
|
394
|
+
return row?.status;
|
|
395
|
+
} catch {
|
|
396
|
+
return undefined;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
async function forceDeleteHelmReleaseRecord(instanceName: string, namespace: string, logger: Logger) {
|
|
401
|
+
const labelSelector = `owner=helm,name=${instanceName}`;
|
|
402
|
+
const cmd = `kubectl delete secret -n ${namespace} -l ${labelSelector} --ignore-not-found=true`;
|
|
403
|
+
logger.warn(`Force deleting Helm release record: ${cmd}`);
|
|
404
|
+
await execAsync(cmd).catch(() => undefined);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
async function hasDeployedHelmRelease(instanceName: string, namespace: string): Promise<boolean> {
|
|
408
|
+
try {
|
|
409
|
+
const status = await getHelmReleaseStatus(instanceName, namespace);
|
|
410
|
+
return status?.toLowerCase() === 'deployed';
|
|
411
|
+
} catch {
|
|
412
|
+
return false;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
export async function uninstallChaosMesh(instanceName: string, namespace: string, logger: Logger) {
|
|
333
417
|
// uninstall the helm chart if it exists
|
|
334
418
|
logger.info(`Uninstalling helm chart ${instanceName}`);
|
|
335
419
|
await execAsync(`helm uninstall ${instanceName} --namespace ${namespace} --wait --ignore-not-found`);
|
|
@@ -393,7 +477,7 @@ export async function installChaosMeshChart({
|
|
|
393
477
|
logger: Logger;
|
|
394
478
|
}) {
|
|
395
479
|
if (clean) {
|
|
396
|
-
await
|
|
480
|
+
await uninstallChaosMesh(instanceName, targetNamespace, logger);
|
|
397
481
|
}
|
|
398
482
|
|
|
399
483
|
return execHelmCommand({
|
|
@@ -429,22 +513,49 @@ export function applyProverFailure({
|
|
|
429
513
|
});
|
|
430
514
|
}
|
|
431
515
|
|
|
516
|
+
export function applyValidatorFailure({
|
|
517
|
+
namespace,
|
|
518
|
+
spartanDir,
|
|
519
|
+
logger,
|
|
520
|
+
values,
|
|
521
|
+
instanceName,
|
|
522
|
+
}: {
|
|
523
|
+
namespace: string;
|
|
524
|
+
spartanDir: string;
|
|
525
|
+
logger: Logger;
|
|
526
|
+
values?: Record<string, string | number>;
|
|
527
|
+
instanceName?: string;
|
|
528
|
+
}) {
|
|
529
|
+
return installChaosMeshChart({
|
|
530
|
+
instanceName: instanceName ?? 'validator-failure',
|
|
531
|
+
targetNamespace: namespace,
|
|
532
|
+
valuesFile: 'validator-failure.yaml',
|
|
533
|
+
helmChartDir: getChartDir(spartanDir, 'aztec-chaos-scenarios'),
|
|
534
|
+
values,
|
|
535
|
+
logger,
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
|
|
432
539
|
export function applyProverKill({
|
|
433
540
|
namespace,
|
|
434
541
|
spartanDir,
|
|
435
542
|
logger,
|
|
543
|
+
values,
|
|
436
544
|
}: {
|
|
437
545
|
namespace: string;
|
|
438
546
|
spartanDir: string;
|
|
439
547
|
logger: Logger;
|
|
548
|
+
values?: Record<string, string | number>;
|
|
440
549
|
}) {
|
|
441
550
|
return installChaosMeshChart({
|
|
442
551
|
instanceName: 'prover-kill',
|
|
443
552
|
targetNamespace: namespace,
|
|
444
553
|
valuesFile: 'prover-kill.yaml',
|
|
445
554
|
helmChartDir: getChartDir(spartanDir, 'aztec-chaos-scenarios'),
|
|
555
|
+
chaosMeshNamespace: namespace,
|
|
446
556
|
clean: true,
|
|
447
557
|
logger,
|
|
558
|
+
values,
|
|
448
559
|
});
|
|
449
560
|
}
|
|
450
561
|
|
|
@@ -452,10 +563,12 @@ export function applyProverBrokerKill({
|
|
|
452
563
|
namespace,
|
|
453
564
|
spartanDir,
|
|
454
565
|
logger,
|
|
566
|
+
values,
|
|
455
567
|
}: {
|
|
456
568
|
namespace: string;
|
|
457
569
|
spartanDir: string;
|
|
458
570
|
logger: Logger;
|
|
571
|
+
values?: Record<string, string | number>;
|
|
459
572
|
}) {
|
|
460
573
|
return installChaosMeshChart({
|
|
461
574
|
instanceName: 'prover-broker-kill',
|
|
@@ -464,66 +577,79 @@ export function applyProverBrokerKill({
|
|
|
464
577
|
helmChartDir: getChartDir(spartanDir, 'aztec-chaos-scenarios'),
|
|
465
578
|
clean: true,
|
|
466
579
|
logger,
|
|
580
|
+
values,
|
|
467
581
|
});
|
|
468
582
|
}
|
|
469
583
|
|
|
470
584
|
export function applyBootNodeFailure({
|
|
585
|
+
instanceName = 'boot-node-failure',
|
|
471
586
|
namespace,
|
|
472
587
|
spartanDir,
|
|
473
588
|
durationSeconds,
|
|
474
589
|
logger,
|
|
590
|
+
values,
|
|
475
591
|
}: {
|
|
592
|
+
instanceName?: string;
|
|
476
593
|
namespace: string;
|
|
477
594
|
spartanDir: string;
|
|
478
595
|
durationSeconds: number;
|
|
479
596
|
logger: Logger;
|
|
597
|
+
values?: Record<string, string | number>;
|
|
480
598
|
}) {
|
|
481
599
|
return installChaosMeshChart({
|
|
482
|
-
instanceName
|
|
600
|
+
instanceName,
|
|
483
601
|
targetNamespace: namespace,
|
|
484
602
|
valuesFile: 'boot-node-failure.yaml',
|
|
485
603
|
helmChartDir: getChartDir(spartanDir, 'aztec-chaos-scenarios'),
|
|
486
604
|
values: {
|
|
487
605
|
'bootNodeFailure.duration': `${durationSeconds}s`,
|
|
606
|
+
...(values ?? {}),
|
|
488
607
|
},
|
|
489
608
|
logger,
|
|
490
609
|
});
|
|
491
610
|
}
|
|
492
611
|
|
|
493
612
|
export function applyValidatorKill({
|
|
613
|
+
instanceName = 'validator-kill',
|
|
494
614
|
namespace,
|
|
495
615
|
spartanDir,
|
|
496
616
|
logger,
|
|
497
617
|
values,
|
|
618
|
+
clean = true,
|
|
498
619
|
}: {
|
|
620
|
+
instanceName?: string;
|
|
499
621
|
namespace: string;
|
|
500
622
|
spartanDir: string;
|
|
501
623
|
logger: Logger;
|
|
502
624
|
values?: Record<string, string | number>;
|
|
625
|
+
clean?: boolean;
|
|
503
626
|
}) {
|
|
504
627
|
return installChaosMeshChart({
|
|
505
|
-
instanceName: 'validator-kill',
|
|
628
|
+
instanceName: instanceName ?? 'validator-kill',
|
|
506
629
|
targetNamespace: namespace,
|
|
507
630
|
valuesFile: 'validator-kill.yaml',
|
|
508
631
|
helmChartDir: getChartDir(spartanDir, 'aztec-chaos-scenarios'),
|
|
632
|
+
clean,
|
|
509
633
|
logger,
|
|
510
634
|
values,
|
|
511
635
|
});
|
|
512
636
|
}
|
|
513
637
|
|
|
514
638
|
export function applyNetworkShaping({
|
|
639
|
+
instanceName = 'network-shaping',
|
|
515
640
|
valuesFile,
|
|
516
641
|
namespace,
|
|
517
642
|
spartanDir,
|
|
518
643
|
logger,
|
|
519
644
|
}: {
|
|
645
|
+
instanceName?: string;
|
|
520
646
|
valuesFile: string;
|
|
521
647
|
namespace: string;
|
|
522
648
|
spartanDir: string;
|
|
523
649
|
logger: Logger;
|
|
524
650
|
}) {
|
|
525
651
|
return installChaosMeshChart({
|
|
526
|
-
instanceName
|
|
652
|
+
instanceName,
|
|
527
653
|
targetNamespace: namespace,
|
|
528
654
|
valuesFile,
|
|
529
655
|
helmChartDir: getChartDir(spartanDir, 'aztec-chaos-scenarios'),
|
|
@@ -531,24 +657,24 @@ export function applyNetworkShaping({
|
|
|
531
657
|
});
|
|
532
658
|
}
|
|
533
659
|
|
|
534
|
-
export async function
|
|
660
|
+
export async function awaitCheckpointNumber(
|
|
535
661
|
rollupCheatCodes: RollupCheatCodes,
|
|
536
|
-
|
|
662
|
+
checkpointNumber: CheckpointNumber,
|
|
537
663
|
timeoutSeconds: number,
|
|
538
664
|
logger: Logger,
|
|
539
665
|
) {
|
|
540
|
-
logger.info(`Waiting for
|
|
666
|
+
logger.info(`Waiting for checkpoint ${checkpointNumber}`);
|
|
541
667
|
let tips = await rollupCheatCodes.getTips();
|
|
542
668
|
const endTime = Date.now() + timeoutSeconds * 1000;
|
|
543
|
-
while (tips.pending <
|
|
544
|
-
logger.info(`At
|
|
669
|
+
while (tips.pending < checkpointNumber && Date.now() < endTime) {
|
|
670
|
+
logger.info(`At checkpoint ${tips.pending}`);
|
|
545
671
|
await sleep(1000);
|
|
546
672
|
tips = await rollupCheatCodes.getTips();
|
|
547
673
|
}
|
|
548
|
-
if (tips.pending <
|
|
549
|
-
throw new Error(`Timeout waiting for
|
|
674
|
+
if (tips.pending < checkpointNumber) {
|
|
675
|
+
throw new Error(`Timeout waiting for checkpoint ${checkpointNumber}, only reached ${tips.pending}`);
|
|
550
676
|
} else {
|
|
551
|
-
logger.info(`Reached
|
|
677
|
+
logger.info(`Reached checkpoint ${tips.pending}`);
|
|
552
678
|
}
|
|
553
679
|
}
|
|
554
680
|
|
|
@@ -622,6 +748,12 @@ export async function installTransferBot({
|
|
|
622
748
|
'bot.node.env.ETHEREUM_HOSTS': `http://${namespace}-eth-execution.${namespace}.svc.cluster.local:8545`,
|
|
623
749
|
// Provide L1 mnemonic for bridging (falls back to labs mnemonic)
|
|
624
750
|
'bot.node.env.BOT_L1_MNEMONIC': mnemonic,
|
|
751
|
+
|
|
752
|
+
// The bot does not need Kubernetes API access. Disable RBAC + ServiceAccount creation so the chart
|
|
753
|
+
// can be installed by users without cluster-scoped RBAC permissions.
|
|
754
|
+
'bot.rbac.create': false,
|
|
755
|
+
'bot.serviceAccount.create': false,
|
|
756
|
+
'bot.serviceAccount.name': 'default',
|
|
625
757
|
};
|
|
626
758
|
// Ensure we derive a funded L1 key (index 0 is funded on anvil default mnemonic)
|
|
627
759
|
if (mnemonicStartIndex === undefined) {
|
|
@@ -646,7 +778,7 @@ export async function installTransferBot({
|
|
|
646
778
|
if (!repository || !tag) {
|
|
647
779
|
try {
|
|
648
780
|
const { stdout } = await execAsync(
|
|
649
|
-
`kubectl get pods -l app.kubernetes.io/
|
|
781
|
+
`kubectl get pods -l app.kubernetes.io/name=validator -n ${namespace} -o jsonpath='{.items[0].spec.containers[?(@.name=="aztec")].image}' | cat`,
|
|
650
782
|
);
|
|
651
783
|
const image = stdout.trim().replace(/^'|'$/g, '');
|
|
652
784
|
if (image && image.includes(':')) {
|
|
@@ -667,6 +799,26 @@ export async function installTransferBot({
|
|
|
667
799
|
typeof mnemonicStartIndex === 'string' ? mnemonicStartIndex : Number(mnemonicStartIndex);
|
|
668
800
|
}
|
|
669
801
|
|
|
802
|
+
// If a previous install attempt left the release in a non-deployed state (e.g. FAILED),
|
|
803
|
+
// `helm upgrade --install` can error with "has no deployed releases".
|
|
804
|
+
// In that case, clear the release record and do a clean install.
|
|
805
|
+
const existingStatus = await getHelmReleaseStatus(instanceName, namespace);
|
|
806
|
+
if (existingStatus && existingStatus.toLowerCase() !== 'deployed') {
|
|
807
|
+
logger.warn(`Transfer bot release ${instanceName} is in status '${existingStatus}'. Reinstalling cleanly.`);
|
|
808
|
+
await execAsync(`helm uninstall ${instanceName} --namespace ${namespace} --wait --ignore-not-found`).catch(
|
|
809
|
+
() => undefined,
|
|
810
|
+
);
|
|
811
|
+
// If helm left the release in `uninstalling`, force-delete the record so we can reinstall.
|
|
812
|
+
const afterUninstallStatus = await getHelmReleaseStatus(instanceName, namespace);
|
|
813
|
+
if (afterUninstallStatus?.toLowerCase() === 'uninstalling') {
|
|
814
|
+
await forceDeleteHelmReleaseRecord(instanceName, namespace, logger);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
// `--reuse-values` fails if the release has never successfully deployed (e.g. first install, or a previous failed install).
|
|
819
|
+
// Only reuse values when we have a deployed release to reuse from.
|
|
820
|
+
const effectiveReuseValues = reuseValues && (await hasDeployedHelmRelease(instanceName, namespace));
|
|
821
|
+
|
|
670
822
|
await execHelmCommand({
|
|
671
823
|
instanceName,
|
|
672
824
|
helmChartDir,
|
|
@@ -674,7 +826,7 @@ export async function installTransferBot({
|
|
|
674
826
|
valuesFile: undefined,
|
|
675
827
|
timeout,
|
|
676
828
|
values: values as unknown as Record<string, string | number | boolean>,
|
|
677
|
-
reuseValues,
|
|
829
|
+
reuseValues: effectiveReuseValues,
|
|
678
830
|
});
|
|
679
831
|
|
|
680
832
|
if (replicas > 0) {
|
|
@@ -719,7 +871,7 @@ export async function setValidatorTxDrop({
|
|
|
719
871
|
const drop = enabled ? 'true' : 'false';
|
|
720
872
|
const prob = String(probability);
|
|
721
873
|
|
|
722
|
-
const selectors = ['app=validator', 'app.kubernetes.io/component=validator'];
|
|
874
|
+
const selectors = ['app.kubernetes.io/name=validator', 'app.kubernetes.io/component=validator', 'app=validator'];
|
|
723
875
|
let updated = false;
|
|
724
876
|
for (const selector of selectors) {
|
|
725
877
|
try {
|
|
@@ -750,7 +902,7 @@ export async function setValidatorTxDrop({
|
|
|
750
902
|
}
|
|
751
903
|
|
|
752
904
|
export async function restartValidators(namespace: string, logger: Logger) {
|
|
753
|
-
const selectors = ['app=validator', 'app.kubernetes.io/component=validator'];
|
|
905
|
+
const selectors = ['app.kubernetes.io/name=validator', 'app.kubernetes.io/component=validator', 'app=validator'];
|
|
754
906
|
let any = false;
|
|
755
907
|
for (const selector of selectors) {
|
|
756
908
|
try {
|
|
@@ -805,11 +957,33 @@ export async function enableValidatorDynamicBootNode(
|
|
|
805
957
|
}
|
|
806
958
|
|
|
807
959
|
export async function getSequencers(namespace: string) {
|
|
808
|
-
const
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
960
|
+
const selectors = [
|
|
961
|
+
'app.kubernetes.io/name=validator',
|
|
962
|
+
'app.kubernetes.io/component=validator',
|
|
963
|
+
'app.kubernetes.io/component=sequencer-node',
|
|
964
|
+
'app=validator',
|
|
965
|
+
];
|
|
966
|
+
for (const selector of selectors) {
|
|
967
|
+
try {
|
|
968
|
+
const command = `kubectl get pods -l ${selector} -n ${namespace} -o jsonpath='{.items[*].metadata.name}'`;
|
|
969
|
+
const { stdout } = await execAsync(command);
|
|
970
|
+
const sequencers = stdout
|
|
971
|
+
.split(' ')
|
|
972
|
+
.map(s => s.trim())
|
|
973
|
+
.filter(Boolean);
|
|
974
|
+
if (sequencers.length > 0) {
|
|
975
|
+
logger.verbose(`Found sequencer pods ${sequencers.join(', ')} (selector=${selector})`);
|
|
976
|
+
return sequencers;
|
|
977
|
+
}
|
|
978
|
+
} catch {
|
|
979
|
+
// try next selector
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
// Fail fast instead of returning [''] which leads to attempts to port-forward `pod/`.
|
|
984
|
+
throw new Error(
|
|
985
|
+
`No sequencer/validator pods found in namespace ${namespace}. Tried selectors: ${selectors.join(', ')}`,
|
|
986
|
+
);
|
|
813
987
|
}
|
|
814
988
|
|
|
815
989
|
export function updateSequencersConfig(env: TestConfig, config: Partial<AztecNodeAdminConfig>) {
|
|
@@ -870,7 +1044,7 @@ export async function getPublicViemClient(
|
|
|
870
1044
|
containerPort: 8545,
|
|
871
1045
|
});
|
|
872
1046
|
const url = `http://127.0.0.1:${port}`;
|
|
873
|
-
const client: ViemPublicClient = createPublicClient({ transport: fallback([http(url)]) });
|
|
1047
|
+
const client: ViemPublicClient = createPublicClient({ transport: fallback([http(url, { batch: false })]) });
|
|
874
1048
|
if (processes) {
|
|
875
1049
|
processes.push(process);
|
|
876
1050
|
}
|
|
@@ -880,7 +1054,9 @@ export async function getPublicViemClient(
|
|
|
880
1054
|
if (!L1_RPC_URLS_JSON) {
|
|
881
1055
|
throw new Error(`L1_RPC_URLS_JSON is not defined`);
|
|
882
1056
|
}
|
|
883
|
-
const client: ViemPublicClient = createPublicClient({
|
|
1057
|
+
const client: ViemPublicClient = createPublicClient({
|
|
1058
|
+
transport: fallback([http(L1_RPC_URLS_JSON, { batch: false })]),
|
|
1059
|
+
});
|
|
884
1060
|
return { url: L1_RPC_URLS_JSON, client };
|
|
885
1061
|
}
|
|
886
1062
|
}
|