@aztec/end-to-end 2.1.0-rc.9 → 3.0.0-devnet.2
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/benchmark.d.ts +3 -2
- package/dest/bench/client_flows/benchmark.d.ts.map +1 -1
- package/dest/bench/client_flows/client_flows_benchmark.d.ts +16 -12
- package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -1
- package/dest/bench/client_flows/client_flows_benchmark.js +54 -58
- package/dest/bench/utils.d.ts +2 -11
- package/dest/bench/utils.d.ts.map +1 -1
- package/dest/bench/utils.js +10 -34
- package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +7 -7
- 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 +42 -42
- package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts +10 -8
- 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 +31 -33
- package/dest/e2e_deploy_contract/deploy_test.d.ts +10 -4
- package/dest/e2e_deploy_contract/deploy_test.d.ts.map +1 -1
- package/dest/e2e_deploy_contract/deploy_test.js +9 -18
- package/dest/e2e_epochs/epochs_test.d.ts +3 -1
- package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
- package/dest/e2e_epochs/epochs_test.js +10 -9
- package/dest/e2e_fees/bridging_race.notest.js +12 -9
- package/dest/e2e_fees/fees_test.d.ts +5 -5
- package/dest/e2e_fees/fees_test.d.ts.map +1 -1
- package/dest/e2e_fees/fees_test.js +23 -31
- package/dest/e2e_l1_publisher/write_json.d.ts +3 -1
- package/dest/e2e_l1_publisher/write_json.d.ts.map +1 -1
- package/dest/e2e_l1_publisher/write_json.js +5 -5
- package/dest/e2e_multi_validator/utils.d.ts +1 -1
- package/dest/e2e_multi_validator/utils.d.ts.map +1 -1
- package/dest/e2e_nested_contract/nested_contract_test.d.ts +6 -3
- package/dest/e2e_nested_contract/nested_contract_test.d.ts.map +1 -1
- package/dest/e2e_nested_contract/nested_contract_test.js +7 -9
- 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 +5 -2
- package/dest/e2e_p2p/p2p_network.d.ts +16 -4
- package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
- package/dest/e2e_p2p/p2p_network.js +32 -10
- package/dest/e2e_p2p/shared.d.ts +11 -13
- package/dest/e2e_p2p/shared.d.ts.map +1 -1
- package/dest/e2e_p2p/shared.js +49 -45
- package/dest/e2e_token_contract/token_contract_test.d.ts +5 -4
- package/dest/e2e_token_contract/token_contract_test.d.ts.map +1 -1
- package/dest/e2e_token_contract/token_contract_test.js +14 -17
- package/dest/fixtures/e2e_prover_test.d.ts +8 -6
- package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
- package/dest/fixtures/e2e_prover_test.js +40 -50
- package/dest/fixtures/get_acvm_config.d.ts +1 -1
- package/dest/fixtures/get_acvm_config.d.ts.map +1 -1
- package/dest/fixtures/get_bb_config.d.ts +1 -1
- package/dest/fixtures/get_bb_config.d.ts.map +1 -1
- package/dest/fixtures/get_bb_config.js +2 -2
- package/dest/fixtures/setup_l1_contracts.d.ts +1 -1
- package/dest/fixtures/setup_l1_contracts.d.ts.map +1 -1
- package/dest/fixtures/setup_l1_contracts.js +2 -2
- package/dest/fixtures/setup_p2p_test.d.ts +0 -7
- package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
- package/dest/fixtures/snapshot_manager.d.ts +10 -7
- package/dest/fixtures/snapshot_manager.d.ts.map +1 -1
- package/dest/fixtures/snapshot_manager.js +44 -34
- package/dest/fixtures/token_utils.d.ts +6 -4
- package/dest/fixtures/token_utils.d.ts.map +1 -1
- package/dest/fixtures/token_utils.js +11 -15
- package/dest/fixtures/utils.d.ts +23 -27
- package/dest/fixtures/utils.d.ts.map +1 -1
- package/dest/fixtures/utils.js +76 -101
- package/dest/fixtures/web3signer.d.ts +1 -1
- package/dest/fixtures/web3signer.d.ts.map +1 -1
- package/dest/fixtures/web3signer.js +16 -5
- package/dest/quality_of_service/alert_checker.d.ts +1 -1
- package/dest/quality_of_service/alert_checker.d.ts.map +1 -1
- package/dest/shared/cross_chain_test_harness.d.ts +16 -10
- package/dest/shared/cross_chain_test_harness.d.ts.map +1 -1
- package/dest/shared/cross_chain_test_harness.js +13 -15
- package/dest/shared/gas_portal_test_harness.d.ts +9 -6
- package/dest/shared/gas_portal_test_harness.d.ts.map +1 -1
- package/dest/shared/gas_portal_test_harness.js +10 -7
- package/dest/shared/jest_setup.js +1 -1
- package/dest/shared/submit-transactions.d.ts +5 -3
- package/dest/shared/submit-transactions.d.ts.map +1 -1
- package/dest/shared/submit-transactions.js +8 -7
- package/dest/shared/uniswap_l1_l2.d.ts +9 -6
- package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
- package/dest/shared/uniswap_l1_l2.js +29 -45
- package/dest/simulators/lending_simulator.d.ts +2 -1
- package/dest/simulators/lending_simulator.d.ts.map +1 -1
- package/dest/simulators/lending_simulator.js +3 -2
- package/dest/simulators/token_simulator.d.ts +3 -1
- package/dest/simulators/token_simulator.d.ts.map +1 -1
- package/dest/simulators/token_simulator.js +2 -2
- package/dest/spartan/setup_test_wallets.d.ts +19 -13
- package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
- package/dest/spartan/setup_test_wallets.js +108 -85
- package/dest/spartan/utils.d.ts +44 -0
- package/dest/spartan/utils.d.ts.map +1 -1
- package/dest/spartan/utils.js +212 -20
- package/package.json +38 -37
- package/src/bench/client_flows/benchmark.ts +6 -6
- package/src/bench/client_flows/client_flows_benchmark.ts +62 -82
- package/src/bench/client_flows/data_extractor.ts +1 -1
- package/src/bench/utils.ts +9 -37
- package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +46 -63
- package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +33 -47
- package/src/e2e_deploy_contract/deploy_test.ts +17 -35
- package/src/e2e_epochs/epochs_test.ts +12 -14
- package/src/e2e_fees/bridging_race.notest.ts +14 -9
- package/src/e2e_fees/fees_test.ts +26 -38
- package/src/e2e_l1_publisher/write_json.ts +8 -6
- package/src/e2e_multi_validator/utils.ts +1 -1
- package/src/e2e_nested_contract/nested_contract_test.ts +11 -10
- package/src/e2e_p2p/inactivity_slash_test.ts +7 -3
- package/src/e2e_p2p/p2p_network.ts +105 -67
- package/src/e2e_p2p/shared.ts +50 -55
- package/src/e2e_token_contract/token_contract_test.ts +17 -17
- package/src/fixtures/e2e_prover_test.ts +51 -88
- package/src/fixtures/get_acvm_config.ts +1 -1
- package/src/fixtures/get_bb_config.ts +3 -2
- package/src/fixtures/setup_l1_contracts.ts +3 -3
- package/src/fixtures/setup_p2p_test.ts +0 -8
- package/src/fixtures/snapshot_manager.ts +61 -61
- package/src/fixtures/token_utils.ts +13 -21
- package/src/fixtures/utils.ts +87 -138
- package/src/fixtures/web3signer.ts +22 -5
- package/src/guides/up_quick_start.sh +2 -10
- package/src/quality_of_service/alert_checker.ts +1 -1
- package/src/shared/cross_chain_test_harness.ts +18 -29
- package/src/shared/gas_portal_test_harness.ts +12 -19
- package/src/shared/jest_setup.ts +1 -1
- package/src/shared/submit-transactions.ts +12 -8
- package/src/shared/uniswap_l1_l2.ts +61 -67
- package/src/simulators/lending_simulator.ts +3 -2
- package/src/simulators/token_simulator.ts +5 -2
- package/src/spartan/DEVELOP.md +8 -3
- package/src/spartan/setup_test_wallets.ts +133 -126
- package/src/spartan/utils.ts +268 -18
package/src/spartan/utils.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { createLogger
|
|
1
|
+
import { createLogger } from '@aztec/aztec.js/log';
|
|
2
2
|
import type { RollupCheatCodes } from '@aztec/aztec/testing';
|
|
3
3
|
import type { L1ContractAddresses, ViemPublicClient } from '@aztec/ethereum';
|
|
4
4
|
import type { Logger } from '@aztec/foundation/log';
|
|
5
5
|
import { makeBackoff, retry } from '@aztec/foundation/retry';
|
|
6
6
|
import { schemas } from '@aztec/foundation/schemas';
|
|
7
|
+
import { sleep } from '@aztec/foundation/sleep';
|
|
7
8
|
import {
|
|
8
9
|
type AztecNodeAdmin,
|
|
9
10
|
type AztecNodeAdminConfig,
|
|
@@ -26,6 +27,9 @@ const testConfigSchema = z.object({
|
|
|
26
27
|
REAL_VERIFIER: schemas.Boolean.optional().default(true),
|
|
27
28
|
CREATE_ETH_DEVNET: schemas.Boolean.optional().default(false),
|
|
28
29
|
L1_RPC_URLS_JSON: z.string().optional(),
|
|
30
|
+
L1_ACCOUNT_MNEMONIC: z.string().optional(),
|
|
31
|
+
AZTEC_SLOT_DURATION: z.coerce.number().optional().default(24),
|
|
32
|
+
AZTEC_PROOF_SUBMISSION_WINDOW: z.coerce.number().optional().default(5),
|
|
29
33
|
});
|
|
30
34
|
|
|
31
35
|
export type TestConfig = z.infer<typeof testConfigSchema>;
|
|
@@ -204,6 +208,16 @@ export async function deleteResourceByLabel({
|
|
|
204
208
|
timeout?: string;
|
|
205
209
|
force?: boolean;
|
|
206
210
|
}) {
|
|
211
|
+
// Check if the resource type exists before attempting to delete
|
|
212
|
+
try {
|
|
213
|
+
await execAsync(
|
|
214
|
+
`kubectl api-resources --api-group="" --no-headers -o name | grep -q "^${resource}$" || kubectl api-resources --no-headers -o name | grep -q "^${resource}$"`,
|
|
215
|
+
);
|
|
216
|
+
} catch (error) {
|
|
217
|
+
logger.warn(`Resource type '${resource}' not found in cluster, skipping deletion ${error}`);
|
|
218
|
+
return '';
|
|
219
|
+
}
|
|
220
|
+
|
|
207
221
|
const command = `kubectl delete ${resource} -l ${label} -n ${namespace} --ignore-not-found=true --wait=true --timeout=${timeout} ${
|
|
208
222
|
force ? '--force' : ''
|
|
209
223
|
}`;
|
|
@@ -235,9 +249,18 @@ export function getChartDir(spartanDir: string, chartName: string) {
|
|
|
235
249
|
return path.join(spartanDir.trim(), chartName);
|
|
236
250
|
}
|
|
237
251
|
|
|
238
|
-
function
|
|
252
|
+
function shellQuote(value: string) {
|
|
253
|
+
// Single-quote safe shell escaping: ' -> '\''
|
|
254
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function valuesToArgs(values: Record<string, string | number | boolean>) {
|
|
239
258
|
return Object.entries(values)
|
|
240
|
-
.map(([key, value]) =>
|
|
259
|
+
.map(([key, value]) =>
|
|
260
|
+
typeof value === 'number' || typeof value === 'boolean'
|
|
261
|
+
? `--set ${key}=${value}`
|
|
262
|
+
: `--set-string ${key}=${shellQuote(String(value))}`,
|
|
263
|
+
)
|
|
241
264
|
.join(' ');
|
|
242
265
|
}
|
|
243
266
|
|
|
@@ -255,7 +278,7 @@ function createHelmCommand({
|
|
|
255
278
|
namespace: string;
|
|
256
279
|
valuesFile: string | undefined;
|
|
257
280
|
timeout: string;
|
|
258
|
-
values: Record<string, string | number>;
|
|
281
|
+
values: Record<string, string | number | boolean>;
|
|
259
282
|
reuseValues?: boolean;
|
|
260
283
|
}) {
|
|
261
284
|
const valuesFileArgs = valuesFile ? `--values ${helmChartDir}/values/${valuesFile}` : '';
|
|
@@ -295,7 +318,7 @@ export async function installChaosMeshChart({
|
|
|
295
318
|
valuesFile,
|
|
296
319
|
helmChartDir,
|
|
297
320
|
chaosMeshNamespace = 'chaos-mesh',
|
|
298
|
-
timeout = '
|
|
321
|
+
timeout = '10m',
|
|
299
322
|
clean = true,
|
|
300
323
|
values = {},
|
|
301
324
|
logger,
|
|
@@ -314,18 +337,23 @@ export async function installChaosMeshChart({
|
|
|
314
337
|
// uninstall the helm chart if it exists
|
|
315
338
|
logger.info(`Uninstalling helm chart ${instanceName}`);
|
|
316
339
|
await execAsync(`helm uninstall ${instanceName} --namespace ${chaosMeshNamespace} --wait --ignore-not-found`);
|
|
317
|
-
// and delete the
|
|
318
|
-
const
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
340
|
+
// and delete the chaos-mesh resources created by this release
|
|
341
|
+
const deleteByLabel = async (resource: string) => {
|
|
342
|
+
const args = {
|
|
343
|
+
resource,
|
|
344
|
+
namespace: chaosMeshNamespace,
|
|
345
|
+
label: `app.kubernetes.io/instance=${instanceName}`,
|
|
346
|
+
} as const;
|
|
347
|
+
logger.info(`Deleting ${resource} resources for release ${instanceName}`);
|
|
348
|
+
await deleteResourceByLabel(args).catch(e => {
|
|
349
|
+
logger.error(`Error deleting ${resource}: ${e}`);
|
|
350
|
+
logger.info(`Force deleting ${resource}`);
|
|
351
|
+
return deleteResourceByLabel({ ...args, force: true });
|
|
352
|
+
});
|
|
322
353
|
};
|
|
323
|
-
|
|
324
|
-
await
|
|
325
|
-
|
|
326
|
-
logger.info(`Force deleting podchaos resource`);
|
|
327
|
-
return deleteResourceByLabel({ ...deleteArgs, force: true });
|
|
328
|
-
});
|
|
354
|
+
|
|
355
|
+
await deleteByLabel('podchaos');
|
|
356
|
+
await deleteByLabel('networkchaos');
|
|
329
357
|
}
|
|
330
358
|
|
|
331
359
|
return execHelmCommand({
|
|
@@ -486,12 +514,234 @@ export async function awaitL2BlockNumber(
|
|
|
486
514
|
|
|
487
515
|
export async function restartBot(namespace: string, logger: Logger) {
|
|
488
516
|
logger.info(`Restarting bot`);
|
|
489
|
-
await deleteResourceByLabel({ resource: 'pods', namespace, label: 'app=bot' });
|
|
517
|
+
await deleteResourceByLabel({ resource: 'pods', namespace, label: 'app.kubernetes.io/name=bot' });
|
|
490
518
|
await sleep(10 * 1000);
|
|
491
|
-
|
|
519
|
+
// Some bot images may take time to report Ready due to heavy boot-time proving.
|
|
520
|
+
// Waiting for PodReadyToStartContainers ensures the pod is scheduled and starting without blocking on full readiness.
|
|
521
|
+
await waitForResourceByLabel({
|
|
522
|
+
resource: 'pods',
|
|
523
|
+
namespace,
|
|
524
|
+
label: 'app.kubernetes.io/name=bot',
|
|
525
|
+
condition: 'PodReadyToStartContainers',
|
|
526
|
+
});
|
|
492
527
|
logger.info(`Bot restarted`);
|
|
493
528
|
}
|
|
494
529
|
|
|
530
|
+
/**
|
|
531
|
+
* Installs or upgrades the transfer bot Helm release for the given namespace.
|
|
532
|
+
* Intended for test setup to enable L2 traffic generation only when needed.
|
|
533
|
+
*/
|
|
534
|
+
export async function installTransferBot({
|
|
535
|
+
namespace,
|
|
536
|
+
spartanDir,
|
|
537
|
+
logger,
|
|
538
|
+
replicas = 1,
|
|
539
|
+
txIntervalSeconds = 10,
|
|
540
|
+
followChain = 'PENDING',
|
|
541
|
+
mnemonic = process.env.LABS_INFRA_MNEMONIC ?? 'test test test test test test test test test test test junk',
|
|
542
|
+
mnemonicStartIndex,
|
|
543
|
+
botPrivateKey = process.env.BOT_TRANSFERS_L2_PRIVATE_KEY ?? '0xcafe01',
|
|
544
|
+
nodeUrl,
|
|
545
|
+
timeout = '15m',
|
|
546
|
+
reuseValues = true,
|
|
547
|
+
aztecSlotDuration = Number(process.env.AZTEC_SLOT_DURATION ?? 12),
|
|
548
|
+
}: {
|
|
549
|
+
namespace: string;
|
|
550
|
+
spartanDir: string;
|
|
551
|
+
logger: Logger;
|
|
552
|
+
replicas?: number;
|
|
553
|
+
txIntervalSeconds?: number;
|
|
554
|
+
followChain?: string;
|
|
555
|
+
mnemonic?: string;
|
|
556
|
+
mnemonicStartIndex?: number | string;
|
|
557
|
+
botPrivateKey?: string;
|
|
558
|
+
nodeUrl?: string;
|
|
559
|
+
timeout?: string;
|
|
560
|
+
reuseValues?: boolean;
|
|
561
|
+
aztecSlotDuration?: number;
|
|
562
|
+
}) {
|
|
563
|
+
const instanceName = `${namespace}-bot-transfers`;
|
|
564
|
+
const helmChartDir = getChartDir(spartanDir, 'aztec-bot');
|
|
565
|
+
const resolvedNodeUrl = nodeUrl ?? `http://${namespace}-rpc-aztec-node.${namespace}.svc.cluster.local:8080`;
|
|
566
|
+
|
|
567
|
+
logger.info(`Installing/upgrading transfer bot: replicas=${replicas}, followChain=${followChain}`);
|
|
568
|
+
|
|
569
|
+
const values: Record<string, string | number | boolean> = {
|
|
570
|
+
'bot.replicaCount': replicas,
|
|
571
|
+
'bot.txIntervalSeconds': txIntervalSeconds,
|
|
572
|
+
'bot.followChain': followChain,
|
|
573
|
+
'bot.botPrivateKey': botPrivateKey,
|
|
574
|
+
'bot.nodeUrl': resolvedNodeUrl,
|
|
575
|
+
'bot.mnemonic': mnemonic,
|
|
576
|
+
'bot.feePaymentMethod': 'fee_juice',
|
|
577
|
+
'aztec.slotDuration': aztecSlotDuration,
|
|
578
|
+
// Ensure bot can reach its own PXE started in-process (default rpc.port is 8080)
|
|
579
|
+
// Note: since aztec-bot depends on aztec-node with alias `bot`, env vars go under `bot.node.env`.
|
|
580
|
+
'bot.node.env.BOT_PXE_URL': 'http://127.0.0.1:8080',
|
|
581
|
+
// Provide L1 execution RPC for bridging fee juice
|
|
582
|
+
'bot.node.env.ETHEREUM_HOSTS': `http://${namespace}-eth-execution.${namespace}.svc.cluster.local:8545`,
|
|
583
|
+
// Provide L1 mnemonic for bridging (falls back to labs mnemonic)
|
|
584
|
+
'bot.node.env.BOT_L1_MNEMONIC': mnemonic,
|
|
585
|
+
};
|
|
586
|
+
// Ensure we derive a funded L1 key (index 0 is funded on anvil default mnemonic)
|
|
587
|
+
if (mnemonicStartIndex === undefined) {
|
|
588
|
+
values['bot.mnemonicStartIndex'] = 0;
|
|
589
|
+
}
|
|
590
|
+
// Also pass a funded private key directly if available
|
|
591
|
+
if (process.env.FUNDING_PRIVATE_KEY) {
|
|
592
|
+
values['bot.node.env.BOT_L1_PRIVATE_KEY'] = process.env.FUNDING_PRIVATE_KEY;
|
|
593
|
+
}
|
|
594
|
+
// Align bot image with the running network image: prefer env var, else detect from a validator pod
|
|
595
|
+
let repositoryFromEnv: string | undefined;
|
|
596
|
+
let tagFromEnv: string | undefined;
|
|
597
|
+
const aztecDockerImage = process.env.AZTEC_DOCKER_IMAGE;
|
|
598
|
+
if (aztecDockerImage && aztecDockerImage.includes(':')) {
|
|
599
|
+
const lastColon = aztecDockerImage.lastIndexOf(':');
|
|
600
|
+
repositoryFromEnv = aztecDockerImage.slice(0, lastColon);
|
|
601
|
+
tagFromEnv = aztecDockerImage.slice(lastColon + 1);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
let repository = repositoryFromEnv;
|
|
605
|
+
let tag = tagFromEnv;
|
|
606
|
+
if (!repository || !tag) {
|
|
607
|
+
try {
|
|
608
|
+
const { stdout } = await execAsync(
|
|
609
|
+
`kubectl get pods -l app.kubernetes.io/component=validator -n ${namespace} -o jsonpath='{.items[0].spec.containers[?(@.name=="aztec")].image}' | cat`,
|
|
610
|
+
);
|
|
611
|
+
const image = stdout.trim().replace(/^'|'$/g, '');
|
|
612
|
+
if (image && image.includes(':')) {
|
|
613
|
+
const lastColon = image.lastIndexOf(':');
|
|
614
|
+
repository = image.slice(0, lastColon);
|
|
615
|
+
tag = image.slice(lastColon + 1);
|
|
616
|
+
}
|
|
617
|
+
} catch (err) {
|
|
618
|
+
logger.warn(`Could not detect aztec image from validator pod: ${String(err)}`);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
if (repository && tag) {
|
|
622
|
+
values['global.aztecImage.repository'] = repository;
|
|
623
|
+
values['global.aztecImage.tag'] = tag;
|
|
624
|
+
}
|
|
625
|
+
if (mnemonicStartIndex !== undefined) {
|
|
626
|
+
values['bot.mnemonicStartIndex'] =
|
|
627
|
+
typeof mnemonicStartIndex === 'string' ? mnemonicStartIndex : Number(mnemonicStartIndex);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
await execHelmCommand({
|
|
631
|
+
instanceName,
|
|
632
|
+
helmChartDir,
|
|
633
|
+
namespace,
|
|
634
|
+
valuesFile: undefined,
|
|
635
|
+
timeout,
|
|
636
|
+
values: values as unknown as Record<string, string | number | boolean>,
|
|
637
|
+
reuseValues,
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
if (replicas > 0) {
|
|
641
|
+
await waitForResourceByLabel({
|
|
642
|
+
resource: 'pods',
|
|
643
|
+
namespace,
|
|
644
|
+
label: 'app.kubernetes.io/name=bot',
|
|
645
|
+
condition: 'PodReadyToStartContainers',
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Uninstalls the transfer bot Helm release from the given namespace.
|
|
652
|
+
* Intended for test teardown to clean up bot resources.
|
|
653
|
+
*/
|
|
654
|
+
export async function uninstallTransferBot(namespace: string, logger: Logger) {
|
|
655
|
+
const instanceName = `${namespace}-bot-transfers`;
|
|
656
|
+
logger.info(`Uninstalling transfer bot release ${instanceName}`);
|
|
657
|
+
await execAsync(`helm uninstall ${instanceName} --namespace ${namespace} --wait --ignore-not-found`);
|
|
658
|
+
// Ensure any leftover pods are removed
|
|
659
|
+
await deleteResourceByLabel({ resource: 'pods', namespace, label: 'app.kubernetes.io/name=bot' }).catch(
|
|
660
|
+
() => undefined,
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Enables or disables probabilistic transaction dropping on validators and waits for rollout.
|
|
666
|
+
* Wired to env vars P2P_DROP_TX and P2P_DROP_TX_CHANCE via Helm values.
|
|
667
|
+
*/
|
|
668
|
+
export async function setValidatorTxDrop({
|
|
669
|
+
namespace,
|
|
670
|
+
enabled,
|
|
671
|
+
probability,
|
|
672
|
+
logger,
|
|
673
|
+
}: {
|
|
674
|
+
namespace: string;
|
|
675
|
+
enabled: boolean;
|
|
676
|
+
probability: number;
|
|
677
|
+
logger: Logger;
|
|
678
|
+
}) {
|
|
679
|
+
const drop = enabled ? 'true' : 'false';
|
|
680
|
+
const prob = String(probability);
|
|
681
|
+
|
|
682
|
+
const selectors = ['app=validator', 'app.kubernetes.io/component=validator'];
|
|
683
|
+
let updated = false;
|
|
684
|
+
for (const selector of selectors) {
|
|
685
|
+
try {
|
|
686
|
+
const list = await execAsync(`kubectl get statefulset -l ${selector} -n ${namespace} --no-headers -o name | cat`);
|
|
687
|
+
const names = list.stdout
|
|
688
|
+
.split('\n')
|
|
689
|
+
.map(s => s.trim())
|
|
690
|
+
.filter(Boolean);
|
|
691
|
+
if (names.length === 0) {
|
|
692
|
+
continue;
|
|
693
|
+
}
|
|
694
|
+
const cmd = `kubectl set env statefulset -l ${selector} -n ${namespace} P2P_DROP_TX=${drop} P2P_DROP_TX_CHANCE=${prob}`;
|
|
695
|
+
logger.info(`command: ${cmd}`);
|
|
696
|
+
await execAsync(cmd);
|
|
697
|
+
updated = true;
|
|
698
|
+
} catch (e) {
|
|
699
|
+
logger.warn(`Failed to update validators with selector ${selector}: ${String(e)}`);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
if (!updated) {
|
|
704
|
+
logger.warn(`No validator StatefulSets found in ${namespace}. Skipping tx drop toggle.`);
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// Restart validator pods to ensure env vars take effect and wait for readiness
|
|
709
|
+
await restartValidators(namespace, logger);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
export async function restartValidators(namespace: string, logger: Logger) {
|
|
713
|
+
const selectors = ['app=validator', 'app.kubernetes.io/component=validator'];
|
|
714
|
+
let any = false;
|
|
715
|
+
for (const selector of selectors) {
|
|
716
|
+
try {
|
|
717
|
+
const { stdout } = await execAsync(`kubectl get pods -l ${selector} -n ${namespace} --no-headers -o name | cat`);
|
|
718
|
+
if (!stdout || stdout.trim().length === 0) {
|
|
719
|
+
continue;
|
|
720
|
+
}
|
|
721
|
+
any = true;
|
|
722
|
+
await deleteResourceByLabel({ resource: 'pods', namespace, label: selector });
|
|
723
|
+
} catch (e) {
|
|
724
|
+
logger.warn(`Error restarting validator pods with selector ${selector}: ${String(e)}`);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
if (!any) {
|
|
729
|
+
logger.warn(`No validator pods found to restart in ${namespace}.`);
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
// Wait for either label to be Ready
|
|
734
|
+
for (const selector of selectors) {
|
|
735
|
+
try {
|
|
736
|
+
await waitForResourceByLabel({ resource: 'pods', namespace, label: selector });
|
|
737
|
+
return;
|
|
738
|
+
} catch {
|
|
739
|
+
// try next
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
logger.warn(`Validator pods did not report Ready; continuing.`);
|
|
743
|
+
}
|
|
744
|
+
|
|
495
745
|
export async function enableValidatorDynamicBootNode(
|
|
496
746
|
instanceName: string,
|
|
497
747
|
namespace: string,
|