@aztec/end-to-end 0.0.1-commit.e6bd8901 → 0.0.1-commit.ec7ac5448

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 (202) hide show
  1. package/README.md +27 -0
  2. package/dest/bench/client_flows/client_flows_benchmark.d.ts +2 -2
  3. package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -1
  4. package/dest/bench/client_flows/client_flows_benchmark.js +22 -29
  5. package/dest/bench/client_flows/config.d.ts +2 -2
  6. package/dest/bench/client_flows/config.d.ts.map +1 -1
  7. package/dest/bench/client_flows/config.js +18 -0
  8. package/dest/bench/utils.d.ts +1 -1
  9. package/dest/bench/utils.d.ts.map +1 -1
  10. package/dest/bench/utils.js +6 -3
  11. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +6 -3
  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 +23 -13
  14. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts +2 -2
  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 +3 -2
  17. package/dest/e2e_deploy_contract/deploy_test.d.ts +2 -2
  18. package/dest/e2e_deploy_contract/deploy_test.d.ts.map +1 -1
  19. package/dest/e2e_epochs/epochs_test.d.ts +17 -7
  20. package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
  21. package/dest/e2e_epochs/epochs_test.js +91 -44
  22. package/dest/e2e_fees/fees_test.d.ts +2 -2
  23. package/dest/e2e_fees/fees_test.d.ts.map +1 -1
  24. package/dest/e2e_fees/fees_test.js +19 -12
  25. package/dest/e2e_l1_publisher/write_json.d.ts +3 -2
  26. package/dest/e2e_l1_publisher/write_json.d.ts.map +1 -1
  27. package/dest/e2e_l1_publisher/write_json.js +1 -7
  28. package/dest/e2e_nested_contract/nested_contract_test.d.ts +1 -1
  29. package/dest/e2e_nested_contract/nested_contract_test.d.ts.map +1 -1
  30. package/dest/e2e_nested_contract/nested_contract_test.js +4 -6
  31. package/dest/e2e_p2p/inactivity_slash_test.js +3 -3
  32. package/dest/e2e_p2p/p2p_network.d.ts +9 -10
  33. package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
  34. package/dest/e2e_p2p/p2p_network.js +38 -20
  35. package/dest/e2e_p2p/reqresp/utils.d.ts +22 -0
  36. package/dest/e2e_p2p/reqresp/utils.d.ts.map +1 -0
  37. package/dest/e2e_p2p/reqresp/utils.js +190 -0
  38. package/dest/e2e_p2p/shared.d.ts +26 -8
  39. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  40. package/dest/e2e_p2p/shared.js +56 -47
  41. package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.d.ts +2 -0
  42. package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.d.ts.map +1 -0
  43. package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.js +184 -0
  44. package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.d.ts +18 -0
  45. package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.d.ts.map +1 -0
  46. package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.js +120 -0
  47. package/dest/e2e_token_contract/token_contract_test.d.ts +4 -2
  48. package/dest/e2e_token_contract/token_contract_test.d.ts.map +1 -1
  49. package/dest/e2e_token_contract/token_contract_test.js +19 -9
  50. package/dest/fixtures/authwit_proxy.d.ts +15 -0
  51. package/dest/fixtures/authwit_proxy.d.ts.map +1 -0
  52. package/dest/fixtures/authwit_proxy.js +34 -0
  53. package/dest/fixtures/e2e_prover_test.d.ts +7 -6
  54. package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
  55. package/dest/fixtures/e2e_prover_test.js +38 -50
  56. package/dest/fixtures/elu_monitor.d.ts +21 -0
  57. package/dest/fixtures/elu_monitor.d.ts.map +1 -0
  58. package/dest/fixtures/elu_monitor.js +102 -0
  59. package/dest/fixtures/fixtures.d.ts +5 -1
  60. package/dest/fixtures/fixtures.d.ts.map +1 -1
  61. package/dest/fixtures/fixtures.js +6 -0
  62. package/dest/fixtures/get_bb_config.d.ts +1 -1
  63. package/dest/fixtures/get_bb_config.d.ts.map +1 -1
  64. package/dest/fixtures/get_bb_config.js +5 -5
  65. package/dest/fixtures/ha_setup.d.ts +71 -0
  66. package/dest/fixtures/ha_setup.d.ts.map +1 -0
  67. package/dest/fixtures/ha_setup.js +116 -0
  68. package/dest/fixtures/index.d.ts +2 -1
  69. package/dest/fixtures/index.d.ts.map +1 -1
  70. package/dest/fixtures/index.js +1 -0
  71. package/dest/fixtures/setup.d.ts +55 -31
  72. package/dest/fixtures/setup.d.ts.map +1 -1
  73. package/dest/fixtures/setup.js +97 -176
  74. package/dest/fixtures/setup_p2p_test.d.ts +18 -11
  75. package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
  76. package/dest/fixtures/setup_p2p_test.js +43 -32
  77. package/dest/fixtures/token_utils.d.ts +2 -2
  78. package/dest/fixtures/token_utils.d.ts.map +1 -1
  79. package/dest/fixtures/token_utils.js +5 -7
  80. package/dest/legacy-jest-resolver.d.cts +3 -0
  81. package/dest/legacy-jest-resolver.d.cts.map +1 -0
  82. package/dest/shared/cross_chain_test_harness.d.ts +1 -1
  83. package/dest/shared/cross_chain_test_harness.d.ts.map +1 -1
  84. package/dest/shared/cross_chain_test_harness.js +13 -13
  85. package/dest/shared/gas_portal_test_harness.js +2 -2
  86. package/dest/shared/index.d.ts +2 -1
  87. package/dest/shared/index.d.ts.map +1 -1
  88. package/dest/shared/index.js +1 -0
  89. package/dest/shared/jest_setup.js +41 -1
  90. package/dest/shared/mock_state_view.d.ts +86 -0
  91. package/dest/shared/mock_state_view.d.ts.map +1 -0
  92. package/dest/shared/mock_state_view.js +186 -0
  93. package/dest/shared/submit-transactions.d.ts +2 -2
  94. package/dest/shared/submit-transactions.d.ts.map +1 -1
  95. package/dest/shared/submit-transactions.js +1 -1
  96. package/dest/shared/uniswap_l1_l2.d.ts +1 -1
  97. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  98. package/dest/shared/uniswap_l1_l2.js +16 -17
  99. package/dest/simulators/lending_simulator.d.ts +1 -1
  100. package/dest/simulators/lending_simulator.d.ts.map +1 -1
  101. package/dest/simulators/lending_simulator.js +4 -4
  102. package/dest/simulators/token_simulator.d.ts +1 -1
  103. package/dest/simulators/token_simulator.d.ts.map +1 -1
  104. package/dest/simulators/token_simulator.js +3 -24
  105. package/dest/spartan/setup_test_wallets.d.ts +12 -3
  106. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  107. package/dest/spartan/setup_test_wallets.js +100 -39
  108. package/dest/spartan/tx_metrics.d.ts +35 -1
  109. package/dest/spartan/tx_metrics.d.ts.map +1 -1
  110. package/dest/spartan/tx_metrics.js +151 -1
  111. package/dest/spartan/utils/bot.d.ts +3 -2
  112. package/dest/spartan/utils/bot.d.ts.map +1 -1
  113. package/dest/spartan/utils/bot.js +2 -1
  114. package/dest/spartan/utils/config.d.ts +10 -1
  115. package/dest/spartan/utils/config.d.ts.map +1 -1
  116. package/dest/spartan/utils/config.js +4 -1
  117. package/dest/spartan/utils/index.d.ts +6 -4
  118. package/dest/spartan/utils/index.d.ts.map +1 -1
  119. package/dest/spartan/utils/index.js +6 -2
  120. package/dest/spartan/utils/k8s.d.ts +31 -1
  121. package/dest/spartan/utils/k8s.d.ts.map +1 -1
  122. package/dest/spartan/utils/k8s.js +124 -0
  123. package/dest/spartan/utils/nodes.d.ts +14 -5
  124. package/dest/spartan/utils/nodes.d.ts.map +1 -1
  125. package/dest/spartan/utils/nodes.js +204 -33
  126. package/dest/spartan/utils/pod_logs.d.ts +25 -0
  127. package/dest/spartan/utils/pod_logs.d.ts.map +1 -0
  128. package/dest/spartan/utils/pod_logs.js +74 -0
  129. package/dest/spartan/utils/scripts.d.ts +18 -4
  130. package/dest/spartan/utils/scripts.d.ts.map +1 -1
  131. package/dest/spartan/utils/scripts.js +19 -4
  132. package/dest/test-wallet/test_wallet.d.ts +84 -0
  133. package/dest/test-wallet/test_wallet.d.ts.map +1 -0
  134. package/dest/test-wallet/test_wallet.js +249 -0
  135. package/dest/test-wallet/utils.d.ts +41 -0
  136. package/dest/test-wallet/utils.d.ts.map +1 -0
  137. package/dest/test-wallet/utils.js +71 -0
  138. package/dest/test-wallet/wallet_worker_script.d.ts +2 -0
  139. package/dest/test-wallet/wallet_worker_script.d.ts.map +1 -0
  140. package/dest/test-wallet/wallet_worker_script.js +48 -0
  141. package/dest/test-wallet/worker_wallet.d.ts +52 -0
  142. package/dest/test-wallet/worker_wallet.d.ts.map +1 -0
  143. package/dest/test-wallet/worker_wallet.js +151 -0
  144. package/dest/test-wallet/worker_wallet_schema.d.ts +274 -0
  145. package/dest/test-wallet/worker_wallet_schema.d.ts.map +1 -0
  146. package/dest/test-wallet/worker_wallet_schema.js +10 -0
  147. package/package.json +46 -43
  148. package/src/bench/client_flows/client_flows_benchmark.ts +31 -18
  149. package/src/bench/client_flows/config.ts +9 -1
  150. package/src/bench/utils.ts +8 -3
  151. package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +31 -21
  152. package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +7 -8
  153. package/src/e2e_deploy_contract/deploy_test.ts +3 -3
  154. package/src/e2e_epochs/epochs_test.ts +115 -72
  155. package/src/e2e_fees/bridging_race.notest.ts +1 -1
  156. package/src/e2e_fees/fees_test.ts +21 -29
  157. package/src/e2e_l1_publisher/write_json.ts +1 -6
  158. package/src/e2e_nested_contract/nested_contract_test.ts +7 -5
  159. package/src/e2e_p2p/inactivity_slash_test.ts +7 -7
  160. package/src/e2e_p2p/p2p_network.ts +58 -37
  161. package/src/e2e_p2p/reqresp/utils.ts +256 -0
  162. package/src/e2e_p2p/shared.ts +84 -62
  163. package/src/e2e_storage_proof/fixtures/storage_proof.json +915 -0
  164. package/src/e2e_storage_proof/fixtures/storage_proof_fetcher.ts +190 -0
  165. package/src/e2e_storage_proof/fixtures/storage_proof_fixture.ts +173 -0
  166. package/src/e2e_token_contract/token_contract_test.ts +26 -9
  167. package/src/fixtures/authwit_proxy.ts +54 -0
  168. package/src/fixtures/dumps/epoch_proof_result.json +1 -1
  169. package/src/fixtures/e2e_prover_test.ts +47 -56
  170. package/src/fixtures/elu_monitor.ts +126 -0
  171. package/src/fixtures/fixtures.ts +10 -0
  172. package/src/fixtures/get_bb_config.ts +7 -6
  173. package/src/fixtures/ha_setup.ts +186 -0
  174. package/src/fixtures/index.ts +1 -0
  175. package/src/fixtures/setup.ts +132 -239
  176. package/src/fixtures/setup_p2p_test.ts +48 -52
  177. package/src/fixtures/token_utils.ts +3 -3
  178. package/src/guides/up_quick_start.sh +3 -3
  179. package/src/legacy-jest-resolver.cjs +135 -0
  180. package/src/shared/cross_chain_test_harness.ts +13 -9
  181. package/src/shared/gas_portal_test_harness.ts +1 -1
  182. package/src/shared/index.ts +1 -0
  183. package/src/shared/jest_setup.ts +51 -1
  184. package/src/shared/mock_state_view.ts +188 -0
  185. package/src/shared/submit-transactions.ts +3 -2
  186. package/src/shared/uniswap_l1_l2.ts +38 -33
  187. package/src/simulators/lending_simulator.ts +8 -4
  188. package/src/simulators/token_simulator.ts +6 -30
  189. package/src/spartan/setup_test_wallets.ts +141 -32
  190. package/src/spartan/tx_metrics.ts +127 -1
  191. package/src/spartan/utils/bot.ts +4 -1
  192. package/src/spartan/utils/config.ts +3 -0
  193. package/src/spartan/utils/index.ts +10 -1
  194. package/src/spartan/utils/k8s.ts +160 -0
  195. package/src/spartan/utils/nodes.ts +251 -31
  196. package/src/spartan/utils/pod_logs.ts +99 -0
  197. package/src/spartan/utils/scripts.ts +43 -7
  198. package/src/test-wallet/test_wallet.ts +351 -0
  199. package/src/test-wallet/utils.ts +112 -0
  200. package/src/test-wallet/wallet_worker_script.ts +60 -0
  201. package/src/test-wallet/worker_wallet.ts +214 -0
  202. package/src/test-wallet/worker_wallet_schema.ts +13 -0
