@aztec/end-to-end 0.0.1-commit.e3c1de76 → 0.0.1-commit.e57c76e

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 (230) hide show
  1. package/README.md +27 -0
  2. package/dest/bench/client_flows/benchmark.d.ts +15 -1
  3. package/dest/bench/client_flows/benchmark.d.ts.map +1 -1
  4. package/dest/bench/client_flows/benchmark.js +17 -0
  5. package/dest/bench/client_flows/client_flows_benchmark.d.ts +3 -3
  6. package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -1
  7. package/dest/bench/client_flows/client_flows_benchmark.js +36 -39
  8. package/dest/bench/client_flows/config.d.ts +2 -2
  9. package/dest/bench/client_flows/config.d.ts.map +1 -1
  10. package/dest/bench/client_flows/config.js +18 -0
  11. package/dest/bench/utils.d.ts +1 -1
  12. package/dest/bench/utils.d.ts.map +1 -1
  13. package/dest/bench/utils.js +8 -3
  14. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +8 -5
  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 +36 -17
  17. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts +16 -5
  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 +42 -9
  20. package/dest/e2e_deploy_contract/deploy_test.d.ts +4 -4
  21. package/dest/e2e_deploy_contract/deploy_test.d.ts.map +1 -1
  22. package/dest/e2e_deploy_contract/deploy_test.js +2 -1
  23. package/dest/e2e_epochs/epochs_test.d.ts +33 -8
  24. package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
  25. package/dest/e2e_epochs/epochs_test.js +143 -44
  26. package/dest/e2e_fees/fees_test.d.ts +6 -3
  27. package/dest/e2e_fees/fees_test.d.ts.map +1 -1
  28. package/dest/e2e_fees/fees_test.js +50 -17
  29. package/dest/e2e_nested_contract/nested_contract_test.d.ts +3 -3
  30. package/dest/e2e_nested_contract/nested_contract_test.d.ts.map +1 -1
  31. package/dest/e2e_nested_contract/nested_contract_test.js +6 -7
  32. package/dest/e2e_p2p/inactivity_slash_test.d.ts +1 -1
  33. package/dest/e2e_p2p/inactivity_slash_test.d.ts.map +1 -1
  34. package/dest/e2e_p2p/inactivity_slash_test.js +4 -3
  35. package/dest/e2e_p2p/p2p_network.d.ts +14 -12
  36. package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
  37. package/dest/e2e_p2p/p2p_network.js +70 -34
  38. package/dest/e2e_p2p/reqresp/utils.d.ts +3 -3
  39. package/dest/e2e_p2p/reqresp/utils.d.ts.map +1 -1
  40. package/dest/e2e_p2p/reqresp/utils.js +67 -14
  41. package/dest/e2e_p2p/shared.d.ts +37 -8
  42. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  43. package/dest/e2e_p2p/shared.js +91 -51
  44. package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.d.ts +2 -0
  45. package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.d.ts.map +1 -0
  46. package/dest/e2e_storage_proof/fixtures/storage_proof_fetcher.js +184 -0
  47. package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.d.ts +18 -0
  48. package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.d.ts.map +1 -0
  49. package/dest/e2e_storage_proof/fixtures/storage_proof_fixture.js +120 -0
  50. package/dest/e2e_token_contract/token_contract_test.d.ts +6 -4
  51. package/dest/e2e_token_contract/token_contract_test.d.ts.map +1 -1
  52. package/dest/e2e_token_contract/token_contract_test.js +23 -11
  53. package/dest/fixtures/authwit_proxy.d.ts +15 -0
  54. package/dest/fixtures/authwit_proxy.d.ts.map +1 -0
  55. package/dest/fixtures/authwit_proxy.js +34 -0
  56. package/dest/fixtures/e2e_prover_test.d.ts +9 -8
  57. package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
  58. package/dest/fixtures/e2e_prover_test.js +39 -50
  59. package/dest/fixtures/elu_monitor.d.ts +21 -0
  60. package/dest/fixtures/elu_monitor.d.ts.map +1 -0
  61. package/dest/fixtures/elu_monitor.js +102 -0
  62. package/dest/fixtures/fixtures.d.ts +74 -1
  63. package/dest/fixtures/fixtures.d.ts.map +1 -1
  64. package/dest/fixtures/fixtures.js +71 -0
  65. package/dest/fixtures/get_bb_config.d.ts +1 -1
  66. package/dest/fixtures/get_bb_config.d.ts.map +1 -1
  67. package/dest/fixtures/get_bb_config.js +5 -5
  68. package/dest/fixtures/ha_setup.d.ts +71 -0
  69. package/dest/fixtures/ha_setup.d.ts.map +1 -0
  70. package/dest/fixtures/ha_setup.js +116 -0
  71. package/dest/fixtures/index.d.ts +2 -1
  72. package/dest/fixtures/index.d.ts.map +1 -1
  73. package/dest/fixtures/index.js +1 -0
  74. package/dest/fixtures/schnorr_hardcoded_account_contract.d.ts +25 -0
  75. package/dest/fixtures/schnorr_hardcoded_account_contract.d.ts.map +1 -0
  76. package/dest/fixtures/schnorr_hardcoded_account_contract.js +37 -0
  77. package/dest/fixtures/setup.d.ts +86 -32
  78. package/dest/fixtures/setup.d.ts.map +1 -1
  79. package/dest/fixtures/setup.js +209 -169
  80. package/dest/fixtures/setup_p2p_test.d.ts +22 -10
  81. package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
  82. package/dest/fixtures/setup_p2p_test.js +23 -17
  83. package/dest/fixtures/token_utils.d.ts +2 -2
  84. package/dest/fixtures/token_utils.d.ts.map +1 -1
  85. package/dest/fixtures/token_utils.js +5 -7
  86. package/dest/fixtures/utils.d.ts +2 -2
  87. package/dest/fixtures/utils.d.ts.map +1 -1
  88. package/dest/fixtures/utils.js +1 -1
  89. package/dest/forward-compatibility/wallet_rpc_client.d.ts +7 -0
  90. package/dest/forward-compatibility/wallet_rpc_client.d.ts.map +1 -0
  91. package/dest/forward-compatibility/wallet_rpc_client.js +15 -0
  92. package/dest/forward-compatibility/wallet_service.d.ts +3 -0
  93. package/dest/forward-compatibility/wallet_service.d.ts.map +1 -0
  94. package/dest/forward-compatibility/wallet_service.js +109 -0
  95. package/dest/install_legacy_contracts.d.cts +10 -0
  96. package/dest/install_legacy_contracts.d.cts.map +1 -0
  97. package/dest/legacy-jest-resolver.d.cts +3 -0
  98. package/dest/legacy-jest-resolver.d.cts.map +1 -0
  99. package/dest/shared/cross_chain_test_harness.d.ts +4 -2
  100. package/dest/shared/cross_chain_test_harness.d.ts.map +1 -1
  101. package/dest/shared/cross_chain_test_harness.js +22 -18
  102. package/dest/shared/gas_portal_test_harness.d.ts +8 -5
  103. package/dest/shared/gas_portal_test_harness.d.ts.map +1 -1
  104. package/dest/shared/gas_portal_test_harness.js +19 -10
  105. package/dest/shared/index.d.ts +2 -1
  106. package/dest/shared/index.d.ts.map +1 -1
  107. package/dest/shared/index.js +1 -0
  108. package/dest/shared/jest_setup.js +41 -1
  109. package/dest/shared/mock_state_view.d.ts +86 -0
  110. package/dest/shared/mock_state_view.d.ts.map +1 -0
  111. package/dest/shared/mock_state_view.js +186 -0
  112. package/dest/shared/submit-transactions.d.ts +2 -2
  113. package/dest/shared/submit-transactions.d.ts.map +1 -1
  114. package/dest/shared/submit-transactions.js +1 -1
  115. package/dest/shared/uniswap_l1_l2.d.ts +1 -1
  116. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  117. package/dest/shared/uniswap_l1_l2.js +57 -40
  118. package/dest/shared/wait_for_l1_to_l2_message.d.ts +13 -0
  119. package/dest/shared/wait_for_l1_to_l2_message.d.ts.map +1 -0
  120. package/dest/shared/wait_for_l1_to_l2_message.js +10 -0
  121. package/dest/simulators/lending_simulator.d.ts +10 -3
  122. package/dest/simulators/lending_simulator.d.ts.map +1 -1
  123. package/dest/simulators/lending_simulator.js +26 -14
  124. package/dest/simulators/token_simulator.d.ts +1 -1
  125. package/dest/simulators/token_simulator.d.ts.map +1 -1
  126. package/dest/simulators/token_simulator.js +3 -24
  127. package/dest/spartan/setup_test_wallets.d.ts +12 -3
  128. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  129. package/dest/spartan/setup_test_wallets.js +108 -41
  130. package/dest/spartan/tx_metrics.d.ts +18 -4
  131. package/dest/spartan/tx_metrics.d.ts.map +1 -1
  132. package/dest/spartan/tx_metrics.js +74 -21
  133. package/dest/spartan/utils/bot.d.ts +3 -2
  134. package/dest/spartan/utils/bot.d.ts.map +1 -1
  135. package/dest/spartan/utils/bot.js +2 -1
  136. package/dest/spartan/utils/config.d.ts +11 -28
  137. package/dest/spartan/utils/config.d.ts.map +1 -1
  138. package/dest/spartan/utils/config.js +4 -1
  139. package/dest/spartan/utils/index.d.ts +5 -3
  140. package/dest/spartan/utils/index.d.ts.map +1 -1
  141. package/dest/spartan/utils/index.js +5 -1
  142. package/dest/spartan/utils/k8s.d.ts +3 -1
  143. package/dest/spartan/utils/k8s.d.ts.map +1 -1
  144. package/dest/spartan/utils/k8s.js +6 -0
  145. package/dest/spartan/utils/nodes.d.ts +4 -5
  146. package/dest/spartan/utils/nodes.d.ts.map +1 -1
  147. package/dest/spartan/utils/nodes.js +11 -11
  148. package/dest/spartan/utils/pod_logs.d.ts +25 -0
  149. package/dest/spartan/utils/pod_logs.d.ts.map +1 -0
  150. package/dest/spartan/utils/pod_logs.js +74 -0
  151. package/dest/spartan/utils/scripts.d.ts +18 -4
  152. package/dest/spartan/utils/scripts.d.ts.map +1 -1
  153. package/dest/spartan/utils/scripts.js +19 -4
  154. package/dest/test-wallet/test_wallet.d.ts +85 -0
  155. package/dest/test-wallet/test_wallet.d.ts.map +1 -0
  156. package/dest/test-wallet/test_wallet.js +273 -0
  157. package/dest/test-wallet/utils.d.ts +41 -0
  158. package/dest/test-wallet/utils.d.ts.map +1 -0
  159. package/dest/test-wallet/utils.js +66 -0
  160. package/dest/test-wallet/wallet_worker_script.d.ts +2 -0
  161. package/dest/test-wallet/wallet_worker_script.d.ts.map +1 -0
  162. package/dest/test-wallet/wallet_worker_script.js +53 -0
  163. package/dest/test-wallet/worker_wallet.d.ts +53 -0
  164. package/dest/test-wallet/worker_wallet.d.ts.map +1 -0
  165. package/dest/test-wallet/worker_wallet.js +155 -0
  166. package/dest/test-wallet/worker_wallet_schema.d.ts +160 -0
  167. package/dest/test-wallet/worker_wallet_schema.d.ts.map +1 -0
  168. package/dest/test-wallet/worker_wallet_schema.js +22 -0
  169. package/package.json +52 -45
  170. package/src/bench/client_flows/benchmark.ts +19 -0
  171. package/src/bench/client_flows/client_flows_benchmark.ts +64 -49
  172. package/src/bench/client_flows/config.ts +9 -1
  173. package/src/bench/utils.ts +10 -4
  174. package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +52 -25
  175. package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +56 -19
  176. package/src/e2e_deploy_contract/deploy_test.ts +6 -5
  177. package/src/e2e_epochs/epochs_test.ts +166 -68
  178. package/src/e2e_fees/bridging_race.notest.ts +1 -1
  179. package/src/e2e_fees/fees_test.ts +57 -32
  180. package/src/e2e_nested_contract/nested_contract_test.ts +10 -6
  181. package/src/e2e_p2p/inactivity_slash_test.ts +8 -7
  182. package/src/e2e_p2p/p2p_network.ts +93 -49
  183. package/src/e2e_p2p/reqresp/utils.ts +84 -17
  184. package/src/e2e_p2p/shared.ts +109 -65
  185. package/src/e2e_storage_proof/fixtures/storage_proof.json +915 -0
  186. package/src/e2e_storage_proof/fixtures/storage_proof_fetcher.ts +190 -0
  187. package/src/e2e_storage_proof/fixtures/storage_proof_fixture.ts +173 -0
  188. package/src/e2e_token_contract/token_contract_test.ts +38 -11
  189. package/src/fixtures/authwit_proxy.ts +54 -0
  190. package/src/fixtures/dumps/epoch_proof_result.json +1 -1
  191. package/src/fixtures/e2e_prover_test.ts +49 -56
  192. package/src/fixtures/elu_monitor.ts +126 -0
  193. package/src/fixtures/fixtures.ts +93 -0
  194. package/src/fixtures/get_bb_config.ts +7 -6
  195. package/src/fixtures/ha_setup.ts +188 -0
  196. package/src/fixtures/index.ts +1 -0
  197. package/src/fixtures/schnorr_hardcoded_account_contract.ts +49 -0
  198. package/src/fixtures/setup.ts +272 -233
  199. package/src/fixtures/setup_p2p_test.ts +37 -32
  200. package/src/fixtures/token_utils.ts +3 -3
  201. package/src/fixtures/utils.ts +2 -0
  202. package/src/forward-compatibility/wallet_rpc_client.ts +14 -0
  203. package/src/forward-compatibility/wallet_service.ts +104 -0
  204. package/src/guides/up_quick_start.sh +3 -5
  205. package/src/install_legacy_contracts.cjs +75 -0
  206. package/src/legacy-jest-resolver.cjs +112 -0
  207. package/src/shared/cross_chain_test_harness.ts +27 -13
  208. package/src/shared/gas_portal_test_harness.ts +21 -11
  209. package/src/shared/index.ts +1 -0
  210. package/src/shared/jest_setup.ts +51 -1
  211. package/src/shared/mock_state_view.ts +188 -0
  212. package/src/shared/submit-transactions.ts +3 -2
  213. package/src/shared/uniswap_l1_l2.ts +103 -54
  214. package/src/shared/wait_for_l1_to_l2_message.ts +23 -0
  215. package/src/simulators/lending_simulator.ts +32 -14
  216. package/src/simulators/token_simulator.ts +6 -30
  217. package/src/spartan/setup_test_wallets.ts +146 -35
  218. package/src/spartan/tx_metrics.ts +82 -24
  219. package/src/spartan/utils/bot.ts +4 -1
  220. package/src/spartan/utils/config.ts +3 -0
  221. package/src/spartan/utils/index.ts +8 -1
  222. package/src/spartan/utils/k8s.ts +8 -0
  223. package/src/spartan/utils/nodes.ts +17 -12
  224. package/src/spartan/utils/pod_logs.ts +99 -0
  225. package/src/spartan/utils/scripts.ts +43 -7
  226. package/src/test-wallet/test_wallet.ts +376 -0
  227. package/src/test-wallet/utils.ts +108 -0
  228. package/src/test-wallet/wallet_worker_script.ts +63 -0
  229. package/src/test-wallet/worker_wallet.ts +218 -0
  230. package/src/test-wallet/worker_wallet_schema.ts +13 -0
