@aztec/end-to-end 0.0.1-commit.fcb71a6 → 0.0.1-commit.fffb133c

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.
Files changed (166) hide show
  1. package/dest/bench/client_flows/benchmark.d.ts +3 -2
  2. package/dest/bench/client_flows/benchmark.d.ts.map +1 -1
  3. package/dest/bench/client_flows/benchmark.js +21 -1
  4. package/dest/bench/client_flows/client_flows_benchmark.d.ts +12 -13
  5. package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -1
  6. package/dest/bench/client_flows/client_flows_benchmark.js +118 -133
  7. package/dest/bench/client_flows/data_extractor.js +3 -1
  8. package/dest/bench/utils.d.ts +9 -8
  9. package/dest/bench/utils.d.ts.map +1 -1
  10. package/dest/bench/utils.js +17 -12
  11. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +6 -7
  12. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts.map +1 -1
  13. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.js +96 -112
  14. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts +15 -10
  15. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts.map +1 -1
  16. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.js +89 -70
  17. package/dest/e2e_deploy_contract/deploy_test.d.ts +4 -3
  18. package/dest/e2e_deploy_contract/deploy_test.d.ts.map +1 -1
  19. package/dest/e2e_deploy_contract/deploy_test.js +18 -13
  20. package/dest/e2e_epochs/epochs_test.d.ts +1 -1
  21. package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
  22. package/dest/e2e_epochs/epochs_test.js +5 -2
  23. package/dest/e2e_fees/bridging_race.notest.js +3 -5
  24. package/dest/e2e_fees/fees_test.d.ts +13 -13
  25. package/dest/e2e_fees/fees_test.d.ts.map +1 -1
  26. package/dest/e2e_fees/fees_test.js +123 -141
  27. package/dest/e2e_l1_publisher/write_json.d.ts +2 -2
  28. package/dest/e2e_l1_publisher/write_json.d.ts.map +1 -1
  29. package/dest/e2e_l1_publisher/write_json.js +19 -15
  30. package/dest/e2e_nested_contract/nested_contract_test.d.ts +6 -9
  31. package/dest/e2e_nested_contract/nested_contract_test.d.ts.map +1 -1
  32. package/dest/e2e_nested_contract/nested_contract_test.js +31 -39
  33. package/dest/e2e_p2p/inactivity_slash_test.d.ts +3 -3
  34. package/dest/e2e_p2p/inactivity_slash_test.d.ts.map +1 -1
  35. package/dest/e2e_p2p/inactivity_slash_test.js +3 -3
  36. package/dest/e2e_p2p/p2p_network.d.ts +7 -6
  37. package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
  38. package/dest/e2e_p2p/p2p_network.js +111 -104
  39. package/dest/e2e_p2p/shared.d.ts +6 -6
  40. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  41. package/dest/e2e_p2p/shared.js +11 -18
  42. package/dest/e2e_token_contract/token_contract_test.d.ts +16 -9
  43. package/dest/e2e_token_contract/token_contract_test.d.ts.map +1 -1
  44. package/dest/e2e_token_contract/token_contract_test.js +89 -91
  45. package/dest/fixtures/e2e_prover_test.d.ts +8 -14
  46. package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
  47. package/dest/fixtures/e2e_prover_test.js +85 -94
  48. package/dest/fixtures/setup.d.ts +218 -0
  49. package/dest/fixtures/setup.d.ts.map +1 -0
  50. package/dest/fixtures/setup.js +690 -0
  51. package/dest/fixtures/token_utils.d.ts +1 -1
  52. package/dest/fixtures/token_utils.d.ts.map +1 -1
  53. package/dest/fixtures/token_utils.js +7 -4
  54. package/dest/fixtures/utils.d.ts +5 -194
  55. package/dest/fixtures/utils.d.ts.map +1 -1
  56. package/dest/fixtures/utils.js +4 -619
  57. package/dest/quality_of_service/grafana_client.d.ts +41 -0
  58. package/dest/quality_of_service/grafana_client.d.ts.map +1 -0
  59. package/dest/quality_of_service/{alert_checker.js → grafana_client.js} +1 -1
  60. package/dest/quality_of_service/prometheus_client.d.ts +38 -0
  61. package/dest/quality_of_service/prometheus_client.d.ts.map +1 -0
  62. package/dest/quality_of_service/prometheus_client.js +67 -0
  63. package/dest/shared/cross_chain_test_harness.d.ts +16 -6
  64. package/dest/shared/cross_chain_test_harness.d.ts.map +1 -1
  65. package/dest/shared/cross_chain_test_harness.js +13 -13
  66. package/dest/shared/gas_portal_test_harness.d.ts +11 -1
  67. package/dest/shared/gas_portal_test_harness.d.ts.map +1 -1
  68. package/dest/shared/gas_portal_test_harness.js +1 -1
  69. package/dest/shared/index.d.ts +2 -2
  70. package/dest/shared/index.d.ts.map +1 -1
  71. package/dest/shared/submit-transactions.d.ts +3 -3
  72. package/dest/shared/submit-transactions.d.ts.map +1 -1
  73. package/dest/shared/submit-transactions.js +9 -11
  74. package/dest/shared/uniswap_l1_l2.d.ts +3 -28
  75. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  76. package/dest/shared/uniswap_l1_l2.js +51 -33
  77. package/dest/simulators/lending_simulator.d.ts +5 -1
  78. package/dest/simulators/lending_simulator.d.ts.map +1 -1
  79. package/dest/simulators/lending_simulator.js +2 -2
  80. package/dest/spartan/setup_test_wallets.d.ts +4 -3
  81. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  82. package/dest/spartan/setup_test_wallets.js +61 -34
  83. package/dest/spartan/tx_metrics.d.ts +17 -2
  84. package/dest/spartan/tx_metrics.d.ts.map +1 -1
  85. package/dest/spartan/tx_metrics.js +183 -6
  86. package/dest/spartan/utils/bot.d.ts +27 -0
  87. package/dest/spartan/utils/bot.d.ts.map +1 -0
  88. package/dest/spartan/utils/bot.js +141 -0
  89. package/dest/spartan/utils/chaos.d.ts +79 -0
  90. package/dest/spartan/utils/chaos.d.ts.map +1 -0
  91. package/dest/spartan/utils/chaos.js +142 -0
  92. package/dest/spartan/utils/clients.d.ts +39 -0
  93. package/dest/spartan/utils/clients.d.ts.map +1 -0
  94. package/dest/spartan/utils/clients.js +90 -0
  95. package/dest/spartan/utils/config.d.ts +36 -0
  96. package/dest/spartan/utils/config.d.ts.map +1 -0
  97. package/dest/spartan/utils/config.js +20 -0
  98. package/dest/spartan/utils/health.d.ts +63 -0
  99. package/dest/spartan/utils/health.d.ts.map +1 -0
  100. package/dest/spartan/utils/health.js +202 -0
  101. package/dest/spartan/utils/helm.d.ts +15 -0
  102. package/dest/spartan/utils/helm.d.ts.map +1 -0
  103. package/dest/spartan/utils/helm.js +47 -0
  104. package/dest/spartan/utils/index.d.ts +9 -0
  105. package/dest/spartan/utils/index.d.ts.map +1 -0
  106. package/dest/spartan/utils/index.js +18 -0
  107. package/dest/spartan/utils/k8s.d.ts +98 -0
  108. package/dest/spartan/utils/k8s.d.ts.map +1 -0
  109. package/dest/spartan/utils/k8s.js +257 -0
  110. package/dest/spartan/utils/nodes.d.ts +31 -0
  111. package/dest/spartan/utils/nodes.d.ts.map +1 -0
  112. package/dest/spartan/utils/nodes.js +290 -0
  113. package/dest/spartan/utils/scripts.d.ts +16 -0
  114. package/dest/spartan/utils/scripts.d.ts.map +1 -0
  115. package/dest/spartan/utils/scripts.js +66 -0
  116. package/dest/spartan/utils.d.ts +2 -253
  117. package/dest/spartan/utils.d.ts.map +1 -1
  118. package/dest/spartan/utils.js +1 -892
  119. package/package.json +40 -39
  120. package/src/bench/client_flows/benchmark.ts +24 -2
  121. package/src/bench/client_flows/client_flows_benchmark.ts +138 -204
  122. package/src/bench/client_flows/data_extractor.ts +1 -1
  123. package/src/bench/utils.ts +20 -14
  124. package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +104 -142
  125. package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +127 -116
  126. package/src/e2e_deploy_contract/deploy_test.ts +21 -14
  127. package/src/e2e_epochs/epochs_test.ts +31 -26
  128. package/src/e2e_fees/bridging_race.notest.ts +3 -9
  129. package/src/e2e_fees/fees_test.ts +172 -220
  130. package/src/e2e_l1_publisher/write_json.ts +21 -16
  131. package/src/e2e_nested_contract/nested_contract_test.ts +33 -56
  132. package/src/e2e_p2p/inactivity_slash_test.ts +5 -5
  133. package/src/e2e_p2p/p2p_network.ts +172 -168
  134. package/src/e2e_p2p/shared.ts +16 -25
  135. package/src/e2e_token_contract/token_contract_test.ts +103 -118
  136. package/src/fixtures/e2e_prover_test.ts +98 -133
  137. package/src/fixtures/setup.ts +1017 -0
  138. package/src/fixtures/token_utils.ts +6 -5
  139. package/src/fixtures/utils.ts +27 -907
  140. package/src/quality_of_service/{alert_checker.ts → grafana_client.ts} +1 -1
  141. package/src/quality_of_service/prometheus_client.ts +113 -0
  142. package/src/shared/cross_chain_test_harness.ts +16 -36
  143. package/src/shared/gas_portal_test_harness.ts +1 -1
  144. package/src/shared/index.ts +1 -1
  145. package/src/shared/submit-transactions.ts +9 -15
  146. package/src/shared/uniswap_l1_l2.ts +58 -77
  147. package/src/simulators/lending_simulator.ts +2 -2
  148. package/src/spartan/setup_test_wallets.ts +79 -25
  149. package/src/spartan/tx_metrics.ts +129 -9
  150. package/src/spartan/utils/bot.ts +185 -0
  151. package/src/spartan/utils/chaos.ts +253 -0
  152. package/src/spartan/utils/clients.ts +100 -0
  153. package/src/spartan/utils/config.ts +26 -0
  154. package/src/spartan/utils/health.ts +255 -0
  155. package/src/spartan/utils/helm.ts +84 -0
  156. package/src/spartan/utils/index.ts +62 -0
  157. package/src/spartan/utils/k8s.ts +375 -0
  158. package/src/spartan/utils/nodes.ts +323 -0
  159. package/src/spartan/utils/scripts.ts +63 -0
  160. package/src/spartan/utils.ts +1 -1158
  161. package/dest/fixtures/snapshot_manager.d.ts +0 -93
  162. package/dest/fixtures/snapshot_manager.d.ts.map +0 -1
  163. package/dest/fixtures/snapshot_manager.js +0 -493
  164. package/dest/quality_of_service/alert_checker.d.ts +0 -41
  165. package/dest/quality_of_service/alert_checker.d.ts.map +0 -1
  166. package/src/fixtures/snapshot_manager.ts +0 -651
