@aztec/end-to-end 0.0.1-commit.c80b6263 → 0.0.1-commit.cd76b27
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 +2 -2
- package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -1
- package/dest/bench/client_flows/client_flows_benchmark.js +3 -3
- package/dest/bench/client_flows/config.d.ts +2 -2
- package/dest/bench/client_flows/config.d.ts.map +1 -1
- package/dest/bench/client_flows/config.js +18 -0
- package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +4 -2
- package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts.map +1 -1
- package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.js +10 -0
- package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts +2 -2
- 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 +3 -2
- package/dest/e2e_deploy_contract/deploy_test.d.ts +2 -2
- package/dest/e2e_deploy_contract/deploy_test.d.ts.map +1 -1
- package/dest/e2e_epochs/epochs_test.d.ts +9 -7
- package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
- package/dest/e2e_epochs/epochs_test.js +58 -33
- package/dest/e2e_fees/fees_test.d.ts +2 -2
- package/dest/e2e_fees/fees_test.d.ts.map +1 -1
- package/dest/e2e_fees/fees_test.js +5 -5
- package/dest/e2e_l1_publisher/write_json.d.ts +3 -2
- package/dest/e2e_l1_publisher/write_json.d.ts.map +1 -1
- package/dest/e2e_l1_publisher/write_json.js +1 -7
- package/dest/e2e_p2p/p2p_network.d.ts +2 -2
- package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
- package/dest/e2e_p2p/p2p_network.js +16 -2
- package/dest/e2e_p2p/reqresp/utils.d.ts +22 -0
- package/dest/e2e_p2p/reqresp/utils.d.ts.map +1 -0
- package/dest/e2e_p2p/reqresp/utils.js +177 -0
- package/dest/e2e_p2p/shared.d.ts +2 -2
- package/dest/e2e_p2p/shared.d.ts.map +1 -1
- package/dest/e2e_p2p/shared.js +5 -1
- package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.d.ts +2 -0
- package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.d.ts.map +1 -0
- package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.js +184 -0
- package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.d.ts +18 -0
- package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.d.ts.map +1 -0
- package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.js +120 -0
- package/dest/e2e_token_contract/token_contract_test.d.ts +4 -2
- package/dest/e2e_token_contract/token_contract_test.d.ts.map +1 -1
- package/dest/e2e_token_contract/token_contract_test.js +10 -0
- package/dest/fixtures/authwit_proxy.d.ts +15 -0
- package/dest/fixtures/authwit_proxy.d.ts.map +1 -0
- package/dest/fixtures/authwit_proxy.js +30 -0
- package/dest/fixtures/e2e_prover_test.d.ts +4 -4
- package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
- package/dest/fixtures/e2e_prover_test.js +27 -34
- package/dest/fixtures/fixtures.d.ts +5 -1
- package/dest/fixtures/fixtures.d.ts.map +1 -1
- package/dest/fixtures/fixtures.js +6 -0
- package/dest/fixtures/ha_setup.d.ts +71 -0
- package/dest/fixtures/ha_setup.d.ts.map +1 -0
- package/dest/fixtures/ha_setup.js +116 -0
- package/dest/fixtures/index.d.ts +2 -1
- package/dest/fixtures/index.d.ts.map +1 -1
- package/dest/fixtures/index.js +1 -0
- package/dest/fixtures/setup.d.ts +39 -22
- package/dest/fixtures/setup.d.ts.map +1 -1
- package/dest/fixtures/setup.js +59 -149
- package/dest/fixtures/setup_p2p_test.d.ts +15 -7
- package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
- package/dest/fixtures/setup_p2p_test.js +18 -12
- package/dest/shared/index.d.ts +2 -1
- package/dest/shared/index.d.ts.map +1 -1
- package/dest/shared/index.js +1 -0
- package/dest/shared/mock_state_view.d.ts +86 -0
- package/dest/shared/mock_state_view.d.ts.map +1 -0
- package/dest/shared/mock_state_view.js +186 -0
- package/dest/shared/submit-transactions.d.ts +2 -2
- package/dest/shared/submit-transactions.d.ts.map +1 -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 +8 -6
- package/dest/simulators/token_simulator.d.ts +1 -1
- package/dest/simulators/token_simulator.d.ts.map +1 -1
- package/dest/simulators/token_simulator.js +2 -23
- package/dest/spartan/setup_test_wallets.d.ts +9 -2
- package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
- package/dest/spartan/setup_test_wallets.js +31 -1
- package/dest/spartan/utils/bot.d.ts +3 -2
- package/dest/spartan/utils/bot.d.ts.map +1 -1
- package/dest/spartan/utils/bot.js +2 -1
- 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 +2 -1
- package/dest/spartan/utils/index.d.ts +4 -4
- package/dest/spartan/utils/index.d.ts.map +1 -1
- package/dest/spartan/utils/index.js +2 -2
- package/dest/spartan/utils/k8s.d.ts +31 -1
- package/dest/spartan/utils/k8s.d.ts.map +1 -1
- package/dest/spartan/utils/k8s.js +124 -0
- package/dest/spartan/utils/nodes.d.ts +11 -1
- package/dest/spartan/utils/nodes.d.ts.map +1 -1
- package/dest/spartan/utils/nodes.js +198 -27
- package/dest/spartan/utils/scripts.d.ts +18 -4
- package/dest/spartan/utils/scripts.d.ts.map +1 -1
- package/dest/spartan/utils/scripts.js +19 -4
- package/dest/test-wallet/test_wallet.d.ts +83 -0
- package/dest/test-wallet/test_wallet.d.ts.map +1 -0
- package/dest/test-wallet/test_wallet.js +214 -0
- package/dest/test-wallet/utils.d.ts +41 -0
- package/dest/test-wallet/utils.d.ts.map +1 -0
- package/dest/test-wallet/utils.js +71 -0
- package/dest/test-wallet/wallet_worker_script.d.ts +2 -0
- package/dest/test-wallet/wallet_worker_script.d.ts.map +1 -0
- package/dest/test-wallet/wallet_worker_script.js +40 -0
- package/dest/test-wallet/worker_wallet.d.ts +52 -0
- package/dest/test-wallet/worker_wallet.d.ts.map +1 -0
- package/dest/test-wallet/worker_wallet.js +103 -0
- package/dest/test-wallet/worker_wallet_schema.d.ts +271 -0
- package/dest/test-wallet/worker_wallet_schema.d.ts.map +1 -0
- package/dest/test-wallet/worker_wallet_schema.js +10 -0
- package/package.json +43 -39
- package/src/bench/client_flows/client_flows_benchmark.ts +8 -12
- package/src/bench/client_flows/config.ts +9 -1
- package/src/bench/utils.ts +1 -1
- package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +11 -2
- package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +7 -8
- package/src/e2e_deploy_contract/deploy_test.ts +3 -3
- package/src/e2e_epochs/epochs_test.ts +73 -63
- package/src/e2e_fees/bridging_race.notest.ts +1 -1
- package/src/e2e_fees/fees_test.ts +11 -26
- package/src/e2e_l1_publisher/write_json.ts +1 -6
- package/src/e2e_nested_contract/nested_contract_test.ts +1 -1
- package/src/e2e_p2p/inactivity_slash_test.ts +4 -4
- package/src/e2e_p2p/p2p_network.ts +29 -7
- package/src/e2e_p2p/reqresp/utils.ts +235 -0
- package/src/e2e_p2p/shared.ts +3 -1
- package/src/e2e_storage_proof/fixtures/storage_proof.json +915 -0
- package/src/e2e_storage_proof/fixtures/storage_proof_fetcher.ts +190 -0
- package/src/e2e_storage_proof/fixtures/storage_proof_fixture.ts +173 -0
- package/src/e2e_token_contract/token_contract_test.ts +11 -2
- package/src/fixtures/authwit_proxy.ts +50 -0
- package/src/fixtures/dumps/epoch_proof_result.json +1 -1
- package/src/fixtures/e2e_prover_test.ts +28 -38
- package/src/fixtures/fixtures.ts +10 -0
- package/src/fixtures/ha_setup.ts +186 -0
- package/src/fixtures/index.ts +1 -0
- package/src/fixtures/setup.ts +89 -210
- package/src/fixtures/setup_p2p_test.ts +25 -24
- package/src/guides/up_quick_start.sh +3 -3
- package/src/shared/index.ts +1 -0
- package/src/shared/mock_state_view.ts +188 -0
- package/src/shared/submit-transactions.ts +2 -1
- package/src/shared/uniswap_l1_l2.ts +9 -11
- package/src/simulators/token_simulator.ts +1 -29
- package/src/spartan/setup_test_wallets.ts +43 -1
- package/src/spartan/utils/bot.ts +4 -1
- package/src/spartan/utils/config.ts +1 -0
- package/src/spartan/utils/index.ts +4 -1
- package/src/spartan/utils/k8s.ts +160 -0
- package/src/spartan/utils/nodes.ts +239 -24
- package/src/spartan/utils/scripts.ts +43 -7
- package/src/test-wallet/test_wallet.ts +306 -0
- package/src/test-wallet/utils.ts +112 -0
- package/src/test-wallet/wallet_worker_script.ts +43 -0
- package/src/test-wallet/worker_wallet.ts +165 -0
- package/src/test-wallet/worker_wallet_schema.ts +13 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { createLogger } from '@aztec/aztec.js/log';
|
|
2
|
+
import { createAztecNodeClient } from '@aztec/aztec.js/node';
|
|
2
3
|
import type { RollupCheatCodes } from '@aztec/aztec/testing';
|
|
3
4
|
import type { CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
4
5
|
import type { Logger } from '@aztec/foundation/log';
|
|
5
|
-
import { makeBackoff, retry } from '@aztec/foundation/retry';
|
|
6
|
+
import { makeBackoff, retry, retryUntil } from '@aztec/foundation/retry';
|
|
6
7
|
import { sleep } from '@aztec/foundation/sleep';
|
|
7
8
|
import {
|
|
8
9
|
type AztecNodeAdmin,
|
|
@@ -15,7 +16,14 @@ import { promisify } from 'util';
|
|
|
15
16
|
|
|
16
17
|
import type { TestConfig } from './config.js';
|
|
17
18
|
import { execHelmCommand } from './helm.js';
|
|
18
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
deleteResourceByLabel,
|
|
21
|
+
getChartDir,
|
|
22
|
+
startPortForward,
|
|
23
|
+
waitForResourceByLabel,
|
|
24
|
+
waitForResourceByName,
|
|
25
|
+
waitForStatefulSetsReady,
|
|
26
|
+
} from './k8s.js';
|
|
19
27
|
|
|
20
28
|
const execAsync = promisify(exec);
|
|
21
29
|
|
|
@@ -42,6 +50,63 @@ export async function awaitCheckpointNumber(
|
|
|
42
50
|
}
|
|
43
51
|
}
|
|
44
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Waits until the proven block number increases.
|
|
55
|
+
*
|
|
56
|
+
* @param rpcUrl - URL of an Aztec RPC node to query
|
|
57
|
+
* @param log - Logger instance
|
|
58
|
+
* @param timeoutSeconds - Maximum time to wait
|
|
59
|
+
* @param pollIntervalSeconds - How often to check
|
|
60
|
+
*/
|
|
61
|
+
export async function waitForProvenToAdvance(
|
|
62
|
+
rpcUrl: string,
|
|
63
|
+
log: Logger,
|
|
64
|
+
timeoutSeconds: number = 300,
|
|
65
|
+
pollIntervalSeconds: number = 12, // slot duration
|
|
66
|
+
): Promise<void> {
|
|
67
|
+
const node = createAztecNodeClient(rpcUrl);
|
|
68
|
+
|
|
69
|
+
log.info('Waiting for proven block to advance (indicating epoch proof just submitted)...');
|
|
70
|
+
|
|
71
|
+
// Get current proven block number
|
|
72
|
+
let initialProvenBlock: number;
|
|
73
|
+
try {
|
|
74
|
+
const tips = await node.getL2Tips();
|
|
75
|
+
initialProvenBlock = Number(tips.proven.block.number);
|
|
76
|
+
log.info(`Current proven block: ${initialProvenBlock}. Waiting for it to increase...`);
|
|
77
|
+
} catch (err) {
|
|
78
|
+
log.warn(`Error getting initial tips: ${err}. Will poll until successful.`);
|
|
79
|
+
initialProvenBlock = 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
await retryUntil(
|
|
83
|
+
async () => {
|
|
84
|
+
try {
|
|
85
|
+
const tips = await node.getL2Tips();
|
|
86
|
+
const currentProvenBlock = Number(tips.proven.block.number);
|
|
87
|
+
const proposedBlock = Number(tips.proposed.number);
|
|
88
|
+
|
|
89
|
+
log.verbose(
|
|
90
|
+
`Chain state: proposed=${proposedBlock}, proven=${currentProvenBlock} (waiting for > ${initialProvenBlock})`,
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
if (currentProvenBlock > initialProvenBlock) {
|
|
94
|
+
log.info(`Proven block advanced from ${initialProvenBlock} to ${currentProvenBlock}.`);
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return false;
|
|
99
|
+
} catch (err) {
|
|
100
|
+
log.verbose(`Error checking tips: ${err}`);
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
'proven block to advance',
|
|
105
|
+
timeoutSeconds,
|
|
106
|
+
pollIntervalSeconds,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
45
110
|
export async function getSequencers(namespace: string) {
|
|
46
111
|
const selectors = [
|
|
47
112
|
'app.kubernetes.io/name=validator',
|
|
@@ -90,6 +155,8 @@ export async function withSequencersAdmin<T>(env: TestConfig, fn: (node: AztecNo
|
|
|
90
155
|
const results = [];
|
|
91
156
|
|
|
92
157
|
for (const sequencer of sequencers) {
|
|
158
|
+
// Ensure pod is Ready before attempting port-forward.
|
|
159
|
+
await waitForResourceByName({ resource: 'pods', name: sequencer, namespace });
|
|
93
160
|
// Wrap port-forward + fetch in a retry to handle flaky port-forwards
|
|
94
161
|
const result = await retry(
|
|
95
162
|
async () => {
|
|
@@ -127,6 +194,66 @@ export async function withSequencersAdmin<T>(env: TestConfig, fn: (node: AztecNo
|
|
|
127
194
|
return results;
|
|
128
195
|
}
|
|
129
196
|
|
|
197
|
+
async function getAztecImageForMigrations(namespace: string): Promise<string> {
|
|
198
|
+
const aztecDockerImage = process.env.AZTEC_DOCKER_IMAGE;
|
|
199
|
+
if (aztecDockerImage) {
|
|
200
|
+
return aztecDockerImage;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const { stdout } = await execAsync(
|
|
204
|
+
`kubectl get pods -l app.kubernetes.io/name=validator -n ${namespace} -o jsonpath='{.items[0].spec.containers[?(@.name=="aztec")].image}' | cat`,
|
|
205
|
+
);
|
|
206
|
+
const image = stdout.trim().replace(/^'|'$/g, '');
|
|
207
|
+
if (!image) {
|
|
208
|
+
throw new Error(`Could not detect aztec image from validator pod in namespace ${namespace}`);
|
|
209
|
+
}
|
|
210
|
+
return image;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async function getHaDbConnectionUrl(namespace: string): Promise<string> {
|
|
214
|
+
const secretName = `${namespace}-validator-ha-db-postgres`;
|
|
215
|
+
const { stdout } = await execAsync(`kubectl get secret ${secretName} -n ${namespace} -o json`);
|
|
216
|
+
const secret = JSON.parse(stdout);
|
|
217
|
+
const data = secret?.data ?? {};
|
|
218
|
+
const decode = (value?: string) => (value ? Buffer.from(value, 'base64').toString('utf8') : '');
|
|
219
|
+
const user = decode(data.POSTGRES_USER);
|
|
220
|
+
const password = decode(data.POSTGRES_PASSWORD);
|
|
221
|
+
const database = decode(data.POSTGRES_DB);
|
|
222
|
+
if (!user || !password || !database) {
|
|
223
|
+
throw new Error(`Missing HA DB credentials in secret ${secretName}`);
|
|
224
|
+
}
|
|
225
|
+
const host = `${namespace}-validator-ha-db-postgres.${namespace}.svc.cluster.local`;
|
|
226
|
+
return `postgresql://${encodeURIComponent(user)}:${encodeURIComponent(password)}@${host}:5432/${database}`;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export async function initHADb(namespace: string): Promise<void> {
|
|
230
|
+
const databaseUrl = await getHaDbConnectionUrl(namespace);
|
|
231
|
+
const image = await getAztecImageForMigrations(namespace);
|
|
232
|
+
const jobName = `${namespace}-validator-ha-db-migrate`;
|
|
233
|
+
await execAsync(`kubectl delete pod ${jobName} -n ${namespace} --ignore-not-found=true`).catch(() => undefined);
|
|
234
|
+
|
|
235
|
+
const migrateCmd = [
|
|
236
|
+
`kubectl run ${jobName} -n ${namespace}`,
|
|
237
|
+
'--rm -i',
|
|
238
|
+
'--restart=Never',
|
|
239
|
+
`--image=${image}`,
|
|
240
|
+
`--env=DATABASE_URL=${databaseUrl}`,
|
|
241
|
+
'--command -- node --no-warnings /usr/src/yarn-project/aztec/dest/bin/index.js migrate-ha-db up',
|
|
242
|
+
].join(' ');
|
|
243
|
+
const migrateCmdForLog = migrateCmd.replace(/--env=DATABASE_URL=\S+/, '--env=DATABASE_URL=<redacted>');
|
|
244
|
+
|
|
245
|
+
await retry(
|
|
246
|
+
async () => {
|
|
247
|
+
logger.info(`command: ${migrateCmdForLog}`);
|
|
248
|
+
await execAsync(migrateCmd);
|
|
249
|
+
},
|
|
250
|
+
'run HA DB migrations',
|
|
251
|
+
makeBackoff([1, 2, 4, 8, 16]),
|
|
252
|
+
logger,
|
|
253
|
+
true,
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
|
|
130
257
|
/**
|
|
131
258
|
* Enables or disables probabilistic transaction dropping on validators and waits for rollout.
|
|
132
259
|
* Wired to env vars P2P_DROP_TX and P2P_DROP_TX_CHANCE via Helm values.
|
|
@@ -239,25 +366,46 @@ export async function enableValidatorDynamicBootNode(
|
|
|
239
366
|
*/
|
|
240
367
|
export async function rollAztecPods(namespace: string, clearState: boolean = false) {
|
|
241
368
|
// Pod components use 'validator', but StatefulSets and PVCs use 'sequencer-node' for validators
|
|
242
|
-
const podComponents = [
|
|
243
|
-
|
|
369
|
+
const podComponents = [
|
|
370
|
+
'p2p-bootstrap',
|
|
371
|
+
'prover-node',
|
|
372
|
+
'prover-broker',
|
|
373
|
+
'prover-agent',
|
|
374
|
+
'sequencer-node',
|
|
375
|
+
'rpc',
|
|
376
|
+
'validator-ha-db',
|
|
377
|
+
];
|
|
378
|
+
const pvcComponents = ['p2p-bootstrap', 'prover-node', 'prover-broker', 'sequencer-node', 'rpc', 'validator-ha-db'];
|
|
244
379
|
// StatefulSet components that need to be scaled down before PVC deletion
|
|
245
380
|
// Note: validators use 'sequencer-node' as component label, not 'validator'
|
|
246
|
-
const statefulSetComponents = [
|
|
381
|
+
const statefulSetComponents = [
|
|
382
|
+
'p2p-bootstrap',
|
|
383
|
+
'prover-node',
|
|
384
|
+
'prover-broker',
|
|
385
|
+
'sequencer-node',
|
|
386
|
+
'rpc',
|
|
387
|
+
'validator-ha-db',
|
|
388
|
+
];
|
|
247
389
|
|
|
248
390
|
if (clearState) {
|
|
249
391
|
// To delete PVCs, we must first scale down StatefulSets so pods release the volumes
|
|
250
392
|
// Otherwise PVC deletion will hang waiting for pods to terminate
|
|
251
393
|
|
|
252
|
-
//
|
|
394
|
+
// Save original replica counts for all StatefulSets
|
|
253
395
|
const originalReplicas: Map<string, number> = new Map();
|
|
254
396
|
for (const component of statefulSetComponents) {
|
|
255
397
|
try {
|
|
256
|
-
|
|
398
|
+
// Get all StatefulSets that match the component label
|
|
399
|
+
const getCmd = `kubectl get statefulset -l app.kubernetes.io/component=${component} -n ${namespace} -o json`;
|
|
257
400
|
const { stdout } = await execAsync(getCmd);
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
401
|
+
const result = JSON.parse(stdout);
|
|
402
|
+
for (const sts of result.items || []) {
|
|
403
|
+
const name = sts.metadata.name;
|
|
404
|
+
const replicas = sts.spec.replicas ?? 1;
|
|
405
|
+
if (replicas > 0) {
|
|
406
|
+
originalReplicas.set(name, replicas);
|
|
407
|
+
logger.debug(`Saved replica count for StatefulSet ${name}: ${replicas}`);
|
|
408
|
+
}
|
|
261
409
|
}
|
|
262
410
|
} catch {
|
|
263
411
|
// Component might not exist, continue
|
|
@@ -276,27 +424,81 @@ export async function rollAztecPods(namespace: string, clearState: boolean = fal
|
|
|
276
424
|
}
|
|
277
425
|
}
|
|
278
426
|
|
|
279
|
-
// Wait for pods to terminate
|
|
280
|
-
|
|
427
|
+
// Wait for all pods to fully terminate before deleting PVCs.
|
|
428
|
+
// terminationGracePeriodSeconds default is 30s.
|
|
429
|
+
logger.info('Waiting for pods to fully terminate before deleting PVCs...');
|
|
430
|
+
for (const component of statefulSetComponents) {
|
|
431
|
+
try {
|
|
432
|
+
// Wait for all pods with this component label to be deleted
|
|
433
|
+
const waitCmd = `kubectl wait pods -l app.kubernetes.io/component=${component} --for=delete -n ${namespace} --timeout=2m`;
|
|
434
|
+
logger.info(`command: ${waitCmd}`);
|
|
435
|
+
await execAsync(waitCmd);
|
|
436
|
+
} catch (e) {
|
|
437
|
+
logger.verbose(`Wait for pod deletion ${component} skipped: ${e}`);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
// Extra buffer to ensure PVC protection finalizers are cleared
|
|
441
|
+
await sleep(5 * 1000);
|
|
281
442
|
|
|
282
443
|
// Now delete PVCs (they should no longer be in use)
|
|
283
444
|
for (const component of pvcComponents) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
445
|
+
try {
|
|
446
|
+
await deleteResourceByLabel({
|
|
447
|
+
resource: 'persistentvolumeclaims',
|
|
448
|
+
namespace: namespace,
|
|
449
|
+
label: `app.kubernetes.io/component=${component}`,
|
|
450
|
+
});
|
|
451
|
+
} catch (e) {
|
|
452
|
+
logger.warn(`Failed to delete PVCs for ${component}: ${e}`);
|
|
453
|
+
}
|
|
289
454
|
}
|
|
290
455
|
|
|
291
|
-
//
|
|
292
|
-
for (const component of
|
|
293
|
-
const replicas = originalReplicas.get(component) ?? 1;
|
|
456
|
+
// Verify PVCs are deleted
|
|
457
|
+
for (const component of pvcComponents) {
|
|
294
458
|
try {
|
|
295
|
-
const
|
|
459
|
+
const waitCmd = `kubectl wait pvc -l app.kubernetes.io/component=${component} --for=delete -n ${namespace} --timeout=2m`;
|
|
460
|
+
logger.info(`command: ${waitCmd}`);
|
|
461
|
+
await execAsync(waitCmd);
|
|
462
|
+
} catch (e) {
|
|
463
|
+
logger.verbose(`Wait for PVC deletion ${component} skipped: ${e}`);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const haDbStatefulSets = [...originalReplicas.entries()].filter(([name]) => name.includes('validator-ha-db'));
|
|
468
|
+
const otherStatefulSets = [...originalReplicas.entries()].filter(([name]) => !name.includes('validator-ha-db'));
|
|
469
|
+
|
|
470
|
+
// Bring up HA DB first so we can run migrations before validators start
|
|
471
|
+
for (const [stsName, replicas] of haDbStatefulSets) {
|
|
472
|
+
try {
|
|
473
|
+
const scaleCmd = `kubectl scale statefulset ${stsName} -n ${namespace} --replicas=${replicas} --timeout=2m`;
|
|
296
474
|
logger.info(`command: ${scaleCmd}`);
|
|
297
475
|
await execAsync(scaleCmd);
|
|
298
476
|
} catch (e) {
|
|
299
|
-
logger.verbose(`Scale up ${
|
|
477
|
+
logger.verbose(`Scale up ${stsName} skipped: ${e}`);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
if (haDbStatefulSets.length > 0) {
|
|
482
|
+
try {
|
|
483
|
+
await waitForStatefulSetsReady({
|
|
484
|
+
namespace,
|
|
485
|
+
label: 'app.kubernetes.io/component=validator-ha-db',
|
|
486
|
+
timeoutSeconds: 600,
|
|
487
|
+
});
|
|
488
|
+
await initHADb(namespace);
|
|
489
|
+
} catch (e) {
|
|
490
|
+
logger.warn(`HA DB migration step skipped or failed: ${e}`);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Scale remaining StatefulSets back up to original replica counts (by name, not label)
|
|
495
|
+
for (const [stsName, replicas] of otherStatefulSets) {
|
|
496
|
+
try {
|
|
497
|
+
const scaleCmd = `kubectl scale statefulset ${stsName} -n ${namespace} --replicas=${replicas} --timeout=2m`;
|
|
498
|
+
logger.info(`command: ${scaleCmd}`);
|
|
499
|
+
await execAsync(scaleCmd);
|
|
500
|
+
} catch (e) {
|
|
501
|
+
logger.verbose(`Scale up ${stsName} skipped: ${e}`);
|
|
300
502
|
}
|
|
301
503
|
}
|
|
302
504
|
} else {
|
|
@@ -312,8 +514,21 @@ export async function rollAztecPods(namespace: string, clearState: boolean = fal
|
|
|
312
514
|
|
|
313
515
|
await sleep(10 * 1000);
|
|
314
516
|
|
|
315
|
-
// Wait for
|
|
316
|
-
for (const component of
|
|
517
|
+
// Wait for StatefulSets to have all replicas ready.
|
|
518
|
+
for (const component of statefulSetComponents) {
|
|
519
|
+
try {
|
|
520
|
+
await waitForStatefulSetsReady({
|
|
521
|
+
namespace,
|
|
522
|
+
label: `app.kubernetes.io/component=${component}`,
|
|
523
|
+
timeoutSeconds: 600, // 10 minutes
|
|
524
|
+
});
|
|
525
|
+
} catch (e) {
|
|
526
|
+
logger.warn(`StatefulSet component ${component} may not be fully ready: ${e}`);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
const nonStatefulSetComponents = podComponents.filter(c => !statefulSetComponents.includes(c));
|
|
531
|
+
for (const component of nonStatefulSetComponents) {
|
|
317
532
|
await waitForResourceByLabel({
|
|
318
533
|
resource: 'pods',
|
|
319
534
|
namespace: namespace,
|
|
@@ -3,24 +3,47 @@ import type { Logger } from '@aztec/foundation/log';
|
|
|
3
3
|
import { execSync, spawn } from 'child_process';
|
|
4
4
|
import path from 'path';
|
|
5
5
|
|
|
6
|
+
/** Result from running a script */
|
|
7
|
+
export type ScriptResult = {
|
|
8
|
+
exitCode: number;
|
|
9
|
+
stdout: string;
|
|
10
|
+
stderr: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
6
13
|
/**
|
|
7
14
|
* @param scriptPath - The path to the script, relative to the project root
|
|
8
15
|
* @param args - The arguments to pass to the script
|
|
9
16
|
* @param logger - The logger to use
|
|
10
|
-
* @returns The exit code of the script
|
|
17
|
+
* @returns The exit code, stdout, and stderr of the script
|
|
11
18
|
*/
|
|
12
|
-
function runScript(
|
|
19
|
+
function runScript(
|
|
20
|
+
scriptPath: string,
|
|
21
|
+
args: string[],
|
|
22
|
+
logger: Logger,
|
|
23
|
+
env?: Record<string, string>,
|
|
24
|
+
): Promise<ScriptResult> {
|
|
13
25
|
const childProcess = spawn(scriptPath, args, {
|
|
14
26
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
15
27
|
env: env ? { ...process.env, ...env } : process.env,
|
|
16
28
|
});
|
|
17
|
-
|
|
18
|
-
|
|
29
|
+
const stdoutChunks: Buffer[] = [];
|
|
30
|
+
const stderrChunks: Buffer[] = [];
|
|
31
|
+
|
|
32
|
+
return new Promise<ScriptResult>((resolve, reject) => {
|
|
33
|
+
childProcess.on('close', (code: number | null) =>
|
|
34
|
+
resolve({
|
|
35
|
+
exitCode: code ?? 0,
|
|
36
|
+
stdout: Buffer.concat(stdoutChunks).toString(),
|
|
37
|
+
stderr: Buffer.concat(stderrChunks).toString(),
|
|
38
|
+
}),
|
|
39
|
+
);
|
|
19
40
|
childProcess.on('error', reject);
|
|
20
41
|
childProcess.stdout?.on('data', (data: Buffer) => {
|
|
42
|
+
stdoutChunks.push(data);
|
|
21
43
|
logger.info(data.toString());
|
|
22
44
|
});
|
|
23
45
|
childProcess.stderr?.on('data', (data: Buffer) => {
|
|
46
|
+
stderrChunks.push(data);
|
|
24
47
|
logger.error(data.toString());
|
|
25
48
|
});
|
|
26
49
|
});
|
|
@@ -51,13 +74,26 @@ export function getAztecBin() {
|
|
|
51
74
|
* @param args - The arguments to pass to the Aztec binary
|
|
52
75
|
* @param logger - The logger to use
|
|
53
76
|
* @param env - Optional environment variables to set for the process
|
|
54
|
-
* @returns The exit code of the Aztec binary
|
|
77
|
+
* @returns The exit code, stdout, and stderr of the Aztec binary
|
|
55
78
|
*/
|
|
56
|
-
export function runAztecBin(args: string[], logger: Logger, env?: Record<string, string>) {
|
|
79
|
+
export function runAztecBin(args: string[], logger: Logger, env?: Record<string, string>): Promise<ScriptResult> {
|
|
57
80
|
return runScript('node', [getAztecBin(), ...args], logger, env);
|
|
58
81
|
}
|
|
59
82
|
|
|
60
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Runs a script from the project root
|
|
85
|
+
* @param script - The path to the script, relative to the project root
|
|
86
|
+
* @param args - The arguments to pass to the script
|
|
87
|
+
* @param logger - The logger to use
|
|
88
|
+
* @param env - Optional environment variables to set for the process
|
|
89
|
+
* @returns The exit code, stdout, and stderr of the script
|
|
90
|
+
*/
|
|
91
|
+
export function runProjectScript(
|
|
92
|
+
script: string,
|
|
93
|
+
args: string[],
|
|
94
|
+
logger: Logger,
|
|
95
|
+
env?: Record<string, string>,
|
|
96
|
+
): Promise<ScriptResult> {
|
|
61
97
|
const scriptPath = script.startsWith('/') ? script : path.join(getGitProjectRoot(), script);
|
|
62
98
|
return runScript(scriptPath, args, logger, env);
|
|
63
99
|
}
|