@@ -1,5 +1,88 @@
1
+ import type { AztecNode } from '@aztec/aztec.js/node';
2
+ import type { GasFees } from '@aztec/stdlib/gas';
3
+
1
4
  export const METRICS_PORT = 4318;
2
5
 
6
+ /** Default fee padding applied to predicted min fees in e2e tests. */
7
+ export const DEFAULT_MIN_FEE_PADDING = 5;
8
+
9
+ /**
10
+ * Large fee padding for txs that may be mined significantly later than when they were created,
11
+ * such as cloned txs in throughput/capacity benchmarks, where fees may spike between creation and mining.
12
+ */
13
+ export const LARGE_MIN_FEE_PADDING = 15;
14
+
15
+ /**
16
+ * Fee padding used by tests running under proposer pipelining. Under pipelining the fee-asset
17
+ * price modifier evolves faster across the build/publish gap, so client-set maxFeesPerGas (sized
18
+ * for the default 5x padding) was getting bumped past by the time the tx mined a few slots later.
19
+ * Observed worst case in CI: fee evolved ~20x between PXE snapshot and inclusion, exceeding even
20
+ * LARGE_MIN_FEE_PADDING (15x).
21
+ */
22
+ export const PIPELINED_FEE_PADDING = 30;
23
+
24
+ /**
25
+ * Setup option preset that opts a test into proposer pipelining. Use with `setup()`:
26
+ *
27
+ * await setup(N, { ...PIPELINING_SETUP_OPTS, ...otherOpts });
28
+ *
29
+ * The preset sets:
30
+ * - `inboxLag: 2` so the sequencer sources L1->L2 messages from checkpoint N-1 (already sealed),
31
+ * avoiding `L1ToL2MessagesNotReadyError` when building for slot N during slot N-1.
32
+ * - `minTxsPerBlock: 0` so empty checkpoints land even when a tx arrives late in the build window
33
+ * (otherwise the chain stalls on alternating slots).
34
+ * - `aztecSlotDuration: 12` / `ethereumSlotDuration: 4` so the pipelined cycle fits inside the
35
+ * default 300s Jest hook budget. Tests that depend on the env-default 72s/12s should override.
36
+ * - `walletMinFeePadding: PIPELINED_FEE_PADDING` (30x) to absorb the wider fee evolution window.
37
+ */
38
+ export const PIPELINING_SETUP_OPTS = {
39
+ inboxLag: 2,
40
+ minTxsPerBlock: 0,
41
+ aztecSlotDuration: 12,
42
+ ethereumSlotDuration: 4,
43
+ walletMinFeePadding: PIPELINED_FEE_PADDING,
44
+ } as const;
45
+
46
+ /**
47
+ * Setup option preset that opts a test into the deterministic AutomineSequencer path.
48
+ * Use only for single-sequencer tests that don't exercise block-building or consensus
49
+ * (e.g. e2e_token, e2e_amm, e2e_authwit). Not compatible with `e2e_p2p/*`,
50
+ * `e2e_epochs/*`, `e2e_slashing/*`, `e2e_block_building`, or any multi-validator suite.
51
+ *
52
+ * await setup(N, { ...AUTOMINE_E2E_OPTS, ...otherOpts });
53
+ *
54
+ * The preset:
55
+ * - Swaps the production Sequencer for an AutomineSequencer that builds one block per
56
+ * submitted tx, publishes synchronously to L1, and owns all time control through a
57
+ * serial queue (see `sequencer-client/src/sequencer/automine/automine_sequencer.ts`).
58
+ * - Disables the validator client and AnvilTestWatcher (the AutomineSequencer needs
59
+ * neither).
60
+ * - Uses `inboxLag: 1` (synchronous) since the AutomineSequencer publishes one block per tx.
61
+ * - Switches anvil into automine mode at setup time (no interval mining); each L1 tx
62
+ * mines an L1 block immediately.
63
+ *
64
+ * Requires `aztecTargetCommitteeSize: 0`, which is the e2e default at `setup.ts:317`.
65
+ */
66
+ export const AUTOMINE_E2E_OPTS = {
67
+ useAutomineSequencer: true,
68
+ disableAnvilTestWatcher: true,
69
+ inboxLag: 1,
70
+ minTxsPerBlock: 0,
71
+ aztecSlotDuration: 12,
72
+ ethereumSlotDuration: 4,
73
+ walletMinFeePadding: PIPELINED_FEE_PADDING,
74
+ } as const;
75
+
76
+ /** Returns worst-case predicted min fees with padding applied, mirroring the BaseWallet pattern. */
77
+ export async function getPaddedMaxFeesPerGas(node: AztecNode, padding = DEFAULT_MIN_FEE_PADDING): Promise<GasFees> {
78
+ const predicted = await node.getPredictedMinFees();
79
+ const worstCase =
80
+ predicted.length > 0
81
+ ? predicted.reduce((worst, fees) => (fees.feePerL2Gas > worst.feePerL2Gas ? fees : worst))
82
+ : await node.getCurrentMinFees();
83
+ return worstCase.mul(1 + padding);
84
+ }
85
+
3
86
  export const shouldCollectMetrics = () => {
4
87
  if (process.env.COLLECT_METRICS) {
5
88
  return METRICS_PORT;
@@ -7,6 +90,16 @@ export const shouldCollectMetrics = () => {
7
90
  return undefined;
8
91
  };
9
92
 
93
+ /** Returns the boot node UDP port from environment variable or default value. */
94
+ export function getBootNodeUdpPort(): number {
95
+ return process.env.BOOT_NODE_UDP_PORT ? parseInt(process.env.BOOT_NODE_UDP_PORT, 10) : 4500;
96
+ }
97
+
98
+ /** Returns the anvil port from environment variable or default value. */
99
+ export function getAnvilPort(): number {
100
+ return process.env.ANVIL_PORT ? parseInt(process.env.ANVIL_PORT, 10) : 8545;
101
+ }
102
+
10
103
  export const TEST_PEER_CHECK_INTERVAL_MS = 1000;
11
104
  export const TEST_MAX_PENDING_TX_POOL_COUNT = 10_000; // Number of max pending TXs ~ 1.56GB
12
105
 
@@ -13,8 +13,10 @@ const {
13
13
  BB_SKIP_CLEANUP = '',
14
14
  TEMP_DIR = tmpdir(),
15
15
  BB_WORKING_DIRECTORY = '',
16
- BB_NUM_IVC_VERIFIERS = '1',
16
+ BB_NUM_IVC_VERIFIERS = '8',
17
17
  BB_IVC_CONCURRENCY = '1',
18
+ BB_CHONK_VERIFY_MAX_BATCH = '16',
19
+ BB_CHONK_VERIFY_BATCH_CONCURRENCY = '6',
18
20
  } = process.env;
19
21
 
20
22
  export const getBBConfig = async (
@@ -41,16 +43,15 @@ export const getBBConfig = async (
41
43
  const bbSkipCleanup = ['1', 'true'].includes(BB_SKIP_CLEANUP);
42
44
  const cleanup = bbSkipCleanup ? () => Promise.resolve() : () => tryRmDir(directoryToCleanup);
43
45
 
44
- const numIvcVerifiers = Number(BB_NUM_IVC_VERIFIERS);
45
- const ivcConcurrency = Number(BB_IVC_CONCURRENCY);
46
-
47
46
  return {
48
47
  bbSkipCleanup,
49
48
  bbBinaryPath,
50
49
  bbWorkingDirectory,
51
50
  cleanup,
52
- numConcurrentIVCVerifiers: numIvcVerifiers,
53
- bbIVCConcurrency: ivcConcurrency,
51
+ numConcurrentIVCVerifiers: Number(BB_NUM_IVC_VERIFIERS),
52
+ bbIVCConcurrency: Number(BB_IVC_CONCURRENCY),
53
+ bbChonkVerifyMaxBatch: Number(BB_CHONK_VERIFY_MAX_BATCH),
54
+ bbChonkVerifyConcurrency: Number(BB_CHONK_VERIFY_BATCH_CONCURRENCY),
54
55
  };
55
56
  } catch (err) {
56
57
  logger.error(`Native BB not available, error: ${err}`);
@@ -0,0 +1,188 @@
1
+ import { EthAddress } from '@aztec/aztec.js/addresses';
2
+ import { Fr } from '@aztec/aztec.js/fields';
3
+ import type { Logger } from '@aztec/aztec.js/log';
4
+ import { SecretValue } from '@aztec/foundation/config';
5
+
6
+ import { Pool } from 'pg';
7
+ import { privateKeyToAccount } from 'viem/accounts';
8
+
9
+ /**
10
+ * Configuration for HA database connection
11
+ */
12
+ export interface HADatabaseConfig {
13
+ /** PostgreSQL connection URL */
14
+ databaseUrl: SecretValue<string>;
15
+ /** Node ID for HA coordination */
16
+ nodeId: string;
17
+ /** Enable HA signing */
18
+ haSigningEnabled: boolean;
19
+ /** Polling interval in ms */
20
+ pollingIntervalMs: number;
21
+ /** Signing timeout in ms */
22
+ signingTimeoutMs: number;
23
+ /** Max stuck duties age in ms */
24
+ maxStuckDutiesAgeMs: number;
25
+ }
26
+
27
+ /**
28
+ * Get database configuration from environment variables
29
+ */
30
+ export function createHADatabaseConfig(nodeId: string): HADatabaseConfig {
31
+ const databaseUrl = new SecretValue(
32
+ process.env.DATABASE_URL || 'postgresql://aztec:aztec@localhost:5432/aztec_ha_test',
33
+ );
34
+
35
+ return {
36
+ databaseUrl,
37
+ nodeId,
38
+ haSigningEnabled: true,
39
+ pollingIntervalMs: 100,
40
+ signingTimeoutMs: 3000,
41
+ maxStuckDutiesAgeMs: 72000,
42
+ };
43
+ }
44
+
45
+ /**
46
+ * Setup PostgreSQL database connection pool for HA tests
47
+ *
48
+ * Note: Database migrations should be run separately before starting tests,
49
+ * either via docker-compose entrypoint or manually with: aztec migrate-ha-db up
50
+ */
51
+ export function setupHADatabase(databaseUrl: string, logger?: Logger): Pool {
52
+ try {
53
+ // Create connection pool for test usage
54
+ // Migrations are already run by docker-compose entrypoint before tests start
55
+ const pool = new Pool({ connectionString: databaseUrl });
56
+
57
+ logger?.info('Connected to HA database (migrations should already be applied)');
58
+
59
+ return pool;
60
+ } catch (error) {
61
+ logger?.error(`Failed to connect to HA database: ${error}`);
62
+ throw error;
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Clean up HA database - drop all tables
68
+ * Use this between tests to ensure clean state
69
+ */
70
+ export async function cleanupHADatabase(pool: Pool, logger?: Logger): Promise<void> {
71
+ try {
72
+ // Drop all HA tables
73
+ await pool.query('DROP TABLE IF EXISTS validator_duties CASCADE');
74
+ await pool.query('DROP TABLE IF EXISTS schema_version CASCADE');
75
+ // Drop migration tracking table (node-pg-migrate uses 'pgmigrations' by default)
76
+ // This ensures migrations will run fresh on next startup
77
+ await pool.query('DROP TABLE IF EXISTS pgmigrations CASCADE');
78
+
79
+ logger?.info('HA database cleaned up successfully');
80
+ } catch (error) {
81
+ logger?.error(`Failed to cleanup HA database: ${error}`);
82
+ throw error;
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Query validator duties from the database
88
+ */
89
+ export async function getValidatorDuties(
90
+ pool: Pool,
91
+ slot: bigint,
92
+ dutyType?: 'ATTESTATION' | 'BLOCK_PROPOSAL' | 'GOVERNANCE_VOTE' | 'SLASHING_VOTE',
93
+ ): Promise<
94
+ Array<{
95
+ slot: string;
96
+ dutyType: string;
97
+ validatorAddress: string;
98
+ nodeId: string;
99
+ startedAt: Date;
100
+ completedAt: Date | undefined;
101
+ }>
102
+ > {
103
+ const query = dutyType
104
+ ? 'SELECT slot, duty_type, validator_address, node_id, started_at, completed_at FROM validator_duties WHERE slot = $1 AND duty_type = $2 ORDER BY started_at'
105
+ : 'SELECT slot, duty_type, validator_address, node_id, started_at, completed_at FROM validator_duties WHERE slot = $1 ORDER BY started_at';
106
+
107
+ const params = dutyType ? [slot.toString(), dutyType] : [slot.toString()];
108
+
109
+ const result = await pool.query<{
110
+ slot: string;
111
+ duty_type: string;
112
+ validator_address: string;
113
+ node_id: string;
114
+ started_at: Date;
115
+ completed_at: Date | undefined;
116
+ }>(query, params);
117
+
118
+ return result.rows.map(row => ({
119
+ slot: row.slot,
120
+ dutyType: row.duty_type,
121
+ validatorAddress: row.validator_address,
122
+ nodeId: row.node_id,
123
+ startedAt: row.started_at,
124
+ completedAt: row.completed_at,
125
+ }));
126
+ }
127
+
128
+ /**
129
+ * Convert private keys to Ethereum addresses
130
+ */
131
+ export function getAddressesFromPrivateKeys(privateKeys: `0x${string}`[]): string[] {
132
+ return privateKeys.map(pk => {
133
+ const account = privateKeyToAccount(pk);
134
+ return account.address;
135
+ });
136
+ }
137
+
138
+ /**
139
+ * Create initial validators from private keys for L1 contract deployment
140
+ */
141
+ export function createInitialValidatorsFromPrivateKeys(attesterPrivateKeys: `0x${string}`[]): Array<{
142
+ attester: EthAddress;
143
+ withdrawer: EthAddress;
144
+ privateKey: `0x${string}`;
145
+ bn254SecretKey: SecretValue<bigint>;
146
+ }> {
147
+ return attesterPrivateKeys.map(pk => {
148
+ const account = privateKeyToAccount(pk);
149
+ return {
150
+ attester: EthAddress.fromString(account.address),
151
+ withdrawer: EthAddress.fromString(account.address),
152
+ privateKey: pk,
153
+ bn254SecretKey: new SecretValue(Fr.random().toBigInt()),
154
+ };
155
+ });
156
+ }
157
+
158
+ /**
159
+ * Verify no duplicate attestations per validator (HA coordination check)
160
+ * Groups duties by validator address and verifies each validator attested exactly once
161
+ */
162
+ export function verifyNoDuplicateAttestations(
163
+ attestationDuties: Array<{
164
+ validatorAddress: string;
165
+ nodeId: string;
166
+ completedAt: Date | undefined;
167
+ }>,
168
+ logger?: Logger,
169
+ ): Map<string, typeof attestationDuties> {
170
+ const dutiesByValidator = new Map<string, typeof attestationDuties>();
171
+ for (const duty of attestationDuties) {
172
+ const existing = dutiesByValidator.get(duty.validatorAddress) || [];
173
+ existing.push(duty);
174
+ dutiesByValidator.set(duty.validatorAddress, existing);
175
+ }
176
+
177
+ for (const [validatorAddress, validatorDuties] of dutiesByValidator.entries()) {
178
+ if (validatorDuties.length !== 1) {
179
+ throw new Error(`Validator ${validatorAddress} attested ${validatorDuties.length} times (expected exactly once)`);
180
+ }
181
+ if (!validatorDuties[0].completedAt) {
182
+ throw new Error(`Validator ${validatorAddress} attestation duty not completed`);
183
+ }
184
+ logger?.info(`Validator ${validatorAddress} attested once via node ${validatorDuties[0].nodeId}`);
185
+ }
186
+
187
+ return dutiesByValidator;
188
+ }
@@ -1,4 +1,5 @@
1
1
  export * from './fixtures.js';
2
+ export * from './ha_setup.js';
2
3
  export * from './logging.js';
3
4
  export * from './utils.js';
4
5
  export * from './token_utils.js';
@@ -0,0 +1,49 @@
1
+ import { DefaultAccountContract } from '@aztec/accounts/defaults';
2
+ import type { ContractArtifact } from '@aztec/aztec.js/abi';
3
+ import type { AuthWitnessProvider } from '@aztec/aztec.js/account';
4
+ import type { CompleteAddress } from '@aztec/aztec.js/addresses';
5
+ import { AuthWitness } from '@aztec/aztec.js/authorization';
6
+ import type { Fr } from '@aztec/aztec.js/fields';
7
+ import { Schnorr } from '@aztec/foundation/crypto/schnorr';
8
+ import { GrumpkinScalar } from '@aztec/foundation/curves/grumpkin';
9
+ import { SchnorrHardcodedAccountContractArtifact } from '@aztec/noir-contracts.js/SchnorrHardcodedAccount';
10
+
11
+ /**
12
+ * The private key that matches the hardcoded public key in the SchnorrHardcodedAccountContract.
13
+ * The corresponding public key is baked into the Noir contract as a global constant.
14
+ */
15
+ export const SCHNORR_HARDCODED_PRIVATE_KEY = GrumpkinScalar.fromHexString(
16
+ '0xd35d743ac0dfe3d6dbe6be8c877cb524a00ab1e3d52d7bada095dfc8894ccfa',
17
+ );
18
+
19
+ /**
20
+ * Account contract backed by the SchnorrHardcodedAccount Noir contract.
21
+ * This contract verifies Schnorr signatures against a public key that is hardcoded
22
+ * in the contract artifact (not stored in a note), so it does not require on-chain
23
+ * deployment or initialization. Useful for tests that need a working account without
24
+ * mining any blocks.
25
+ */
26
+ export class SchnorrHardcodedKeyAccountContract extends DefaultAccountContract {
27
+ constructor(private privateKey: GrumpkinScalar = SCHNORR_HARDCODED_PRIVATE_KEY) {
28
+ super();
29
+ }
30
+
31
+ override getContractArtifact(): Promise<ContractArtifact> {
32
+ return Promise.resolve(SchnorrHardcodedAccountContractArtifact);
33
+ }
34
+
35
+ getInitializationFunctionAndArgs() {
36
+ return Promise.resolve(undefined);
37
+ }
38
+
39
+ getAuthWitnessProvider(_address: CompleteAddress): AuthWitnessProvider {
40
+ const privateKey = this.privateKey;
41
+ return {
42
+ async createAuthWit(messageHash: Fr): Promise<AuthWitness> {
43
+ const signer = new Schnorr();
44
+ const signature = await signer.constructSignature(messageHash, privateKey);
45
+ return new AuthWitness(messageHash, signature.toLimbFields());
46
+ },
47
+ };
48
+ }
49
+ }