@@ -0,0 +1,98 @@
1
+ import { type ChildProcess } from 'child_process';
2
+ /**
3
+ * Represents an endpoint to reach a K8s service.
4
+ * May be a LoadBalancer external IP or a port-forward.
5
+ */
6
+ export interface ServiceEndpoint {
7
+ url: string;
8
+ process?: ChildProcess;
9
+ }
10
+ export declare function startPortForward({ resource, namespace, containerPort, hostPort }: {
11
+ resource: string;
12
+ namespace: string;
13
+ containerPort: number;
14
+ hostPort?: number;
15
+ }): Promise<{
16
+ process: ChildProcess;
17
+ port: number;
18
+ }>;
19
+ export declare function getExternalIP(namespace: string, serviceName: string): Promise<string>;
20
+ /**
21
+ * Gets an endpoint for a K8s service.
22
+ * By default, tries to get the external IP first and falls back to port-forward if unavailable.
23
+ *
24
+ * @param opts.namespace - K8s namespace
25
+ * @param opts.serviceName - Service name suffix (e.g., 'rpc-aztec-node', 'eth-execution')
26
+ * @param opts.containerPort - Port the service exposes
27
+ * @param opts.usePortForward - If true, skip external IP check and always use port-forward
28
+ */
29
+ export declare function getServiceEndpoint(opts: {
30
+ namespace: string;
31
+ serviceName: string;
32
+ containerPort: number;
33
+ forcePortForward?: boolean;
34
+ }): Promise<ServiceEndpoint>;
35
+ /**
36
+ * Gets an endpoint for the RPC node service.
37
+ * Tries external IP first, falls back to port-forward.
38
+ *
39
+ * @param namespace - K8s namespace
40
+ * @param usePortForward - If true, skip external IP and use port-forward directly
41
+ */
42
+ export declare function getRPCEndpoint(namespace: string, forcePortForward?: boolean): Promise<ServiceEndpoint>;
43
+ /**
44
+ * Gets an endpoint for the Ethereum execution service.
45
+ * Tries external IP first, falls back to port-forward.
46
+ *
47
+ * @param namespace - K8s namespace
48
+ * @param usePortForward - If true, skip external IP and use port-forward directly
49
+ */
50
+ export declare function getEthereumEndpoint(namespace: string, forcePortForward?: boolean): Promise<ServiceEndpoint>;
51
+ export declare function startPortForwardForPrometeheus(namespace: string): Promise<{
52
+ process: ChildProcess;
53
+ port: number;
54
+ }>;
55
+ export declare function startPortForwardForRPC(namespace: string, index?: number): Promise<{
56
+ process: ChildProcess;
57
+ port: number;
58
+ }>;
59
+ export declare function startPortForwardForEthereum(namespace: string): Promise<{
60
+ process: ChildProcess;
61
+ port: number;
62
+ }>;
63
+ export declare function deleteResourceByName({ resource, namespace, name, force }: {
64
+ resource: string;
65
+ namespace: string;
66
+ name: string;
67
+ force?: boolean;
68
+ }): Promise<string>;
69
+ export declare function deleteResourceByLabel({ resource, namespace, label, timeout, force }: {
70
+ resource: string;
71
+ namespace: string;
72
+ label: string;
73
+ timeout?: string;
74
+ force?: boolean;
75
+ }): Promise<string>;
76
+ export declare function waitForResourceByLabel({ resource, label, namespace, condition, timeout }: {
77
+ resource: string;
78
+ label: string;
79
+ namespace: string;
80
+ condition?: string;
81
+ timeout?: string;
82
+ }): Promise<string>;
83
+ export declare function waitForResourceByName({ resource, name, namespace, condition, timeout }: {
84
+ resource: string;
85
+ name: string;
86
+ namespace: string;
87
+ condition?: string;
88
+ timeout?: string;
89
+ }): Promise<string>;
90
+ export declare function waitForResourcesByName({ resource, names, namespace, condition, timeout }: {
91
+ resource: string;
92
+ names: string[];
93
+ namespace: string;
94
+ condition?: string;
95
+ timeout?: string;
96
+ }): Promise<void>;
97
+ export declare function getChartDir(spartanDir: string, chartName: string): string;
98
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiazhzLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc3BhcnRhbi91dGlscy9rOHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBSUEsT0FBTyxFQUFFLEtBQUssWUFBWSxFQUFlLE1BQU0sZUFBZSxDQUFDO0FBUS9EOzs7R0FHRztBQUNILE1BQU0sV0FBVyxlQUFlO0lBQzlCLEdBQUcsRUFBRSxNQUFNLENBQUM7SUFDWixPQUFPLENBQUMsRUFBRSxZQUFZLENBQUM7Q0FDeEI7QUFFRCx3QkFBc0IsZ0JBQWdCLENBQUMsRUFDckMsUUFBUSxFQUNSLFNBQVMsRUFDVCxhQUFhLEVBQ2IsUUFBUSxFQUNULEVBQUU7SUFDRCxRQUFRLEVBQUUsTUFBTSxDQUFDO0lBQ2pCLFNBQVMsRUFBRSxNQUFNLENBQUM7SUFDbEIsYUFBYSxFQUFFLE1BQU0sQ0FBQztJQUV0QixRQUFRLENBQUMsRUFBRSxNQUFNLENBQUM7Q0FDbkIsR0FBRyxPQUFPLENBQUM7SUFDVixPQUFPLEVBQUUsWUFBWSxDQUFDO0lBQ3RCLElBQUksRUFBRSxNQUFNLENBQUM7Q0FDZCxDQUFDLENBdUVEO0FBRUQsd0JBQWdCLGFBQWEsQ0FBQyxTQUFTLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQStCckY7QUFFRDs7Ozs7Ozs7R0FRRztBQUNILHdCQUFzQixrQkFBa0IsQ0FBQyxJQUFJLEVBQUU7SUFDN0MsU0FBUyxFQUFFLE1BQU0sQ0FBQztJQUNsQixXQUFXLEVBQUUsTUFBTSxDQUFDO0lBQ3BCLGFBQWEsRUFBRSxNQUFNLENBQUM7SUFDdEIsZ0JBQWdCLENBQUMsRUFBRSxPQUFPLENBQUM7Q0FDNUIsR0FBRyxPQUFPLENBQUMsZUFBZSxDQUFDLENBc0MzQjtBQUVEOzs7Ozs7R0FNRztBQUNILHdCQUFzQixjQUFjLENBQUMsU0FBUyxFQUFFLE1BQU0sRUFBRSxnQkFBZ0IsQ0FBQyxFQUFFLE9BQU8sR0FB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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"k8s.d.ts","sourceRoot":"","sources":["../../../src/spartan/utils/k8s.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,257 @@
1
+ import { createLogger } from '@aztec/aztec.js/log';
2
+ import { promiseWithResolvers } from '@aztec/foundation/promise';
3
+ import { retryUntil } from '@aztec/foundation/retry';
4
+ import { exec, spawn } from 'child_process';
5
+ import path from 'path';
6
+ import { promisify } from 'util';
7
+ const execAsync = promisify(exec);
8
+ const logger = createLogger('e2e:k8s-utils');
9
+ export async function startPortForward({ resource, namespace, containerPort, hostPort }) {
10
+ const hostPortAsString = hostPort ? hostPort.toString() : '';
11
+ logger.debug(`kubectl port-forward -n ${namespace} ${resource} ${hostPortAsString}:${containerPort}`);
12
+ const process = spawn('kubectl', [
13
+ 'port-forward',
14
+ '-n',
15
+ namespace,
16
+ resource,
17
+ `${hostPortAsString}:${containerPort}`
18
+ ], {
19
+ detached: true,
20
+ windowsHide: true,
21
+ stdio: [
22
+ 'ignore',
23
+ 'pipe',
24
+ 'pipe'
25
+ ]
26
+ });
27
+ let isResolved = false;
28
+ const connected = new Promise((resolve, reject)=>{
29
+ process.stdout?.on('data', (data)=>{
30
+ const str = data.toString();
31
+ if (!isResolved && str.includes('Forwarding from')) {
32
+ isResolved = true;
33
+ logger.debug(`Port forward for ${resource}: ${str}`);
34
+ const port = str.search(/:\d+/);
35
+ if (port === -1) {
36
+ reject(new Error('Port not found in port forward output'));
37
+ return;
38
+ }
39
+ const portNumber = parseInt(str.slice(port + 1));
40
+ logger.verbose(`Port forwarded for ${resource} at ${portNumber}:${containerPort}`);
41
+ resolve(portNumber);
42
+ } else {
43
+ logger.silent(str);
44
+ }
45
+ });
46
+ process.stderr?.on('data', (data)=>{
47
+ logger.verbose(`Port forward for ${resource}: ${data.toString()}`);
48
+ // It's a strange thing:
49
+ // If we don't pipe stderr, then the port forwarding does not work.
50
+ // Log to silent because this doesn't actually report errors,
51
+ // just extremely verbose debug logs.
52
+ logger.silent(data.toString());
53
+ });
54
+ process.on('close', ()=>{
55
+ if (!isResolved) {
56
+ isResolved = true;
57
+ const msg = `Port forward for ${resource} closed before connection established`;
58
+ logger.warn(msg);
59
+ reject(new Error(msg));
60
+ }
61
+ });
62
+ process.on('error', (error)=>{
63
+ if (!isResolved) {
64
+ isResolved = true;
65
+ const msg = `Port forward for ${resource} error: ${error}`;
66
+ logger.error(msg);
67
+ reject(new Error(msg));
68
+ }
69
+ });
70
+ process.on('exit', (code)=>{
71
+ if (!isResolved) {
72
+ isResolved = true;
73
+ const msg = `Port forward for ${resource} exited with code ${code}`;
74
+ logger.verbose(msg);
75
+ reject(new Error(msg));
76
+ }
77
+ });
78
+ });
79
+ const port = await connected;
80
+ return {
81
+ process,
82
+ port
83
+ };
84
+ }
85
+ export function getExternalIP(namespace, serviceName) {
86
+ const { promise, resolve, reject } = promiseWithResolvers();
87
+ const process = spawn('kubectl', [
88
+ 'get',
89
+ 'service',
90
+ '-n',
91
+ namespace,
92
+ `${namespace}-${serviceName}`,
93
+ '--output',
94
+ "jsonpath='{.status.loadBalancer.ingress[0].ip}'"
95
+ ], {
96
+ stdio: 'pipe'
97
+ });
98
+ let ip = '';
99
+ process.stdout.on('data', (data)=>{
100
+ ip += data;
101
+ });
102
+ process.on('error', (err)=>{
103
+ reject(err);
104
+ });
105
+ process.on('exit', ()=>{
106
+ // kubectl prints JSON. Remove the quotes
107
+ resolve(ip.replace(/"|'/g, ''));
108
+ });
109
+ return promise;
110
+ }
111
+ /**
112
+ * Gets an endpoint for a K8s service.
113
+ * By default, tries to get the external IP first and falls back to port-forward if unavailable.
114
+ *
115
+ * @param opts.namespace - K8s namespace
116
+ * @param opts.serviceName - Service name suffix (e.g., 'rpc-aztec-node', 'eth-execution')
117
+ * @param opts.containerPort - Port the service exposes
118
+ * @param opts.usePortForward - If true, skip external IP check and always use port-forward
119
+ */ export async function getServiceEndpoint(opts) {
120
+ const { namespace, serviceName, containerPort, forcePortForward } = opts;
121
+ if (!forcePortForward) {
122
+ try {
123
+ const ip = await retryUntil(async ()=>{
124
+ try {
125
+ const ip = await getExternalIP(namespace, serviceName);
126
+ if (ip && ip !== '' && ip !== '<pending>' && ip !== 'null') {
127
+ return ip;
128
+ }
129
+ } catch (err) {
130
+ logger.verbose(`Failed to get external IP for ${serviceName}: ${err}`);
131
+ }
132
+ return undefined;
133
+ }, `external IP for ${serviceName}`, 30, 5);
134
+ logger.info(`Using external IP for ${serviceName}: ${ip}:${containerPort}`);
135
+ return {
136
+ url: `http://${ip}:${containerPort}`
137
+ };
138
+ } catch {
139
+ logger.warn(`External IP not available for ${serviceName} after 5min, using port-forward`);
140
+ }
141
+ }
142
+ // Fallback to port-forward
143
+ const resource = `svc/${namespace}-${serviceName}`;
144
+ const { process, port } = await startPortForward({
145
+ resource,
146
+ namespace,
147
+ containerPort
148
+ });
149
+ return {
150
+ url: `http://127.0.0.1:${port}`,
151
+ process
152
+ };
153
+ }
154
+ /**
155
+ * Gets an endpoint for the RPC node service.
156
+ * Tries external IP first, falls back to port-forward.
157
+ *
158
+ * @param namespace - K8s namespace
159
+ * @param usePortForward - If true, skip external IP and use port-forward directly
160
+ */ export async function getRPCEndpoint(namespace, forcePortForward) {
161
+ return await getServiceEndpoint({
162
+ namespace,
163
+ serviceName: 'rpc-aztec-node',
164
+ containerPort: 8080,
165
+ forcePortForward
166
+ });
167
+ }
168
+ /**
169
+ * Gets an endpoint for the Ethereum execution service.
170
+ * Tries external IP first, falls back to port-forward.
171
+ *
172
+ * @param namespace - K8s namespace
173
+ * @param usePortForward - If true, skip external IP and use port-forward directly
174
+ */ export async function getEthereumEndpoint(namespace, forcePortForward) {
175
+ return await getServiceEndpoint({
176
+ namespace,
177
+ serviceName: 'eth-execution',
178
+ containerPort: 8545,
179
+ forcePortForward
180
+ });
181
+ }
182
+ export function startPortForwardForPrometeheus(namespace) {
183
+ return startPortForward({
184
+ resource: `svc/${namespace}-prometheus-server`,
185
+ namespace,
186
+ containerPort: 80
187
+ });
188
+ }
189
+ export function startPortForwardForRPC(namespace, index = 0) {
190
+ return startPortForward({
191
+ resource: `pod/${namespace}-rpc-aztec-node-${index}`,
192
+ namespace,
193
+ containerPort: 8080
194
+ });
195
+ }
196
+ export function startPortForwardForEthereum(namespace) {
197
+ return startPortForward({
198
+ resource: `services/${namespace}-eth-execution`,
199
+ namespace,
200
+ containerPort: 8545
201
+ });
202
+ }
203
+ export async function deleteResourceByName({ resource, namespace, name, force = false }) {
204
+ const command = `kubectl delete ${resource} ${name} -n ${namespace} --ignore-not-found=true --wait=true ${force ? '--force' : ''}`;
205
+ logger.info(`command: ${command}`);
206
+ const { stdout } = await execAsync(command);
207
+ return stdout;
208
+ }
209
+ export async function deleteResourceByLabel({ resource, namespace, label, timeout = '5m', force = false }) {
210
+ try {
211
+ // Match both plain and group-qualified names (e.g., "podchaos" or "podchaos.chaos-mesh.org")
212
+ const escaped = resource.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
213
+ const regex = `(^|\\.)${escaped}(\\.|$)`;
214
+ await execAsync(`kubectl api-resources --no-headers -o name | grep -Eq '${regex}'`);
215
+ } catch (error) {
216
+ logger.warn(`Resource type '${resource}' not found in cluster, skipping deletion ${error}`);
217
+ return '';
218
+ }
219
+ const command = `kubectl delete ${resource} -l ${label} -n ${namespace} --ignore-not-found=true --wait=true --timeout=${timeout} ${force ? '--force' : ''}`;
220
+ logger.info(`command: ${command}`);
221
+ const { stdout } = await execAsync(command);
222
+ return stdout;
223
+ }
224
+ export async function waitForResourceByLabel({ resource, label, namespace, condition = 'Ready', timeout = '10m' }) {
225
+ const command = `kubectl wait ${resource} -l ${label} --for=condition=${condition} -n ${namespace} --timeout=${timeout}`;
226
+ logger.info(`command: ${command}`);
227
+ const { stdout } = await execAsync(command);
228
+ return stdout;
229
+ }
230
+ export async function waitForResourceByName({ resource, name, namespace, condition = 'Ready', timeout = '10m' }) {
231
+ const command = `kubectl wait ${resource}/${name} --for=condition=${condition} -n ${namespace} --timeout=${timeout}`;
232
+ logger.info(`command: ${command}`);
233
+ const { stdout } = await execAsync(command);
234
+ return stdout;
235
+ }
236
+ export async function waitForResourcesByName({ resource, names, namespace, condition = 'Ready', timeout = '10m' }) {
237
+ if (!names.length) {
238
+ throw new Error(`No ${resource} names provided to waitForResourcesByName`);
239
+ }
240
+ // Wait all in parallel; if any fails, surface which one.
241
+ await Promise.all(names.map(async (name)=>{
242
+ try {
243
+ await waitForResourceByName({
244
+ resource,
245
+ name,
246
+ namespace,
247
+ condition,
248
+ timeout
249
+ });
250
+ } catch (err) {
251
+ throw new Error(`Failed waiting for ${resource}/${name} condition=${condition} timeout=${timeout} namespace=${namespace}: ${String(err)}`);
252
+ }
253
+ }));
254
+ }
255
+ export function getChartDir(spartanDir, chartName) {
256
+ return path.join(spartanDir.trim(), chartName);
257
+ }
@@ -0,0 +1,31 @@
1
+ import type { RollupCheatCodes } from '@aztec/aztec/testing';
2
+ import type { CheckpointNumber } from '@aztec/foundation/branded-types';
3
+ import type { Logger } from '@aztec/foundation/log';
4
+ import { type AztecNodeAdmin, type AztecNodeAdminConfig } from '@aztec/stdlib/interfaces/client';
5
+ import type { TestConfig } from './config.js';
6
+ export declare function awaitCheckpointNumber(rollupCheatCodes: RollupCheatCodes, checkpointNumber: CheckpointNumber, timeoutSeconds: number, log: Logger): Promise<void>;
7
+ export declare function getSequencers(namespace: string): Promise<string[]>;
8
+ export declare function updateSequencersConfig(env: TestConfig, config: Partial<AztecNodeAdminConfig>): Promise<AztecNodeAdminConfig[]>;
9
+ export declare function getSequencersConfig(env: TestConfig): Promise<AztecNodeAdminConfig[]>;
10
+ export declare function withSequencersAdmin<T>(env: TestConfig, fn: (node: AztecNodeAdmin) => Promise<T>): Promise<T[]>;
11
+ /**
12
+ * Enables or disables probabilistic transaction dropping on validators and waits for rollout.
13
+ * Wired to env vars P2P_DROP_TX and P2P_DROP_TX_CHANCE via Helm values.
14
+ */
15
+ export declare function setValidatorTxDrop({ namespace, enabled, probability, logger: log }: {
16
+ namespace: string;
17
+ enabled: boolean;
18
+ probability: number;
19
+ logger: Logger;
20
+ }): Promise<void>;
21
+ export declare function restartValidators(namespace: string, log: Logger): Promise<void>;
22
+ export declare function enableValidatorDynamicBootNode(instanceName: string, namespace: string, spartanDir: string, log: Logger): Promise<void>;
23
+ /**
24
+ * Rolls the Aztec pods in the given namespace.
25
+ * @param namespace - The namespace to roll the Aztec pods in.
26
+ * @param clearState - If true, also deletes the underlying PVCs to clear persistent storage.
27
+ * This is required for rollup upgrades where the old state is incompatible with the new rollup.
28
+ * Defaults to false, which preserves the existing storage.
29
+ */
30
+ export declare function rollAztecPods(namespace: string, clearState?: boolean): Promise<void>;
31
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZXMuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zcGFydGFuL3V0aWxzL25vZGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sS0FBSyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDN0QsT0FBTyxLQUFLLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUN4RSxPQUFPLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUdwRCxPQUFPLEVBQ0wsS0FBSyxjQUFjLEVBQ25CLEtBQUssb0JBQW9CLEVBRTFCLE1BQU0saUNBQWlDLENBQUM7QUFLekMsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBUTlDLHdCQUFzQixxQkFBcUIsQ0FDekMsZ0JBQWdCLEVBQUUsZ0JBQWdCLEVBQ2xDLGdCQUFnQixFQUFFLGdCQUFnQixFQUNsQyxjQUFjLEVBQUUsTUFBTSxFQUN0QixHQUFHLEVBQUUsTUFBTSxpQkFlWjtBQUVELHdCQUFzQixhQUFhLENBQUMsU0FBUyxFQUFFLE1BQU0scUJBNEJwRDtBQUVELHdCQUFnQixzQkFBc0IsQ0FBQyxHQUFHLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsb0JBQW9CLENBQUMsbUNBSzVGO0FBRUQsd0JBQWdCLG1CQUFtQixDQUFDLEdBQUcsRUFBRSxVQUFVLG1DQUVsRDtBQUVELHdCQUFzQixtQkFBbUIsQ0FBQyxDQUFDLEVBQUUsR0FBRyxFQUFFLFVBQVUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxJQUFJLEVBQUUsY0FBYyxLQUFLLE9BQU8sQ0FBQyxDQUFDLENBQUMsR0FBRyxPQUFPLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0EwQ3BIO0FBRUQ7OztHQUdHO0FBQ0gsd0JBQXNCLGtCQUFrQixDQUFDLEVBQ3ZDLFNBQVMsRUFDVCxPQUFPLEVBQ1AsV0FBVyxFQUNYLE1BQU0sRUFBRSxHQUFHLEVBQ1osRUFBRTtJQUNELFNBQVMsRUFBRSxNQUFNLENBQUM7SUFDbEIsT0FBTyxFQUFFLE9BQU8sQ0FBQztJQUNqQixXQUFXLEVBQUUsTUFBTSxDQUFDO0lBQ3BCLE1BQU0sRUFBRSxNQUFNLENBQUM7Q0FDaEIsaUJBZ0NBO0FBRUQsd0JBQXNCLGlCQUFpQixDQUFDLFNBQVMsRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLE1BQU0saUJBK0JyRTtBQUVELHdCQUFzQiw4QkFBOEIsQ0FDbEQsWUFBWSxFQUFFLE1BQU0sRUFDcEIsU0FBUyxFQUFFLE1BQU0sRUFDakIsVUFBVSxFQUFFLE1BQU0sRUFDbEIsR0FBRyxFQUFFLE1BQU0saUJBZ0JaO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsd0JBQXNCLGFBQWEsQ0FBQyxTQUFTLEVBQUUsTUFBTSxFQUFFLFVBQVUsR0FBRSxPQUFlLGlCQW1GakYifQ==
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nodes.d.ts","sourceRoot":"","sources":["../../../src/spartan/utils/nodes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAGpD,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,oBAAoB,EAE1B,MAAM,iCAAiC,CAAC;AAKzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAQ9C,wBAAsB,qBAAqB,CACzC,gBAAgB,EAAE,gBAAgB,EAClC,gBAAgB,EAAE,gBAAgB,EAClC,cAAc,EAAE,MAAM,EACtB,GAAG,EAAE,MAAM,iBAeZ;AAED,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,qBA4BpD;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,oBAAoB,CAAC,mCAK5F;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,UAAU,mCAElD;AAED,wBAAsB,mBAAmB,CAAC,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CA0CpH;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,EACvC,SAAS,EACT,OAAO,EACP,WAAW,EACX,MAAM,EAAE,GAAG,EACZ,EAAE;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB,iBAgCA;AAED,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,iBA+BrE;AAED,wBAAsB,8BAA8B,CAClD,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,iBAgBZ;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,GAAE,OAAe,iBAmFjF"}