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

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 (234) 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 +13 -14
  5. package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -1
  6. package/dest/bench/client_flows/client_flows_benchmark.js +121 -136
  7. package/dest/bench/client_flows/config.d.ts +2 -2
  8. package/dest/bench/client_flows/config.d.ts.map +1 -1
  9. package/dest/bench/client_flows/config.js +18 -0
  10. package/dest/bench/client_flows/data_extractor.js +3 -1
  11. package/dest/bench/utils.d.ts +9 -8
  12. package/dest/bench/utils.d.ts.map +1 -1
  13. package/dest/bench/utils.js +17 -12
  14. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +9 -8
  15. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts.map +1 -1
  16. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.js +106 -112
  17. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts +16 -11
  18. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts.map +1 -1
  19. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.js +90 -70
  20. package/dest/e2e_deploy_contract/deploy_test.d.ts +5 -4
  21. package/dest/e2e_deploy_contract/deploy_test.d.ts.map +1 -1
  22. package/dest/e2e_deploy_contract/deploy_test.js +18 -13
  23. package/dest/e2e_epochs/epochs_test.d.ts +15 -7
  24. package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
  25. package/dest/e2e_epochs/epochs_test.js +87 -40
  26. package/dest/e2e_fees/bridging_race.notest.js +3 -5
  27. package/dest/e2e_fees/fees_test.d.ts +14 -14
  28. package/dest/e2e_fees/fees_test.d.ts.map +1 -1
  29. package/dest/e2e_fees/fees_test.js +125 -143
  30. package/dest/e2e_l1_publisher/write_json.d.ts +4 -3
  31. package/dest/e2e_l1_publisher/write_json.d.ts.map +1 -1
  32. package/dest/e2e_l1_publisher/write_json.js +14 -16
  33. package/dest/e2e_nested_contract/nested_contract_test.d.ts +6 -9
  34. package/dest/e2e_nested_contract/nested_contract_test.d.ts.map +1 -1
  35. package/dest/e2e_nested_contract/nested_contract_test.js +31 -39
  36. package/dest/e2e_p2p/inactivity_slash_test.d.ts +3 -3
  37. package/dest/e2e_p2p/inactivity_slash_test.d.ts.map +1 -1
  38. package/dest/e2e_p2p/inactivity_slash_test.js +3 -3
  39. package/dest/e2e_p2p/p2p_network.d.ts +8 -7
  40. package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
  41. package/dest/e2e_p2p/p2p_network.js +127 -106
  42. package/dest/e2e_p2p/reqresp/utils.d.ts +22 -0
  43. package/dest/e2e_p2p/reqresp/utils.d.ts.map +1 -0
  44. package/dest/e2e_p2p/reqresp/utils.js +177 -0
  45. package/dest/e2e_p2p/shared.d.ts +6 -6
  46. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  47. package/dest/e2e_p2p/shared.js +18 -21
  48. package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.d.ts +2 -0
  49. package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.d.ts.map +1 -0
  50. package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.js +184 -0
  51. package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.d.ts +18 -0
  52. package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.d.ts.map +1 -0
  53. package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.js +120 -0
  54. package/dest/e2e_token_contract/token_contract_test.d.ts +19 -10
  55. package/dest/e2e_token_contract/token_contract_test.d.ts.map +1 -1
  56. package/dest/e2e_token_contract/token_contract_test.js +99 -91
  57. package/dest/fixtures/authwit_proxy.d.ts +15 -0
  58. package/dest/fixtures/authwit_proxy.d.ts.map +1 -0
  59. package/dest/fixtures/authwit_proxy.js +30 -0
  60. package/dest/fixtures/e2e_prover_test.d.ts +11 -17
  61. package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
  62. package/dest/fixtures/e2e_prover_test.js +112 -128
  63. package/dest/fixtures/fixtures.d.ts +5 -1
  64. package/dest/fixtures/fixtures.d.ts.map +1 -1
  65. package/dest/fixtures/fixtures.js +6 -0
  66. package/dest/fixtures/ha_setup.d.ts +71 -0
  67. package/dest/fixtures/ha_setup.d.ts.map +1 -0
  68. package/dest/fixtures/ha_setup.js +116 -0
  69. package/dest/fixtures/index.d.ts +2 -1
  70. package/dest/fixtures/index.d.ts.map +1 -1
  71. package/dest/fixtures/index.js +1 -0
  72. package/dest/fixtures/setup.d.ts +235 -0
  73. package/dest/fixtures/setup.d.ts.map +1 -0
  74. package/dest/fixtures/setup.js +605 -0
  75. package/dest/fixtures/setup_p2p_test.d.ts +16 -9
  76. package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
  77. package/dest/fixtures/setup_p2p_test.js +40 -29
  78. package/dest/fixtures/token_utils.d.ts +2 -2
  79. package/dest/fixtures/token_utils.d.ts.map +1 -1
  80. package/dest/fixtures/token_utils.js +10 -6
  81. package/dest/fixtures/utils.d.ts +5 -194
  82. package/dest/fixtures/utils.d.ts.map +1 -1
  83. package/dest/fixtures/utils.js +4 -619
  84. package/dest/quality_of_service/grafana_client.d.ts +41 -0
  85. package/dest/quality_of_service/grafana_client.d.ts.map +1 -0
  86. package/dest/quality_of_service/{alert_checker.js → grafana_client.js} +1 -1
  87. package/dest/quality_of_service/prometheus_client.d.ts +38 -0
  88. package/dest/quality_of_service/prometheus_client.d.ts.map +1 -0
  89. package/dest/quality_of_service/prometheus_client.js +67 -0
  90. package/dest/shared/cross_chain_test_harness.d.ts +16 -6
  91. package/dest/shared/cross_chain_test_harness.d.ts.map +1 -1
  92. package/dest/shared/cross_chain_test_harness.js +13 -13
  93. package/dest/shared/gas_portal_test_harness.d.ts +11 -1
  94. package/dest/shared/gas_portal_test_harness.d.ts.map +1 -1
  95. package/dest/shared/gas_portal_test_harness.js +1 -1
  96. package/dest/shared/index.d.ts +3 -2
  97. package/dest/shared/index.d.ts.map +1 -1
  98. package/dest/shared/index.js +1 -0
  99. package/dest/shared/mock_state_view.d.ts +86 -0
  100. package/dest/shared/mock_state_view.d.ts.map +1 -0
  101. package/dest/shared/mock_state_view.js +186 -0
  102. package/dest/shared/submit-transactions.d.ts +4 -4
  103. package/dest/shared/submit-transactions.d.ts.map +1 -1
  104. package/dest/shared/submit-transactions.js +9 -11
  105. package/dest/shared/uniswap_l1_l2.d.ts +3 -28
  106. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  107. package/dest/shared/uniswap_l1_l2.js +53 -33
  108. package/dest/simulators/lending_simulator.d.ts +5 -1
  109. package/dest/simulators/lending_simulator.d.ts.map +1 -1
  110. package/dest/simulators/lending_simulator.js +2 -2
  111. package/dest/simulators/token_simulator.d.ts +1 -1
  112. package/dest/simulators/token_simulator.d.ts.map +1 -1
  113. package/dest/simulators/token_simulator.js +2 -23
  114. package/dest/spartan/setup_test_wallets.d.ts +12 -4
  115. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  116. package/dest/spartan/setup_test_wallets.js +92 -35
  117. package/dest/spartan/tx_metrics.d.ts +51 -2
  118. package/dest/spartan/tx_metrics.d.ts.map +1 -1
  119. package/dest/spartan/tx_metrics.js +333 -6
  120. package/dest/spartan/utils/bot.d.ts +28 -0
  121. package/dest/spartan/utils/bot.d.ts.map +1 -0
  122. package/dest/spartan/utils/bot.js +142 -0
  123. package/dest/spartan/utils/chaos.d.ts +79 -0
  124. package/dest/spartan/utils/chaos.d.ts.map +1 -0
  125. package/dest/spartan/utils/chaos.js +142 -0
  126. package/dest/spartan/utils/clients.d.ts +39 -0
  127. package/dest/spartan/utils/clients.d.ts.map +1 -0
  128. package/dest/spartan/utils/clients.js +90 -0
  129. package/dest/spartan/utils/config.d.ts +39 -0
  130. package/dest/spartan/utils/config.d.ts.map +1 -0
  131. package/dest/spartan/utils/config.js +21 -0
  132. package/dest/spartan/utils/health.d.ts +63 -0
  133. package/dest/spartan/utils/health.d.ts.map +1 -0
  134. package/dest/spartan/utils/health.js +202 -0
  135. package/dest/spartan/utils/helm.d.ts +15 -0
  136. package/dest/spartan/utils/helm.d.ts.map +1 -0
  137. package/dest/spartan/utils/helm.js +47 -0
  138. package/dest/spartan/utils/index.d.ts +9 -0
  139. package/dest/spartan/utils/index.d.ts.map +1 -0
  140. package/dest/spartan/utils/index.js +18 -0
  141. package/dest/spartan/utils/k8s.d.ts +128 -0
  142. package/dest/spartan/utils/k8s.d.ts.map +1 -0
  143. package/dest/spartan/utils/k8s.js +381 -0
  144. package/dest/spartan/utils/nodes.d.ts +40 -0
  145. package/dest/spartan/utils/nodes.d.ts.map +1 -0
  146. package/dest/spartan/utils/nodes.js +460 -0
  147. package/dest/spartan/utils/scripts.d.ts +30 -0
  148. package/dest/spartan/utils/scripts.d.ts.map +1 -0
  149. package/dest/spartan/utils/scripts.js +81 -0
  150. package/dest/spartan/utils.d.ts +2 -253
  151. package/dest/spartan/utils.d.ts.map +1 -1
  152. package/dest/spartan/utils.js +1 -892
  153. package/dest/test-wallet/test_wallet.d.ts +83 -0
  154. package/dest/test-wallet/test_wallet.d.ts.map +1 -0
  155. package/dest/test-wallet/test_wallet.js +214 -0
  156. package/dest/test-wallet/utils.d.ts +41 -0
  157. package/dest/test-wallet/utils.d.ts.map +1 -0
  158. package/dest/test-wallet/utils.js +71 -0
  159. package/dest/test-wallet/wallet_worker_script.d.ts +2 -0
  160. package/dest/test-wallet/wallet_worker_script.d.ts.map +1 -0
  161. package/dest/test-wallet/wallet_worker_script.js +40 -0
  162. package/dest/test-wallet/worker_wallet.d.ts +52 -0
  163. package/dest/test-wallet/worker_wallet.d.ts.map +1 -0
  164. package/dest/test-wallet/worker_wallet.js +103 -0
  165. package/dest/test-wallet/worker_wallet_schema.d.ts +274 -0
  166. package/dest/test-wallet/worker_wallet_schema.d.ts.map +1 -0
  167. package/dest/test-wallet/worker_wallet_schema.js +10 -0
  168. package/package.json +44 -39
  169. package/src/bench/client_flows/benchmark.ts +24 -2
  170. package/src/bench/client_flows/client_flows_benchmark.ts +141 -211
  171. package/src/bench/client_flows/config.ts +9 -1
  172. package/src/bench/client_flows/data_extractor.ts +1 -1
  173. package/src/bench/utils.ts +21 -15
  174. package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +114 -143
  175. package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +127 -117
  176. package/src/e2e_deploy_contract/deploy_test.ts +22 -15
  177. package/src/e2e_epochs/epochs_test.ts +130 -94
  178. package/src/e2e_fees/bridging_race.notest.ts +4 -10
  179. package/src/e2e_fees/fees_test.ts +164 -227
  180. package/src/e2e_l1_publisher/write_json.ts +16 -16
  181. package/src/e2e_nested_contract/nested_contract_test.ts +33 -56
  182. package/src/e2e_p2p/inactivity_slash_test.ts +3 -3
  183. package/src/e2e_p2p/p2p_network.ts +197 -171
  184. package/src/e2e_p2p/reqresp/utils.ts +235 -0
  185. package/src/e2e_p2p/shared.ts +28 -27
  186. package/src/e2e_storage_proof/fixtures/storage_proof.json +915 -0
  187. package/src/e2e_storage_proof/fixtures/storage_proof_fetcher.ts +190 -0
  188. package/src/e2e_storage_proof/fixtures/storage_proof_fixture.ts +173 -0
  189. package/src/e2e_token_contract/token_contract_test.ts +113 -119
  190. package/src/fixtures/authwit_proxy.ts +50 -0
  191. package/src/fixtures/dumps/epoch_proof_result.json +1 -1
  192. package/src/fixtures/e2e_prover_test.ts +127 -172
  193. package/src/fixtures/fixtures.ts +10 -0
  194. package/src/fixtures/ha_setup.ts +186 -0
  195. package/src/fixtures/index.ts +1 -0
  196. package/src/fixtures/setup.ts +896 -0
  197. package/src/fixtures/setup_p2p_test.ts +40 -44
  198. package/src/fixtures/token_utils.ts +7 -5
  199. package/src/fixtures/utils.ts +27 -907
  200. package/src/guides/up_quick_start.sh +3 -3
  201. package/src/quality_of_service/{alert_checker.ts → grafana_client.ts} +1 -1
  202. package/src/quality_of_service/prometheus_client.ts +113 -0
  203. package/src/shared/cross_chain_test_harness.ts +16 -36
  204. package/src/shared/gas_portal_test_harness.ts +1 -1
  205. package/src/shared/index.ts +2 -1
  206. package/src/shared/mock_state_view.ts +188 -0
  207. package/src/shared/submit-transactions.ts +14 -16
  208. package/src/shared/uniswap_l1_l2.ts +59 -80
  209. package/src/simulators/lending_simulator.ts +2 -2
  210. package/src/simulators/token_simulator.ts +1 -29
  211. package/src/spartan/setup_test_wallets.ts +134 -26
  212. package/src/spartan/tx_metrics.ts +255 -9
  213. package/src/spartan/utils/bot.ts +188 -0
  214. package/src/spartan/utils/chaos.ts +253 -0
  215. package/src/spartan/utils/clients.ts +100 -0
  216. package/src/spartan/utils/config.ts +27 -0
  217. package/src/spartan/utils/health.ts +255 -0
  218. package/src/spartan/utils/helm.ts +84 -0
  219. package/src/spartan/utils/index.ts +65 -0
  220. package/src/spartan/utils/k8s.ts +535 -0
  221. package/src/spartan/utils/nodes.ts +535 -0
  222. package/src/spartan/utils/scripts.ts +99 -0
  223. package/src/spartan/utils.ts +1 -1158
  224. package/src/test-wallet/test_wallet.ts +306 -0
  225. package/src/test-wallet/utils.ts +112 -0
  226. package/src/test-wallet/wallet_worker_script.ts +43 -0
  227. package/src/test-wallet/worker_wallet.ts +165 -0
  228. package/src/test-wallet/worker_wallet_schema.ts +13 -0
  229. package/dest/fixtures/snapshot_manager.d.ts +0 -93
  230. package/dest/fixtures/snapshot_manager.d.ts.map +0 -1
  231. package/dest/fixtures/snapshot_manager.js +0 -493
  232. package/dest/quality_of_service/alert_checker.d.ts +0 -41
  233. package/dest/quality_of_service/alert_checker.d.ts.map +0 -1
  234. package/src/fixtures/snapshot_manager.ts +0 -651