@@ -4,14 +4,12 @@
4
4
  import { type AztecNodeConfig, AztecNodeService } from '@aztec/aztec-node';
5
5
  import { range } from '@aztec/foundation/array';
6
6
  import { SecretValue } from '@aztec/foundation/config';
7
- import { addLogNameHandler, removeLogNameHandler } from '@aztec/foundation/log';
7
+ import { withLoggerBindings } from '@aztec/foundation/log/server';
8
8
  import { bufferToHex } from '@aztec/foundation/string';
9
9
  import type { DateProvider } from '@aztec/foundation/timer';
10
- import type { ProverNodeConfig, ProverNodeDeps } from '@aztec/prover-node';
11
- import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
10
+ import type { GenesisData } from '@aztec/stdlib/world-state';
12
11
 
13
12
  import getPort from 'get-port';
14
- import { AsyncLocalStorage } from 'node:async_hooks';
15
13
 
16
14
  import { TEST_PEER_CHECK_INTERVAL_MS } from './fixtures.js';
17
15
  import { createAndSyncProverNode, getPrivateKeyFromIndex } from './utils.js';
@@ -22,6 +20,11 @@ import { getEndToEndTestTelemetryClient } from './with_telemetry_utils.js';
22
20
  // to avoid running validators with the same key
23
21
  export const ATTESTER_PRIVATE_KEYS_START_INDEX = 3;
24
22
 
23
+ // Global counters for actor naming (start at 1)
24
+ let validatorCounter = 1;
25
+ let nodeCounter = 1;
26
+ let proverCounter = 1;
27
+
25
28
  export function generatePrivateKeys(startIndex: number, numberOfKeys: number): `0x${string}`[] {
26
29
  const privateKeys: `0x${string}`[] = [];
27
30
  // Do not start from 0 as it is used during setup
@@ -37,17 +40,13 @@ export async function createNodes(
37
40
  bootstrapNodeEnr: string,
38
41
  numNodes: number,
39
42
  bootNodePort: number,
40
- prefilledPublicData?: PublicDataTreeLeaf[],
43
+ genesis?: GenesisData,
41
44
  dataDirectory?: string,
42
45
  metricsPort?: number,
43
46
  indexOffset = 0,
44
47
  validatorsPerNode = 1,
45
48
  ): Promise<AztecNodeService[]> {
46
49
  const nodePromises: Promise<AztecNodeService>[] = [];
47
- const loggerIdStorage = new AsyncLocalStorage<string>();
48
- const logNameHandler = (module: string) =>
49
- loggerIdStorage.getStore() ? `${module}:${loggerIdStorage.getStore()}` : module;
50
- addLogNameHandler(logNameHandler);
51
50
 
52
51
  for (let i = 0; i < numNodes; i++) {
53
52
  const index = indexOffset + i;
@@ -66,10 +65,9 @@ export async function createNodes(
66
65
  port,
67
66
  bootstrapNodeEnr,
68
67
  validatorIndices,
69
- prefilledPublicData,
68
+ genesis,
70
69
  dataDir,
71
70
  metricsPort,
72
- loggerIdStorage,
73
71
  );
74
72
  nodePromises.push(nodePromise);
75
73
  }
@@ -81,32 +79,38 @@ export async function createNodes(
81
79
  throw new Error('Sequencer not found');
82
80
  }
83
81
 
84
- removeLogNameHandler(logNameHandler);
85
82
  return nodes;
86
83
  }
87
84
 
88
- /** Creates a P2P enabled instance of Aztec Node Service with a validator */
85
+ /** Extended config type for createNode with test-specific overrides. */
86
+ export type CreateNodeConfig = AztecNodeConfig & {
87
+ /** Whether to skip starting the sequencer. */
88
+ dontStartSequencer?: boolean;
89
+ /** Override the private key (instead of deriving from addressIndex). */
90
+ validatorPrivateKey?: `0x${string}`;
91
+ };
92
+
93
+ /** Creates a P2P enabled instance of Aztec Node Service with a validator. */
89
94
  export async function createNode(
90
- config: AztecNodeConfig & { dontStartSequencer?: boolean },
95
+ config: CreateNodeConfig,
91
96
  dateProvider: DateProvider,
92
97
  tcpPort: number,
93
98
  bootstrapNode: string | undefined,
94
99
  addressIndex: number | number[],
95
- prefilledPublicData?: PublicDataTreeLeaf[],
100
+ genesis?: GenesisData,
96
101
  dataDirectory?: string,
97
102
  metricsPort?: number,
98
- loggerIdStorage?: AsyncLocalStorage<string>,
99
103
  ) {
100
- const createNode = async () => {
104
+ const actorIndex = validatorCounter++;
105
+ return await withLoggerBindings({ actor: `validator-${actorIndex}` }, async () => {
101
106
  const validatorConfig = await createValidatorConfig(config, bootstrapNode, tcpPort, addressIndex, dataDirectory);
102
107
  const telemetry = await getEndToEndTestTelemetryClient(metricsPort);
103
108
  return await AztecNodeService.createAndSync(
104
109
  validatorConfig,
105
110
  { telemetry, dateProvider },
106
- { prefilledPublicData, dontStartSequencer: config.dontStartSequencer },
111
+ { genesis, dontStartSequencer: config.dontStartSequencer },
107
112
  );
108
- };
109
- return loggerIdStorage ? await loggerIdStorage.run(tcpPort.toString(), createNode) : createNode();
113
+ });
110
114
  }
111
115
 
112
116
  /** Creates a P2P enabled instance of Aztec Node Service without a validator */
@@ -115,23 +119,22 @@ export async function createNonValidatorNode(
115
119
  dateProvider: DateProvider,
116
120
  tcpPort: number,
117
121
  bootstrapNode: string | undefined,
118
- prefilledPublicData?: PublicDataTreeLeaf[],
122
+ genesis?: GenesisData,
119
123
  dataDirectory?: string,
120
124
  metricsPort?: number,
121
- loggerIdStorage?: AsyncLocalStorage<string>,
122
125
  ) {
123
- const createNode = async () => {
126
+ const actorIndex = nodeCounter++;
127
+ return await withLoggerBindings({ actor: `node-${actorIndex}` }, async () => {
124
128
  const p2pConfig = await createP2PConfig(baseConfig, bootstrapNode, tcpPort, dataDirectory);
125
129
  const config: AztecNodeConfig = {
126
130
  ...p2pConfig,
127
131
  disableValidator: true,
128
132
  validatorPrivateKeys: undefined,
129
- publisherPrivateKeys: [],
133
+ sequencerPublisherPrivateKeys: [],
130
134
  };
131
135
  const telemetry = await getEndToEndTestTelemetryClient(metricsPort);
132
- return await AztecNodeService.createAndSync(config, { telemetry, dateProvider }, { prefilledPublicData });
133
- };
134
- return loggerIdStorage ? await loggerIdStorage.run(tcpPort.toString(), createNode) : createNode();
136
+ return await AztecNodeService.createAndSync(config, { telemetry, dateProvider }, { genesis });
137
+ });
135
138
  }
136
139
 
137
140
  export async function createProverNode(
@@ -139,34 +142,26 @@ export async function createProverNode(
139
142
  tcpPort: number,
140
143
  bootstrapNode: string | undefined,
141
144
  addressIndex: number,
142
- proverNodeDeps: ProverNodeDeps & Required<Pick<ProverNodeDeps, 'dateProvider'>>,
143
- prefilledPublicData?: PublicDataTreeLeaf[],
145
+ deps: { dateProvider: DateProvider },
146
+ genesis?: GenesisData,
144
147
  dataDirectory?: string,
145
148
  metricsPort?: number,
146
- loggerIdStorage?: AsyncLocalStorage<string>,
147
- ) {
148
- const createProverNode = async () => {
149
+ ): Promise<{ proverNode: AztecNodeService }> {
150
+ const actorIndex = proverCounter++;
151
+ return await withLoggerBindings({ actor: `prover-${actorIndex}` }, async () => {
149
152
  const proverNodePrivateKey = getPrivateKeyFromIndex(ATTESTER_PRIVATE_KEYS_START_INDEX + addressIndex)!;
150
153
  const telemetry = await getEndToEndTestTelemetryClient(metricsPort);
151
154
 
152
- const proverConfig: Partial<ProverNodeConfig> = await createP2PConfig(
153
- config,
154
- bootstrapNode,
155
- tcpPort,
156
- dataDirectory,
157
- );
155
+ const p2pConfig = await createP2PConfig(config, bootstrapNode, tcpPort, dataDirectory);
158
156
 
159
- const aztecNodeRpcTxProvider = undefined;
160
157
  return await createAndSyncProverNode(
161
158
  bufferToHex(proverNodePrivateKey),
162
- config,
163
- { ...proverConfig, dataDirectory },
164
- aztecNodeRpcTxProvider,
165
- prefilledPublicData,
166
- { ...proverNodeDeps, telemetry },
159
+ { ...config, ...p2pConfig },
160
+ { dataDirectory },
161
+ { ...deps, telemetry },
162
+ { genesis },
167
163
  );
168
- };
169
- return loggerIdStorage ? await loggerIdStorage.run(tcpPort.toString(), createProverNode) : createProverNode();
164
+ });
170
165
  }
171
166
 
172
167
  export async function createP2PConfig(
@@ -192,26 +187,27 @@ export async function createP2PConfig(
192
187
  }
193
188
 
194
189
  export async function createValidatorConfig(
195
- config: AztecNodeConfig,
190
+ config: CreateNodeConfig,
196
191
  bootstrapNodeEnr?: string,
197
192
  port?: number,
198
193
  addressIndex: number | number[] = 1,
199
194
  dataDirectory?: string,
200
195
  ) {
201
196
  const addressIndices = Array.isArray(addressIndex) ? addressIndex : [addressIndex];
202
- if (addressIndices.length === 0) {
197
+ if (addressIndices.length === 0 && !config.validatorPrivateKey) {
203
198
  throw new Error('At least one address index must be provided to create a validator config');
204
199
  }
205
200
 
206
- const attesterPrivateKeys = addressIndices.map(index =>
207
- bufferToHex(getPrivateKeyFromIndex(ATTESTER_PRIVATE_KEYS_START_INDEX + index)!),
208
- );
201
+ // Use override private key if provided, otherwise derive from address indices
202
+ const attesterPrivateKeys = config.validatorPrivateKey
203
+ ? [config.validatorPrivateKey]
204
+ : addressIndices.map(index => bufferToHex(getPrivateKeyFromIndex(ATTESTER_PRIVATE_KEYS_START_INDEX + index)!));
209
205
  const p2pConfig = await createP2PConfig(config, bootstrapNodeEnr, port, dataDirectory);
210
206
  const nodeConfig: AztecNodeConfig = {
211
207
  ...config,
212
208
  ...p2pConfig,
213
209
  validatorPrivateKeys: new SecretValue(attesterPrivateKeys),
214
- publisherPrivateKeys: [new SecretValue(attesterPrivateKeys[0])],
210
+ sequencerPublisherPrivateKeys: [new SecretValue(attesterPrivateKeys[0])],
215
211
  };
216
212
 
217
213
  return nodeConfig;
@@ -8,7 +8,6 @@ export async function deployToken(wallet: Wallet, admin: AztecAddress, initialAd
8
8
  logger.info(`Deploying Token contract...`);
9
9
  const { contract, instance } = await TokenContract.deploy(wallet, admin, 'TokenName', 'TokenSymbol', 18).send({
10
10
  from: admin,
11
- wait: { returnReceipt: true },
12
11
  });
13
12
 
14
13
  if (initialAdminBalance > 0n) {
@@ -25,8 +24,9 @@ export async function mintTokensToPrivate(
25
24
  minter: AztecAddress,
26
25
  recipient: AztecAddress,
27
26
  amount: bigint,
27
+ additionalScopes?: AztecAddress[],
28
28
  ) {
29
- await token.methods.mint_to_private(recipient, amount).send({ from: minter });
29
+ await token.methods.mint_to_private(recipient, amount).send({ from: minter, additionalScopes });
30
30
  }
31
31
 
32
32
  export async function expectTokenBalance(
@@ -38,7 +38,7 @@ export async function expectTokenBalance(
38
38
  ) {
39
39
  // Then check the balance
40
40
  const contractWithWallet = TokenContract.at(token.address, wallet);
41
- const balance = await contractWithWallet.methods.balance_of_private(owner).simulate({ from: owner });
41
+ const { result: balance } = await contractWithWallet.methods.balance_of_private(owner).simulate({ from: owner });
42
42
  logger.info(`Account ${owner} balance: ${balance}`);
43
43
  expect(balance).toBe(expectedBalance);
44
44
  }
@@ -23,6 +23,8 @@ aztec-wallet create-account -a alice -f test0
23
23
  aztec-wallet create-account -a bob -f test0
24
24
  # docs:end:declare-accounts
25
25
 
26
+ aztec-wallet bridge-fee-juice 1000000000000000000000 accounts:alice --mint --no-wait
27
+
26
28
  DEPLOY_OUTPUT=$(aztec-wallet deploy ../noir-contracts.js/artifacts/token_contract-Token.json --args accounts:test0 Test TST 18 -f test0)
27
29
  TOKEN_ADDRESS=$(echo "$DEPLOY_OUTPUT" | grep -oE 'Contract deployed at 0x[0-9a-fA-F]+' | cut -d ' ' -f4)
28
30
  echo "Deployed contract at $TOKEN_ADDRESS"
@@ -38,9 +40,7 @@ fi
38
40
 
39
41
  TRANSFER_AMOUNT=42
40
42
 
41
- aztec-wallet create-authwit transfer_in_private accounts:test0 -ca last --args accounts:alice accounts:bob $TRANSFER_AMOUNT 1 -f alice
42
-
43
- aztec-wallet send transfer_in_private -ca last --args accounts:alice accounts:bob $TRANSFER_AMOUNT 1 -aw authwits:last -f test0
43
+ aztec-wallet send transfer_in_private -ca last --args accounts:alice accounts:bob $TRANSFER_AMOUNT 0 -f alice --payment method=fee_juice,claim
44
44
 
45
45
  # Test end result
46
46
  ALICE_BALANCE=$(aztec-wallet simulate balance_of_private -ca last --args accounts:alice -f alice)
@@ -0,0 +1,135 @@
1
+ // Custom Jest resolver. When CONTRACT_ARTIFACTS_VERSION is set, redirects *only* JSON artifact files under
2
+ // @aztec/noir-contracts.js/artifacts/ and @aztec/noir-test-contracts.js/artifacts/ to a local cache of the pinned
3
+ // legacy versions. TypeScript wrapper classes (e.g. Token.ts) continue to load from the current workspace and use the
4
+ // current @aztec/aztec.js — only the artifact JSON (the deployed-contract ABI / bytecode / notes surface) is swapped.
5
+ //
6
+ // Why JSON-only: the JSON artifact is the actual interchange surface a "deployed contract" exposes. The TS wrapper is
7
+ // generated client-side ergonomics that's tightly coupled to the current @aztec/aztec.js API. Redirecting the wrapper
8
+ // would couple this test to a moving aztec.js surface and break at import time on unrelated breaking changes; we want
9
+ // to fail only on actual artifact-compat regressions.
10
+ //
11
+ // The cache is populated on demand by running `npm install` into .legacy-contracts/<version>/.
12
+ //
13
+ // Activated by env var; passthrough otherwise.
14
+ /* eslint-disable @typescript-eslint/no-require-imports */
15
+
16
+ const path = require('path');
17
+ const fs = require('fs');
18
+ const { execSync } = require('child_process');
19
+
20
+ const version = process.env.CONTRACT_ARTIFACTS_VERSION;
21
+ const REDIRECTED = ['@aztec/noir-contracts.js', '@aztec/noir-test-contracts.js'];
22
+
23
+ // Jest sets rootDir to <e2e>/src; this file lives there too.
24
+ const e2eRoot = path.resolve(__dirname, '..');
25
+ const cacheRoot = version ? path.join(e2eRoot, '.legacy-contracts', version) : null;
26
+
27
+ function pkgJsonPath(name) {
28
+ return path.join(cacheRoot, 'node_modules', name, 'package.json');
29
+ }
30
+
31
+ function ensureCache() {
32
+ const missing = REDIRECTED.some(p => !fs.existsSync(pkgJsonPath(p)));
33
+ if (!missing) {
34
+ return;
35
+ }
36
+ fs.mkdirSync(cacheRoot, { recursive: true });
37
+ // Seed a standalone package.json so `npm install --prefix` treats cacheRoot as its own project. Without this, npm
38
+ // walks up and finds the yarn-project workspace root, which breaks on `workspace:` protocol deps and risks
39
+ // clobbering the monorepo's node_modules.
40
+ const seed = path.join(cacheRoot, 'package.json');
41
+ if (!fs.existsSync(seed)) {
42
+ fs.writeFileSync(seed, JSON.stringify({ name: 'legacy-contracts-cache', private: true }));
43
+ }
44
+
45
+ const specs = REDIRECTED.map(p => `${p}@${version}`).join(' ');
46
+ process.stderr.write(`[legacy-contracts] installing ${specs} into ${cacheRoot}\n`);
47
+ // --prefix: install into cacheRoot instead of cwd, so the cache is isolated from the monorepo.
48
+ // --no-save: don't write the installed packages back to the seeded package.json.
49
+ // --ignore-scripts: skip lifecycle scripts (preinstall/postinstall) of the legacy packages and their transitive
50
+ // deps; we only want the files on disk, not to run any build steps.
51
+ // --legacy-peer-deps: tolerate peer-dependency mismatches between the pinned legacy @aztec/* graph and whatever
52
+ // current versions npm would otherwise try to reconcile.
53
+ execSync(`npm install --prefix "${cacheRoot}" --no-save --ignore-scripts --legacy-peer-deps ${specs}`, {
54
+ stdio: 'inherit',
55
+ });
56
+
57
+ // Verify versions on disk match the requested version.
58
+ for (const p of REDIRECTED) {
59
+ const onDisk = JSON.parse(fs.readFileSync(pkgJsonPath(p), 'utf8')).version;
60
+ if (onDisk !== version) {
61
+ throw new Error(`[legacy-contracts] ${p} on disk is ${onDisk}, expected ${version}`);
62
+ }
63
+ }
64
+ }
65
+
66
+ if (version) {
67
+ ensureCache();
68
+ }
69
+
70
+ let bannerPrinted = false;
71
+ const seen = new Set();
72
+
73
+ function printBannerOnce() {
74
+ if (bannerPrinted || !version) {
75
+ return;
76
+ }
77
+ bannerPrinted = true;
78
+ const lines = ['='.repeat(60), `[legacy-contracts][jest] CONTRACT_ARTIFACTS_VERSION=${version}`];
79
+ for (const p of REDIRECTED) {
80
+ const v = JSON.parse(fs.readFileSync(pkgJsonPath(p), 'utf8')).version;
81
+ if (v !== version) {
82
+ throw new Error(`[legacy-contracts] ${p} on disk is ${v}, expected ${version}`);
83
+ }
84
+ lines.push(`[legacy-contracts][jest] redirecting ${p}/artifacts/*.json -> .legacy-contracts/${version}/...`);
85
+ }
86
+ lines.push('='.repeat(60));
87
+ process.stderr.write(lines.join('\n') + '\n');
88
+ }
89
+
90
+ // Match a resolved absolute path against the workspace artifacts dirs and return the legacy cache equivalent, or null
91
+ // if it's not an artifact path we should redirect.
92
+ function legacyArtifactPath(resolved) {
93
+ if (!resolved.endsWith('.json')) {
94
+ return null;
95
+ }
96
+ for (const pkg of REDIRECTED) {
97
+ // pkg = '@aztec/noir-contracts.js' -> match '/noir-contracts.js/artifacts/'
98
+ const dirName = pkg.split('/')[1];
99
+ const marker = `/${dirName}/artifacts/`;
100
+ const idx = resolved.indexOf(marker);
101
+ if (idx === -1) {
102
+ continue;
103
+ }
104
+ const basename = resolved.slice(idx + marker.length);
105
+ return path.join(cacheRoot, 'node_modules', pkg, 'artifacts', basename);
106
+ }
107
+ return null;
108
+ }
109
+
110
+ module.exports = function legacyResolver(request, options) {
111
+ // Always run the default resolver first. We only inspect (and possibly rewrite) the *result*; this catches both
112
+ // bare-specifier imports of `@aztec/noir-contracts.js/artifacts/foo.json` and the relative `../artifacts/foo.json`
113
+ // imports inside the workspace TS wrapper classes — both resolve to the same workspace artifact path that we then
114
+ // redirect.
115
+ const resolved = options.defaultResolver(request, options);
116
+ if (!version) {
117
+ return resolved;
118
+ }
119
+ printBannerOnce();
120
+ const legacy = legacyArtifactPath(resolved);
121
+ if (!legacy) {
122
+ return resolved;
123
+ }
124
+ if (!fs.existsSync(legacy)) {
125
+ throw new Error(
126
+ `[legacy-contracts] artifact ${path.basename(legacy)} not present in legacy cache @${version}; ` +
127
+ `the contract may have been added after that release. Pin a newer CONTRACT_ARTIFACTS_VERSION or skip this test.`,
128
+ );
129
+ }
130
+ if (!seen.has(resolved)) {
131
+ seen.add(resolved);
132
+ process.stderr.write(`[legacy-contracts][jest] redirected ${path.basename(legacy)} -> ${legacy}\n`);
133
+ }
134
+ return legacy;
135
+ };
@@ -73,22 +73,26 @@ export async function deployAndInitializeTokenAndBridgeContracts(
73
73
  });
74
74
 
75
75
  // deploy l2 token
76
- const token = await TokenContract.deploy(wallet, owner, 'TokenName', 'TokenSymbol', 18).send({ from: owner });
76
+ const { contract: token } = await TokenContract.deploy(wallet, owner, 'TokenName', 'TokenSymbol', 18).send({
77
+ from: owner,
78
+ });
77
79
 
78
80
  // deploy l2 token bridge and attach to the portal
79
- const bridge = await TokenBridgeContract.deploy(wallet, token.address, tokenPortalAddress).send({ from: owner });
81
+ const { contract: bridge } = await TokenBridgeContract.deploy(wallet, token.address, tokenPortalAddress).send({
82
+ from: owner,
83
+ });
80
84
 
81
- if ((await token.methods.get_admin().simulate({ from: owner })) !== owner.toBigInt()) {
85
+ if ((await token.methods.get_admin().simulate({ from: owner })).result !== owner.toBigInt()) {
82
86
  throw new Error(`Token admin is not ${owner}`);
83
87
  }
84
88
 
85
- if (!(await bridge.methods.get_config().simulate({ from: owner })).token.equals(token.address)) {
89
+ if (!(await bridge.methods.get_config().simulate({ from: owner })).result.token.equals(token.address)) {
86
90
  throw new Error(`Bridge token is not ${token.address}`);
87
91
  }
88
92
 
89
93
  // make the bridge a minter on the token:
90
94
  await token.methods.set_minter(bridge.address, true).send({ from: owner });
91
- if ((await token.methods.is_minter(bridge.address).simulate({ from: owner })) === 1n) {
95
+ if ((await token.methods.is_minter(bridge.address).simulate({ from: owner })).result === 1n) {
92
96
  throw new Error(`Bridge is not a minter`);
93
97
  }
94
98
 
@@ -269,7 +273,7 @@ export class CrossChainTestHarness {
269
273
  authwitNonce: Fr = Fr.ZERO,
270
274
  authWitness: AuthWitness,
271
275
  ): Promise<TxReceipt> {
272
- const withdrawReceipt = await this.l2Bridge.methods
276
+ const { receipt: withdrawReceipt } = await this.l2Bridge.methods
273
277
  .exit_to_l1_private(this.l2Token.address, this.ethAccount, withdrawAmount, EthAddress.ZERO, authwitNonce)
274
278
  .send({ authWitnesses: [authWitness], from: this.ownerAddress });
275
279
 
@@ -277,7 +281,7 @@ export class CrossChainTestHarness {
277
281
  }
278
282
 
279
283
  async withdrawPublicFromAztecToL1(withdrawAmount: bigint, authwitNonce: Fr = Fr.ZERO): Promise<TxReceipt> {
280
- const withdrawReceipt = await this.l2Bridge.methods
284
+ const { receipt: withdrawReceipt } = await this.l2Bridge.methods
281
285
  .exit_to_l1_public(this.ethAccount, withdrawAmount, EthAddress.ZERO, authwitNonce)
282
286
  .send({ from: this.ownerAddress });
283
287
 
@@ -285,7 +289,7 @@ export class CrossChainTestHarness {
285
289
  }
286
290
 
287
291
  async getL2PrivateBalanceOf(owner: AztecAddress) {
288
- return await this.l2Token.methods.balance_of_private(owner).simulate({ from: owner });
292
+ return (await this.l2Token.methods.balance_of_private(owner).simulate({ from: owner })).result;
289
293
  }
290
294
 
291
295
  async expectPrivateBalanceOnL2(owner: AztecAddress, expectedBalance: bigint) {
@@ -295,7 +299,7 @@ export class CrossChainTestHarness {
295
299
  }
296
300
 
297
301
  async getL2PublicBalanceOf(owner: AztecAddress) {
298
- return await this.l2Token.methods.balance_of_public(owner).simulate({ from: this.ownerAddress });
302
+ return (await this.l2Token.methods.balance_of_public(owner).simulate({ from: this.ownerAddress })).result;
299
303
  }
300
304
 
301
305
  async expectPublicBalanceOnL2(owner: AztecAddress, expectedBalance: bigint) {
@@ -131,7 +131,7 @@ export class GasBridgingTestHarness implements IGasBridgingTestHarness {
131
131
  }
132
132
 
133
133
  async getL2PublicBalanceOf(owner: AztecAddress) {
134
- return await this.feeJuice.methods.balance_of_public(owner).simulate({ from: owner });
134
+ return (await this.feeJuice.methods.balance_of_public(owner).simulate({ from: owner })).result;
135
135
  }
136
136
 
137
137
  async expectPublicBalanceOnL2(owner: AztecAddress, expectedBalance: bigint) {
@@ -1 +1,2 @@
1
1
  export { uniswapL1L2TestSuite } from './uniswap_l1_l2.js';
2
+ export { MockStateView, diffInBps } from './mock_state_view.js';
@@ -1,8 +1,19 @@
1
1
  import { createLogger } from '@aztec/aztec.js/log';
2
2
 
3
- import { beforeEach, expect } from '@jest/globals';
3
+ import { afterAll, afterEach, beforeEach, expect } from '@jest/globals';
4
+ import { readlinkSync } from 'fs';
4
5
  import { basename } from 'path';
5
6
 
7
+ import { EluMonitor } from '../fixtures/elu_monitor.js';
8
+
9
+ const eluMonitor = process.env.ELU_MONITOR_FILE
10
+ ? new EluMonitor(process.env.ELU_MONITOR_FILE, Number(process.env.ELU_MONITOR_INTERVAL_MS) || undefined)
11
+ : undefined;
12
+
13
+ if (eluMonitor) {
14
+ process.on('exit', () => eluMonitor.stop());
15
+ }
16
+
6
17
  beforeEach(() => {
7
18
  const { testPath, currentTestName } = expect.getState();
8
19
  if (!testPath || !currentTestName) {
@@ -10,4 +21,43 @@ beforeEach(() => {
10
21
  }
11
22
  const logger = createLogger(`e2e:${basename(testPath).replace('.test.ts', '')}`);
12
23
  logger.info(`Running test: ${currentTestName}`);
24
+ eluMonitor?.startTest(currentTestName);
25
+ });
26
+
27
+ afterEach(() => {
28
+ eluMonitor?.stopTest();
29
+ });
30
+
31
+ // Log leaked handles after all tests complete. This runs after test-level afterAll hooks,
32
+ // so any handles still alive at this point were not properly cleaned up during teardown.
33
+ // This diagnostic helps identify the source of exit hangs without masking them.
34
+ afterAll(() => {
35
+ const handles = (process as any)._getActiveHandles();
36
+ if (handles.length > 0) {
37
+ const details = handles.map((h: any) => {
38
+ const type = h?.constructor?.name ?? typeof h;
39
+ const fd = h?.fd ?? h?._handle?.fd ?? '?';
40
+ const destroyed = h?.destroyed ?? '?';
41
+ const hasRef = typeof h?.hasRef === 'function' ? h.hasRef() : '?';
42
+ const localAddr = h?.localAddress ?? '';
43
+ const remoteAddr = h?.remoteAddress ?? '';
44
+ const localPort = h?.localPort ?? '';
45
+ const remotePort = h?.remotePort ?? '';
46
+ const proto = Object.getPrototypeOf(h)?.constructor?.name ?? '?';
47
+ const keys = Object.keys(h).slice(0, 10).join(',');
48
+ let fdTarget = '';
49
+ if (typeof fd === 'number') {
50
+ try {
51
+ fdTarget = ` -> ${readlinkSync(`/proc/self/fd/${fd}`)}`;
52
+ } catch {
53
+ // ignore
54
+ }
55
+ }
56
+ return ` ${type}(fd=${fd}, destroyed=${destroyed}, hasRef=${hasRef}${fdTarget}) proto=${proto} addr=${localAddr}:${localPort}->${remoteAddr}:${remotePort} keys=[${keys}]`;
57
+ });
58
+ process.stderr.write(
59
+ `\n[jest_setup] WARNING: ${handles.length} handle(s) still active after teardown:\n${details.join('\n')}\n` +
60
+ `These may prevent Jest from exiting. Investigate and fix the leak.\n\n`,
61
+ );
62
+ }
13
63
  });