@@ -0,0 +1,460 @@
1
+ import { createLogger } from '@aztec/aztec.js/log';
2
+ import { createAztecNodeClient } from '@aztec/aztec.js/node';
3
+ import { makeBackoff, retry, retryUntil } from '@aztec/foundation/retry';
4
+ import { sleep } from '@aztec/foundation/sleep';
5
+ import { createAztecNodeAdminClient } from '@aztec/stdlib/interfaces/client';
6
+ import { exec } from 'child_process';
7
+ import { promisify } from 'util';
8
+ import { execHelmCommand } from './helm.js';
9
+ import { deleteResourceByLabel, getChartDir, startPortForward, waitForResourceByLabel, waitForResourceByName, waitForStatefulSetsReady } from './k8s.js';
10
+ const execAsync = promisify(exec);
11
+ const logger = createLogger('e2e:k8s-utils');
12
+ export async function awaitCheckpointNumber(rollupCheatCodes, checkpointNumber, timeoutSeconds, log) {
13
+ log.info(`Waiting for checkpoint ${checkpointNumber}`);
14
+ let tips = await rollupCheatCodes.getTips();
15
+ const endTime = Date.now() + timeoutSeconds * 1000;
16
+ while(tips.pending < checkpointNumber && Date.now() < endTime){
17
+ log.info(`At checkpoint ${tips.pending}`);
18
+ await sleep(1000);
19
+ tips = await rollupCheatCodes.getTips();
20
+ }
21
+ if (tips.pending < checkpointNumber) {
22
+ throw new Error(`Timeout waiting for checkpoint ${checkpointNumber}, only reached ${tips.pending}`);
23
+ } else {
24
+ log.info(`Reached checkpoint ${tips.pending}`);
25
+ }
26
+ }
27
+ /**
28
+ * Waits until the proven block number increases.
29
+ *
30
+ * @param rpcUrl - URL of an Aztec RPC node to query
31
+ * @param log - Logger instance
32
+ * @param timeoutSeconds - Maximum time to wait
33
+ * @param pollIntervalSeconds - How often to check
34
+ */ export async function waitForProvenToAdvance(rpcUrl, log, timeoutSeconds = 300, pollIntervalSeconds = 12) {
35
+ const node = createAztecNodeClient(rpcUrl);
36
+ log.info('Waiting for proven block to advance (indicating epoch proof just submitted)...');
37
+ // Get current proven block number
38
+ let initialProvenBlock;
39
+ try {
40
+ const tips = await node.getL2Tips();
41
+ initialProvenBlock = Number(tips.proven.block.number);
42
+ log.info(`Current proven block: ${initialProvenBlock}. Waiting for it to increase...`);
43
+ } catch (err) {
44
+ log.warn(`Error getting initial tips: ${err}. Will poll until successful.`);
45
+ initialProvenBlock = 0;
46
+ }
47
+ await retryUntil(async ()=>{
48
+ try {
49
+ const tips = await node.getL2Tips();
50
+ const currentProvenBlock = Number(tips.proven.block.number);
51
+ const proposedBlock = Number(tips.proposed.number);
52
+ log.verbose(`Chain state: proposed=${proposedBlock}, proven=${currentProvenBlock} (waiting for > ${initialProvenBlock})`);
53
+ if (currentProvenBlock > initialProvenBlock) {
54
+ log.info(`Proven block advanced from ${initialProvenBlock} to ${currentProvenBlock}.`);
55
+ return true;
56
+ }
57
+ return false;
58
+ } catch (err) {
59
+ log.verbose(`Error checking tips: ${err}`);
60
+ return false;
61
+ }
62
+ }, 'proven block to advance', timeoutSeconds, pollIntervalSeconds);
63
+ }
64
+ export async function getSequencers(namespace) {
65
+ const selectors = [
66
+ 'app.kubernetes.io/name=validator',
67
+ 'app.kubernetes.io/component=validator',
68
+ 'app.kubernetes.io/component=sequencer-node',
69
+ 'app=validator'
70
+ ];
71
+ for (const selector of selectors){
72
+ try {
73
+ const command = `kubectl get pods -l ${selector} -n ${namespace} -o jsonpath='{.items[*].metadata.name}'`;
74
+ const { stdout } = await execAsync(command);
75
+ const sequencers = stdout.split(' ').map((s)=>s.trim()).filter(Boolean);
76
+ if (sequencers.length > 0) {
77
+ logger.verbose(`Found sequencer pods ${sequencers.join(', ')} (selector=${selector})`);
78
+ return sequencers;
79
+ }
80
+ } catch {
81
+ // try next selector
82
+ }
83
+ }
84
+ // Fail fast instead of returning [''] which leads to attempts to port-forward `pod/`.
85
+ throw new Error(`No sequencer/validator pods found in namespace ${namespace}. Tried selectors: ${selectors.join(', ')}`);
86
+ }
87
+ export function updateSequencersConfig(env, config) {
88
+ return withSequencersAdmin(env, async (client)=>{
89
+ await client.setConfig(config);
90
+ return client.getConfig();
91
+ });
92
+ }
93
+ export function getSequencersConfig(env) {
94
+ return withSequencersAdmin(env, (client)=>client.getConfig());
95
+ }
96
+ export async function withSequencersAdmin(env, fn) {
97
+ const adminContainerPort = 8880;
98
+ const namespace = env.NAMESPACE;
99
+ const sequencers = await getSequencers(namespace);
100
+ const results = [];
101
+ for (const sequencer of sequencers){
102
+ // Ensure pod is Ready before attempting port-forward.
103
+ await waitForResourceByName({
104
+ resource: 'pods',
105
+ name: sequencer,
106
+ namespace
107
+ });
108
+ // Wrap port-forward + fetch in a retry to handle flaky port-forwards
109
+ const result = await retry(async ()=>{
110
+ const { process: process1, port } = await startPortForward({
111
+ resource: `pod/${sequencer}`,
112
+ namespace,
113
+ containerPort: adminContainerPort
114
+ });
115
+ try {
116
+ const url = `http://localhost:${port}`;
117
+ // Quick health check before using the connection
118
+ const statusRes = await fetch(`${url}/status`);
119
+ if (statusRes.status !== 200) {
120
+ throw new Error(`Admin endpoint returned status ${statusRes.status}`);
121
+ }
122
+ const client = createAztecNodeAdminClient(url);
123
+ return {
124
+ result: await fn(client),
125
+ process: process1
126
+ };
127
+ } catch (err) {
128
+ // Kill the port-forward before retrying
129
+ process1.kill();
130
+ throw err;
131
+ }
132
+ }, 'connect to node admin', makeBackoff([
133
+ 1,
134
+ 2,
135
+ 4,
136
+ 8
137
+ ]), logger, true);
138
+ results.push(result.result);
139
+ result.process.kill();
140
+ }
141
+ return results;
142
+ }
143
+ async function getAztecImageForMigrations(namespace) {
144
+ const aztecDockerImage = process.env.AZTEC_DOCKER_IMAGE;
145
+ if (aztecDockerImage) {
146
+ return aztecDockerImage;
147
+ }
148
+ const { stdout } = await execAsync(`kubectl get pods -l app.kubernetes.io/name=validator -n ${namespace} -o jsonpath='{.items[0].spec.containers[?(@.name=="aztec")].image}' | cat`);
149
+ const image = stdout.trim().replace(/^'|'$/g, '');
150
+ if (!image) {
151
+ throw new Error(`Could not detect aztec image from validator pod in namespace ${namespace}`);
152
+ }
153
+ return image;
154
+ }
155
+ async function getHaDbConnectionUrl(namespace) {
156
+ const secretName = `${namespace}-validator-ha-db-postgres`;
157
+ const { stdout } = await execAsync(`kubectl get secret ${secretName} -n ${namespace} -o json`);
158
+ const secret = JSON.parse(stdout);
159
+ const data = secret?.data ?? {};
160
+ const decode = (value)=>value ? Buffer.from(value, 'base64').toString('utf8') : '';
161
+ const user = decode(data.POSTGRES_USER);
162
+ const password = decode(data.POSTGRES_PASSWORD);
163
+ const database = decode(data.POSTGRES_DB);
164
+ if (!user || !password || !database) {
165
+ throw new Error(`Missing HA DB credentials in secret ${secretName}`);
166
+ }
167
+ const host = `${namespace}-validator-ha-db-postgres.${namespace}.svc.cluster.local`;
168
+ return `postgresql://${encodeURIComponent(user)}:${encodeURIComponent(password)}@${host}:5432/${database}`;
169
+ }
170
+ export async function initHADb(namespace) {
171
+ const databaseUrl = await getHaDbConnectionUrl(namespace);
172
+ const image = await getAztecImageForMigrations(namespace);
173
+ const jobName = `${namespace}-validator-ha-db-migrate`;
174
+ await execAsync(`kubectl delete pod ${jobName} -n ${namespace} --ignore-not-found=true`).catch(()=>undefined);
175
+ const migrateCmd = [
176
+ `kubectl run ${jobName} -n ${namespace}`,
177
+ '--rm -i',
178
+ '--restart=Never',
179
+ `--image=${image}`,
180
+ `--env=DATABASE_URL=${databaseUrl}`,
181
+ '--command -- node --no-warnings /usr/src/yarn-project/aztec/dest/bin/index.js migrate-ha-db up'
182
+ ].join(' ');
183
+ const migrateCmdForLog = migrateCmd.replace(/--env=DATABASE_URL=\S+/, '--env=DATABASE_URL=<redacted>');
184
+ await retry(async ()=>{
185
+ logger.info(`command: ${migrateCmdForLog}`);
186
+ await execAsync(migrateCmd);
187
+ }, 'run HA DB migrations', makeBackoff([
188
+ 1,
189
+ 2,
190
+ 4,
191
+ 8,
192
+ 16
193
+ ]), logger, true);
194
+ }
195
+ /**
196
+ * Sets probabilistic transaction dropping on validators and waits for rollout.
197
+ * Use probability=0 to disable. Wired to env var P2P_DROP_TX_CHANCE via Helm values.
198
+ */ export async function setValidatorTxDrop({ namespace, probability, logger: log }) {
199
+ const prob = String(probability);
200
+ const selectors = [
201
+ 'app.kubernetes.io/name=validator',
202
+ 'app.kubernetes.io/component=validator',
203
+ 'app=validator'
204
+ ];
205
+ let updated = false;
206
+ for (const selector of selectors){
207
+ try {
208
+ const list = await execAsync(`kubectl get statefulset -l ${selector} -n ${namespace} --no-headers -o name | cat`);
209
+ const names = list.stdout.split('\n').map((s)=>s.trim()).filter(Boolean);
210
+ if (names.length === 0) {
211
+ continue;
212
+ }
213
+ const cmd = `kubectl set env statefulset -l ${selector} -n ${namespace} P2P_DROP_TX_CHANCE=${prob}`;
214
+ log.info(`command: ${cmd}`);
215
+ await execAsync(cmd);
216
+ updated = true;
217
+ } catch (e) {
218
+ log.warn(`Failed to update validators with selector ${selector}: ${String(e)}`);
219
+ }
220
+ }
221
+ if (!updated) {
222
+ log.warn(`No validator StatefulSets found in ${namespace}. Skipping tx drop toggle.`);
223
+ return;
224
+ }
225
+ // Restart validator pods to ensure env vars take effect and wait for readiness
226
+ await restartValidators(namespace, log);
227
+ }
228
+ export async function restartValidators(namespace, log) {
229
+ const selectors = [
230
+ 'app.kubernetes.io/name=validator',
231
+ 'app.kubernetes.io/component=validator',
232
+ 'app=validator'
233
+ ];
234
+ let any = false;
235
+ for (const selector of selectors){
236
+ try {
237
+ const { stdout } = await execAsync(`kubectl get pods -l ${selector} -n ${namespace} --no-headers -o name | cat`);
238
+ if (!stdout || stdout.trim().length === 0) {
239
+ continue;
240
+ }
241
+ any = true;
242
+ await deleteResourceByLabel({
243
+ resource: 'pods',
244
+ namespace,
245
+ label: selector
246
+ });
247
+ } catch (e) {
248
+ log.warn(`Error restarting validator pods with selector ${selector}: ${String(e)}`);
249
+ }
250
+ }
251
+ if (!any) {
252
+ log.warn(`No validator pods found to restart in ${namespace}.`);
253
+ return;
254
+ }
255
+ // Wait for either label to be Ready
256
+ for (const selector of selectors){
257
+ try {
258
+ await waitForResourceByLabel({
259
+ resource: 'pods',
260
+ namespace,
261
+ label: selector
262
+ });
263
+ return;
264
+ } catch {
265
+ // try next
266
+ }
267
+ }
268
+ log.warn(`Validator pods did not report Ready; continuing.`);
269
+ }
270
+ export async function enableValidatorDynamicBootNode(instanceName, namespace, spartanDir, log) {
271
+ log.info(`Enabling validator dynamic boot node`);
272
+ await execHelmCommand({
273
+ instanceName,
274
+ namespace,
275
+ helmChartDir: getChartDir(spartanDir, 'aztec-network'),
276
+ values: {
277
+ 'validator.dynamicBootNode': 'true'
278
+ },
279
+ valuesFile: undefined,
280
+ timeout: '15m',
281
+ reuseValues: true
282
+ });
283
+ log.info(`Validator dynamic boot node enabled`);
284
+ }
285
+ /**
286
+ * Rolls the Aztec pods in the given namespace.
287
+ * @param namespace - The namespace to roll the Aztec pods in.
288
+ * @param clearState - If true, also deletes the underlying PVCs to clear persistent storage.
289
+ * This is required for rollup upgrades where the old state is incompatible with the new rollup.
290
+ * Defaults to false, which preserves the existing storage.
291
+ */ export async function rollAztecPods(namespace, clearState = false) {
292
+ // Pod components use 'validator', but StatefulSets and PVCs use 'sequencer-node' for validators
293
+ const podComponents = [
294
+ 'p2p-bootstrap',
295
+ 'prover-node',
296
+ 'prover-broker',
297
+ 'prover-agent',
298
+ 'sequencer-node',
299
+ 'rpc',
300
+ 'validator-ha-db'
301
+ ];
302
+ const pvcComponents = [
303
+ 'p2p-bootstrap',
304
+ 'prover-node',
305
+ 'prover-broker',
306
+ 'sequencer-node',
307
+ 'rpc',
308
+ 'validator-ha-db'
309
+ ];
310
+ // StatefulSet components that need to be scaled down before PVC deletion
311
+ // Note: validators use 'sequencer-node' as component label, not 'validator'
312
+ const statefulSetComponents = [
313
+ 'p2p-bootstrap',
314
+ 'prover-node',
315
+ 'prover-broker',
316
+ 'sequencer-node',
317
+ 'rpc',
318
+ 'validator-ha-db'
319
+ ];
320
+ if (clearState) {
321
+ // To delete PVCs, we must first scale down StatefulSets so pods release the volumes
322
+ // Otherwise PVC deletion will hang waiting for pods to terminate
323
+ // Save original replica counts for all StatefulSets
324
+ const originalReplicas = new Map();
325
+ for (const component of statefulSetComponents){
326
+ try {
327
+ // Get all StatefulSets that match the component label
328
+ const getCmd = `kubectl get statefulset -l app.kubernetes.io/component=${component} -n ${namespace} -o json`;
329
+ const { stdout } = await execAsync(getCmd);
330
+ const result = JSON.parse(stdout);
331
+ for (const sts of result.items || []){
332
+ const name = sts.metadata.name;
333
+ const replicas = sts.spec.replicas ?? 1;
334
+ if (replicas > 0) {
335
+ originalReplicas.set(name, replicas);
336
+ logger.debug(`Saved replica count for StatefulSet ${name}: ${replicas}`);
337
+ }
338
+ }
339
+ } catch {
340
+ // Component might not exist, continue
341
+ }
342
+ }
343
+ // Scale down to 0
344
+ for (const component of statefulSetComponents){
345
+ try {
346
+ const scaleCmd = `kubectl scale statefulset -l app.kubernetes.io/component=${component} -n ${namespace} --replicas=0 --timeout=2m`;
347
+ logger.info(`command: ${scaleCmd}`);
348
+ await execAsync(scaleCmd);
349
+ } catch (e) {
350
+ // Component might not exist or might be a Deployment, continue
351
+ logger.verbose(`Scale down ${component} skipped: ${e}`);
352
+ }
353
+ }
354
+ // Wait for all pods to fully terminate before deleting PVCs.
355
+ // terminationGracePeriodSeconds default is 30s.
356
+ logger.info('Waiting for pods to fully terminate before deleting PVCs...');
357
+ for (const component of statefulSetComponents){
358
+ try {
359
+ // Wait for all pods with this component label to be deleted
360
+ const waitCmd = `kubectl wait pods -l app.kubernetes.io/component=${component} --for=delete -n ${namespace} --timeout=2m`;
361
+ logger.info(`command: ${waitCmd}`);
362
+ await execAsync(waitCmd);
363
+ } catch (e) {
364
+ logger.verbose(`Wait for pod deletion ${component} skipped: ${e}`);
365
+ }
366
+ }
367
+ // Extra buffer to ensure PVC protection finalizers are cleared
368
+ await sleep(5 * 1000);
369
+ // Now delete PVCs (they should no longer be in use)
370
+ for (const component of pvcComponents){
371
+ try {
372
+ await deleteResourceByLabel({
373
+ resource: 'persistentvolumeclaims',
374
+ namespace: namespace,
375
+ label: `app.kubernetes.io/component=${component}`
376
+ });
377
+ } catch (e) {
378
+ logger.warn(`Failed to delete PVCs for ${component}: ${e}`);
379
+ }
380
+ }
381
+ // Verify PVCs are deleted
382
+ for (const component of pvcComponents){
383
+ try {
384
+ const waitCmd = `kubectl wait pvc -l app.kubernetes.io/component=${component} --for=delete -n ${namespace} --timeout=2m`;
385
+ logger.info(`command: ${waitCmd}`);
386
+ await execAsync(waitCmd);
387
+ } catch (e) {
388
+ logger.verbose(`Wait for PVC deletion ${component} skipped: ${e}`);
389
+ }
390
+ }
391
+ const haDbStatefulSets = [
392
+ ...originalReplicas.entries()
393
+ ].filter(([name])=>name.includes('validator-ha-db'));
394
+ const otherStatefulSets = [
395
+ ...originalReplicas.entries()
396
+ ].filter(([name])=>!name.includes('validator-ha-db'));
397
+ // Bring up HA DB first so we can run migrations before validators start
398
+ for (const [stsName, replicas] of haDbStatefulSets){
399
+ try {
400
+ const scaleCmd = `kubectl scale statefulset ${stsName} -n ${namespace} --replicas=${replicas} --timeout=2m`;
401
+ logger.info(`command: ${scaleCmd}`);
402
+ await execAsync(scaleCmd);
403
+ } catch (e) {
404
+ logger.verbose(`Scale up ${stsName} skipped: ${e}`);
405
+ }
406
+ }
407
+ if (haDbStatefulSets.length > 0) {
408
+ try {
409
+ await waitForStatefulSetsReady({
410
+ namespace,
411
+ label: 'app.kubernetes.io/component=validator-ha-db',
412
+ timeoutSeconds: 600
413
+ });
414
+ await initHADb(namespace);
415
+ } catch (e) {
416
+ logger.warn(`HA DB migration step skipped or failed: ${e}`);
417
+ }
418
+ }
419
+ // Scale remaining StatefulSets back up to original replica counts (by name, not label)
420
+ for (const [stsName, replicas] of otherStatefulSets){
421
+ try {
422
+ const scaleCmd = `kubectl scale statefulset ${stsName} -n ${namespace} --replicas=${replicas} --timeout=2m`;
423
+ logger.info(`command: ${scaleCmd}`);
424
+ await execAsync(scaleCmd);
425
+ } catch (e) {
426
+ logger.verbose(`Scale up ${stsName} skipped: ${e}`);
427
+ }
428
+ }
429
+ } else {
430
+ // Just delete pods (no state clearing)
431
+ for (const component of podComponents){
432
+ await deleteResourceByLabel({
433
+ resource: 'pods',
434
+ namespace: namespace,
435
+ label: `app.kubernetes.io/component=${component}`
436
+ });
437
+ }
438
+ }
439
+ await sleep(10 * 1000);
440
+ // Wait for StatefulSets to have all replicas ready.
441
+ for (const component of statefulSetComponents){
442
+ try {
443
+ await waitForStatefulSetsReady({
444
+ namespace,
445
+ label: `app.kubernetes.io/component=${component}`,
446
+ timeoutSeconds: 600
447
+ });
448
+ } catch (e) {
449
+ logger.warn(`StatefulSet component ${component} may not be fully ready: ${e}`);
450
+ }
451
+ }
452
+ const nonStatefulSetComponents = podComponents.filter((c)=>!statefulSetComponents.includes(c));
453
+ for (const component of nonStatefulSetComponents){
454
+ await waitForResourceByLabel({
455
+ resource: 'pods',
456
+ namespace: namespace,
457
+ label: `app.kubernetes.io/component=${component}`
458
+ });
459
+ }
460
+ }
@@ -0,0 +1,30 @@
1
+ import type { Logger } from '@aztec/foundation/log';
2
+ /** Result from running a script */
3
+ export type ScriptResult = {
4
+ exitCode: number;
5
+ stdout: string;
6
+ stderr: string;
7
+ };
8
+ /**
9
+ * Returns the absolute path to the git repository root
10
+ */
11
+ export declare function getGitProjectRoot(): string;
12
+ export declare function getAztecBin(): string;
13
+ /**
14
+ * Runs the Aztec binary
15
+ * @param args - The arguments to pass to the Aztec binary
16
+ * @param logger - The logger to use
17
+ * @param env - Optional environment variables to set for the process
18
+ * @returns The exit code, stdout, and stderr of the Aztec binary
19
+ */
20
+ export declare function runAztecBin(args: string[], logger: Logger, env?: Record<string, string>): Promise<ScriptResult>;
21
+ /**
22
+ * Runs a script from the project root
23
+ * @param script - The path to the script, relative to the project root
24
+ * @param args - The arguments to pass to the script
25
+ * @param logger - The logger to use
26
+ * @param env - Optional environment variables to set for the process
27
+ * @returns The exit code, stdout, and stderr of the script
28
+ */
29
+ export declare function runProjectScript(script: string, args: string[], logger: Logger, env?: Record<string, string>): Promise<ScriptResult>;
30
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2NyaXB0cy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3NwYXJ0YW4vdXRpbHMvc2NyaXB0cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUtwRCxtQ0FBbUM7QUFDbkMsTUFBTSxNQUFNLFlBQVksR0FBRztJQUN6QixRQUFRLEVBQUUsTUFBTSxDQUFDO0lBQ2pCLE1BQU0sRUFBRSxNQUFNLENBQUM7SUFDZixNQUFNLEVBQUUsTUFBTSxDQUFDO0NBQ2hCLENBQUM7QUF5Q0Y7O0dBRUc7QUFDSCx3QkFBZ0IsaUJBQWlCLElBQUksTUFBTSxDQVcxQztBQUVELHdCQUFnQixXQUFXLFdBRTFCO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsd0JBQWdCLFdBQVcsQ0FBQyxJQUFJLEVBQUUsTUFBTSxFQUFFLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxHQUFHLENBQUMsRUFBRSxNQUFNLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxHQUFHLE9BQU8sQ0FBQyxZQUFZLENBQUMsQ0FFL0c7QUFFRDs7Ozs7OztHQU9HO0FBQ0gsd0JBQWdCLGdCQUFnQixDQUM5QixNQUFNLEVBQUUsTUFBTSxFQUNkLElBQUksRUFBRSxNQUFNLEVBQUUsRUFDZCxNQUFNLEVBQUUsTUFBTSxFQUNkLEdBQUcsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLEdBQzNCLE9BQU8sQ0FBQyxZQUFZLENBQUMsQ0FHdkIifQ==
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scripts.d.ts","sourceRoot":"","sources":["../../../src/spartan/utils/scripts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAKpD,mCAAmC;AACnC,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAyCF;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAW1C;AAED,wBAAgB,WAAW,WAE1B;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAE/G;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,EAAE,MAAM,EACd,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC3B,OAAO,CAAC,YAAY,CAAC,CAGvB"}
@@ -0,0 +1,81 @@
1
+ import { execSync, spawn } from 'child_process';
2
+ import path from 'path';
3
+ /**
4
+ * @param scriptPath - The path to the script, relative to the project root
5
+ * @param args - The arguments to pass to the script
6
+ * @param logger - The logger to use
7
+ * @returns The exit code, stdout, and stderr of the script
8
+ */ function runScript(scriptPath, args, logger, env) {
9
+ const childProcess = spawn(scriptPath, args, {
10
+ stdio: [
11
+ 'ignore',
12
+ 'pipe',
13
+ 'pipe'
14
+ ],
15
+ env: env ? {
16
+ ...process.env,
17
+ ...env
18
+ } : process.env
19
+ });
20
+ const stdoutChunks = [];
21
+ const stderrChunks = [];
22
+ return new Promise((resolve, reject)=>{
23
+ childProcess.on('close', (code)=>resolve({
24
+ exitCode: code ?? 0,
25
+ stdout: Buffer.concat(stdoutChunks).toString(),
26
+ stderr: Buffer.concat(stderrChunks).toString()
27
+ }));
28
+ childProcess.on('error', reject);
29
+ childProcess.stdout?.on('data', (data)=>{
30
+ stdoutChunks.push(data);
31
+ logger.info(data.toString());
32
+ });
33
+ childProcess.stderr?.on('data', (data)=>{
34
+ stderrChunks.push(data);
35
+ logger.error(data.toString());
36
+ });
37
+ });
38
+ }
39
+ /**
40
+ * Returns the absolute path to the git repository root
41
+ */ export function getGitProjectRoot() {
42
+ try {
43
+ const rootDir = execSync('git rev-parse --show-toplevel', {
44
+ encoding: 'utf-8',
45
+ stdio: [
46
+ 'ignore',
47
+ 'pipe',
48
+ 'ignore'
49
+ ]
50
+ }).trim();
51
+ return rootDir;
52
+ } catch (error) {
53
+ throw new Error(`Failed to determine git project root: ${error}`);
54
+ }
55
+ }
56
+ export function getAztecBin() {
57
+ return path.join(getGitProjectRoot(), 'yarn-project/aztec/dest/bin/index.js');
58
+ }
59
+ /**
60
+ * Runs the Aztec binary
61
+ * @param args - The arguments to pass to the Aztec binary
62
+ * @param logger - The logger to use
63
+ * @param env - Optional environment variables to set for the process
64
+ * @returns The exit code, stdout, and stderr of the Aztec binary
65
+ */ export function runAztecBin(args, logger, env) {
66
+ return runScript('node', [
67
+ getAztecBin(),
68
+ ...args
69
+ ], logger, env);
70
+ }
71
+ /**
72
+ * Runs a script from the project root
73
+ * @param script - The path to the script, relative to the project root
74
+ * @param args - The arguments to pass to the script
75
+ * @param logger - The logger to use
76
+ * @param env - Optional environment variables to set for the process
77
+ * @returns The exit code, stdout, and stderr of the script
78
+ */ export function runProjectScript(script, args, logger, env) {
79
+ const scriptPath = script.startsWith('/') ? script : path.join(getGitProjectRoot(), script);
80
+ return runScript(scriptPath, args, logger, env);
81
+ }