@aztec/end-to-end 0.0.0-test.1 → 0.0.1-fake-ceab37513c

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 (156) hide show
  1. package/dest/bench/client_flows/benchmark.d.ts +60 -0
  2. package/dest/bench/client_flows/benchmark.d.ts.map +1 -0
  3. package/dest/bench/client_flows/benchmark.js +261 -0
  4. package/dest/bench/client_flows/client_flows_benchmark.d.ts +69 -0
  5. package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -0
  6. package/dest/bench/client_flows/client_flows_benchmark.js +315 -0
  7. package/dest/bench/client_flows/config.d.ts +14 -0
  8. package/dest/bench/client_flows/config.d.ts.map +1 -0
  9. package/dest/bench/client_flows/config.js +106 -0
  10. package/dest/bench/client_flows/data_extractor.d.ts +2 -0
  11. package/dest/bench/client_flows/data_extractor.d.ts.map +1 -0
  12. package/dest/bench/client_flows/data_extractor.js +99 -0
  13. package/dest/bench/utils.d.ts +10 -27
  14. package/dest/bench/utils.d.ts.map +1 -1
  15. package/dest/bench/utils.js +27 -43
  16. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +15 -7
  17. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts.map +1 -1
  18. package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.js +66 -38
  19. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts +10 -18
  20. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts.map +1 -1
  21. package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.js +34 -53
  22. package/dest/e2e_deploy_contract/deploy_test.d.ts +4 -2
  23. package/dest/e2e_deploy_contract/deploy_test.d.ts.map +1 -1
  24. package/dest/e2e_deploy_contract/deploy_test.js +9 -6
  25. package/dest/e2e_epochs/epochs_test.d.ts +56 -17
  26. package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
  27. package/dest/e2e_epochs/epochs_test.js +222 -42
  28. package/dest/e2e_fees/bridging_race.notest.d.ts +2 -0
  29. package/dest/e2e_fees/bridging_race.notest.d.ts.map +1 -0
  30. package/dest/e2e_fees/bridging_race.notest.js +60 -0
  31. package/dest/e2e_fees/fees_test.d.ts +16 -5
  32. package/dest/e2e_fees/fees_test.d.ts.map +1 -1
  33. package/dest/e2e_fees/fees_test.js +87 -88
  34. package/dest/e2e_l1_publisher/write_json.d.ts +8 -0
  35. package/dest/e2e_l1_publisher/write_json.d.ts.map +1 -0
  36. package/dest/e2e_l1_publisher/write_json.js +57 -0
  37. package/dest/e2e_multi_validator/utils.d.ts +12 -0
  38. package/dest/e2e_multi_validator/utils.d.ts.map +1 -0
  39. package/dest/e2e_multi_validator/utils.js +214 -0
  40. package/dest/e2e_nested_contract/nested_contract_test.d.ts +5 -5
  41. package/dest/e2e_nested_contract/nested_contract_test.d.ts.map +1 -1
  42. package/dest/e2e_nested_contract/nested_contract_test.js +19 -14
  43. package/dest/e2e_p2p/inactivity_slash_test.d.ts +31 -0
  44. package/dest/e2e_p2p/inactivity_slash_test.d.ts.map +1 -0
  45. package/dest/e2e_p2p/inactivity_slash_test.js +132 -0
  46. package/dest/e2e_p2p/p2p_network.d.ts +56 -21
  47. package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
  48. package/dest/e2e_p2p/p2p_network.js +154 -125
  49. package/dest/e2e_p2p/shared.d.ts +41 -3
  50. package/dest/e2e_p2p/shared.d.ts.map +1 -1
  51. package/dest/e2e_p2p/shared.js +146 -6
  52. package/dest/e2e_token_contract/token_contract_test.d.ts +10 -5
  53. package/dest/e2e_token_contract/token_contract_test.d.ts.map +1 -1
  54. package/dest/e2e_token_contract/token_contract_test.js +51 -24
  55. package/dest/{e2e_prover → fixtures}/e2e_prover_test.d.ts +7 -4
  56. package/dest/fixtures/e2e_prover_test.d.ts.map +1 -0
  57. package/dest/{e2e_prover → fixtures}/e2e_prover_test.js +67 -62
  58. package/dest/fixtures/fixtures.d.ts +5 -6
  59. package/dest/fixtures/fixtures.d.ts.map +1 -1
  60. package/dest/fixtures/fixtures.js +4 -3
  61. package/dest/fixtures/get_acvm_config.d.ts.map +1 -1
  62. package/dest/fixtures/get_acvm_config.js +2 -14
  63. package/dest/fixtures/get_bb_config.d.ts.map +1 -1
  64. package/dest/fixtures/get_bb_config.js +8 -15
  65. package/dest/fixtures/l1_to_l2_messaging.d.ts +8 -5
  66. package/dest/fixtures/l1_to_l2_messaging.d.ts.map +1 -1
  67. package/dest/fixtures/l1_to_l2_messaging.js +44 -18
  68. package/dest/fixtures/setup_l1_contracts.d.ts +3 -3
  69. package/dest/fixtures/setup_l1_contracts.d.ts.map +1 -1
  70. package/dest/fixtures/setup_l1_contracts.js +3 -3
  71. package/dest/fixtures/setup_p2p_test.d.ts +14 -6
  72. package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
  73. package/dest/fixtures/setup_p2p_test.js +73 -21
  74. package/dest/fixtures/snapshot_manager.d.ts +8 -3
  75. package/dest/fixtures/snapshot_manager.d.ts.map +1 -1
  76. package/dest/fixtures/snapshot_manager.js +120 -104
  77. package/dest/fixtures/token_utils.d.ts +4 -3
  78. package/dest/fixtures/token_utils.d.ts.map +1 -1
  79. package/dest/fixtures/token_utils.js +24 -7
  80. package/dest/fixtures/utils.d.ts +65 -22
  81. package/dest/fixtures/utils.d.ts.map +1 -1
  82. package/dest/fixtures/utils.js +439 -318
  83. package/dest/fixtures/web3signer.d.ts +5 -0
  84. package/dest/fixtures/web3signer.d.ts.map +1 -0
  85. package/dest/fixtures/web3signer.js +42 -0
  86. package/dest/shared/cross_chain_test_harness.d.ts +28 -18
  87. package/dest/shared/cross_chain_test_harness.d.ts.map +1 -1
  88. package/dest/shared/cross_chain_test_harness.js +97 -41
  89. package/dest/shared/gas_portal_test_harness.d.ts +23 -18
  90. package/dest/shared/gas_portal_test_harness.d.ts.map +1 -1
  91. package/dest/shared/gas_portal_test_harness.js +43 -25
  92. package/dest/shared/submit-transactions.d.ts.map +1 -1
  93. package/dest/shared/uniswap_l1_l2.d.ts +5 -6
  94. package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
  95. package/dest/shared/uniswap_l1_l2.js +136 -90
  96. package/dest/simulators/lending_simulator.d.ts +5 -6
  97. package/dest/simulators/lending_simulator.d.ts.map +1 -1
  98. package/dest/simulators/lending_simulator.js +11 -15
  99. package/dest/simulators/token_simulator.d.ts +2 -1
  100. package/dest/simulators/token_simulator.d.ts.map +1 -1
  101. package/dest/simulators/token_simulator.js +16 -13
  102. package/dest/spartan/setup_test_wallets.d.ts +8 -1
  103. package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
  104. package/dest/spartan/setup_test_wallets.js +108 -22
  105. package/dest/spartan/utils.d.ts +60 -307
  106. package/dest/spartan/utils.d.ts.map +1 -1
  107. package/dest/spartan/utils.js +200 -115
  108. package/package.json +60 -56
  109. package/src/bench/client_flows/benchmark.ts +341 -0
  110. package/src/bench/client_flows/client_flows_benchmark.ts +422 -0
  111. package/src/bench/client_flows/config.ts +61 -0
  112. package/src/bench/client_flows/data_extractor.ts +111 -0
  113. package/src/bench/utils.ts +26 -52
  114. package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +60 -40
  115. package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +47 -75
  116. package/src/e2e_deploy_contract/deploy_test.ts +11 -8
  117. package/src/e2e_epochs/epochs_test.ts +276 -54
  118. package/src/e2e_fees/bridging_race.notest.ts +75 -0
  119. package/src/e2e_fees/fees_test.ts +121 -108
  120. package/src/e2e_l1_publisher/write_json.ts +74 -0
  121. package/src/e2e_multi_validator/utils.ts +258 -0
  122. package/src/e2e_nested_contract/nested_contract_test.ts +22 -14
  123. package/src/e2e_p2p/inactivity_slash_test.ts +174 -0
  124. package/src/e2e_p2p/p2p_network.ts +212 -144
  125. package/src/e2e_p2p/shared.ts +234 -14
  126. package/src/e2e_token_contract/token_contract_test.ts +42 -38
  127. package/src/fixtures/dumps/epoch_proof_result.json +1 -1
  128. package/src/{e2e_prover → fixtures}/e2e_prover_test.ts +62 -69
  129. package/src/fixtures/fixtures.ts +4 -3
  130. package/src/fixtures/get_acvm_config.ts +2 -10
  131. package/src/fixtures/get_bb_config.ts +15 -11
  132. package/src/fixtures/l1_to_l2_messaging.ts +53 -23
  133. package/src/fixtures/setup_l1_contracts.ts +5 -6
  134. package/src/fixtures/setup_p2p_test.ts +112 -30
  135. package/src/fixtures/snapshot_manager.ts +150 -102
  136. package/src/fixtures/token_utils.ts +33 -8
  137. package/src/fixtures/utils.ts +530 -352
  138. package/src/fixtures/web3signer.ts +46 -0
  139. package/src/guides/up_quick_start.sh +4 -4
  140. package/src/shared/cross_chain_test_harness.ts +92 -52
  141. package/src/shared/gas_portal_test_harness.ts +47 -31
  142. package/src/shared/uniswap_l1_l2.ts +127 -124
  143. package/src/simulators/lending_simulator.ts +11 -15
  144. package/src/simulators/token_simulator.ts +17 -12
  145. package/src/spartan/DEVELOP.md +116 -0
  146. package/src/spartan/setup_test_wallets.ts +144 -29
  147. package/src/spartan/utils.ts +194 -116
  148. package/dest/e2e_prover/e2e_prover_test.d.ts.map +0 -1
  149. package/dest/sample-dapp/connect.js +0 -12
  150. package/dest/sample-dapp/contracts.js +0 -10
  151. package/dest/sample-dapp/deploy.js +0 -35
  152. package/dest/sample-dapp/index.js +0 -98
  153. package/src/sample-dapp/connect.mjs +0 -16
  154. package/src/sample-dapp/contracts.mjs +0 -14
  155. package/src/sample-dapp/deploy.mjs +0 -40
  156. package/src/sample-dapp/index.mjs +0 -128
@@ -1,20 +1,39 @@
1
- import { AztecNodeService } from '@aztec/aztec-node';
2
- import { Fr, type Logger, getTimestampRangeForEpoch, retryUntil, sleep } from '@aztec/aztec.js';
3
- import { ChainMonitor } from '@aztec/aztec.js/ethereum';
1
+ import { type AztecNodeConfig, AztecNodeService } from '@aztec/aztec-node';
2
+ import {
3
+ Fr,
4
+ type Logger,
5
+ MerkleTreeId,
6
+ type Wallet,
7
+ getContractInstanceFromInstantiationParams,
8
+ getTimestampRangeForEpoch,
9
+ retryUntil,
10
+ sleep,
11
+ } from '@aztec/aztec.js';
12
+ import { EpochCache } from '@aztec/epoch-cache';
13
+ import { DefaultL1ContractsConfig, type ExtendedViemWalletClient, createExtendedL1Client } from '@aztec/ethereum';
4
14
  import { RollupContract } from '@aztec/ethereum/contracts';
5
- import { DelayedTxUtils, type Delayer, waitUntilL1Timestamp } from '@aztec/ethereum/test';
15
+ import { ChainMonitor, DelayedTxUtils, type Delayer, waitUntilL1Timestamp, withDelayer } from '@aztec/ethereum/test';
16
+ import { SecretValue } from '@aztec/foundation/config';
6
17
  import { randomBytes } from '@aztec/foundation/crypto';
7
18
  import { withLogNameSuffix } from '@aztec/foundation/log';
8
- import { ProverNode, ProverNodePublisher } from '@aztec/prover-node';
19
+ import { SpamContract } from '@aztec/noir-test-contracts.js/Spam';
20
+ import { getMockPubSubP2PServiceFactory } from '@aztec/p2p/test-helpers';
21
+ import { ProverNode, type ProverNodeConfig, ProverNodePublisher } from '@aztec/prover-node';
9
22
  import type { TestProverNode } from '@aztec/prover-node/test';
10
- import type { SequencerPublisher } from '@aztec/sequencer-client';
23
+ import {
24
+ type SequencerClient,
25
+ type SequencerEvents,
26
+ type SequencerPublisher,
27
+ SequencerState,
28
+ } from '@aztec/sequencer-client';
11
29
  import type { TestSequencerClient } from '@aztec/sequencer-client/test';
12
- import type { L2BlockNumber } from '@aztec/stdlib/block';
13
- import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
14
- import { MerkleTreeId } from '@aztec/stdlib/trees';
30
+ import { EthAddress, type L2BlockNumber } from '@aztec/stdlib/block';
31
+ import { type L1RollupConstants, getProofSubmissionDeadlineTimestamp } from '@aztec/stdlib/epoch-helpers';
32
+ import { tryStop } from '@aztec/stdlib/interfaces/server';
15
33
 
16
34
  import { join } from 'path';
17
- import type { Hex, PublicClient } from 'viem';
35
+ import type { Hex } from 'viem';
36
+ import { privateKeyToAccount } from 'viem/accounts';
18
37
 
19
38
  import {
20
39
  type EndToEndContext,
@@ -24,15 +43,20 @@ import {
24
43
  setup,
25
44
  } from '../fixtures/utils.js';
26
45
 
27
- // This can be lowered to as much as 2s in non-CI
28
- export const L1_BLOCK_TIME_IN_S = process.env.L1_BLOCK_TIME ? parseInt(process.env.L1_BLOCK_TIME) : 8;
29
- export const EPOCH_DURATION_IN_L2_SLOTS = 4;
30
- export const L2_SLOT_DURATION_IN_L1_SLOTS = 2;
31
46
  export const WORLD_STATE_BLOCK_HISTORY = 2;
32
47
  export const WORLD_STATE_BLOCK_CHECK_INTERVAL = 50;
33
48
  export const ARCHIVER_POLL_INTERVAL = 50;
49
+ export const DEFAULT_L1_BLOCK_TIME = process.env.CI ? 12 : 8;
50
+
51
+ export type EpochsTestOpts = Partial<SetupOptions> & { numberOfAccounts?: number };
34
52
 
35
- export type EpochsTestOpts = Partial<Pick<SetupOptions, 'startProverNode'>>;
53
+ export type TrackedSequencerEvent = {
54
+ [K in keyof SequencerEvents]: Parameters<SequencerEvents[K]>[0] & {
55
+ type: K;
56
+ sequencerIndex: number;
57
+ validator: EthAddress;
58
+ };
59
+ }[keyof SequencerEvents];
36
60
 
37
61
  /**
38
62
  * Tests building of epochs using fast block times and short epochs.
@@ -41,46 +65,72 @@ export type EpochsTestOpts = Partial<Pick<SetupOptions, 'startProverNode'>>;
41
65
  */
42
66
  export class EpochsTestContext {
43
67
  public context!: EndToEndContext;
44
- public l1Client!: PublicClient;
68
+ public l1Client!: ExtendedViemWalletClient;
45
69
  public rollup!: RollupContract;
46
70
  public constants!: L1RollupConstants;
47
71
  public logger!: Logger;
48
72
  public monitor!: ChainMonitor;
73
+ public epochCache!: EpochCache;
49
74
  public proverDelayer!: Delayer;
50
75
  public sequencerDelayer!: Delayer;
51
76
 
52
77
  public proverNodes: ProverNode[] = [];
53
78
  public nodes: AztecNodeService[] = [];
54
79
 
80
+ public epochDuration!: number;
81
+
82
+ public L1_BLOCK_TIME_IN_S!: number;
83
+ public L2_SLOT_DURATION_IN_S!: number;
84
+
55
85
  public static async setup(opts: EpochsTestOpts = {}) {
56
86
  const test = new EpochsTestContext();
57
87
  await test.setup(opts);
58
88
  return test;
59
89
  }
60
90
 
91
+ public static getSlotDurations(opts: EpochsTestOpts = {}) {
92
+ const envEthereumSlotDuration = process.env.L1_BLOCK_TIME
93
+ ? parseInt(process.env.L1_BLOCK_TIME)
94
+ : DEFAULT_L1_BLOCK_TIME;
95
+ const ethereumSlotDuration = opts.ethereumSlotDuration ?? envEthereumSlotDuration;
96
+ const aztecSlotDuration = opts.aztecSlotDuration ?? ethereumSlotDuration * 2;
97
+ const aztecEpochDuration = opts.aztecEpochDuration ?? 6;
98
+ const aztecProofSubmissionEpochs = opts.aztecProofSubmissionEpochs ?? 1;
99
+ return { ethereumSlotDuration, aztecSlotDuration, aztecEpochDuration, aztecProofSubmissionEpochs };
100
+ }
101
+
61
102
  public async setup(opts: EpochsTestOpts = {}) {
103
+ const { ethereumSlotDuration, aztecSlotDuration, aztecEpochDuration, aztecProofSubmissionEpochs } =
104
+ EpochsTestContext.getSlotDurations(opts);
105
+
106
+ this.L1_BLOCK_TIME_IN_S = ethereumSlotDuration;
107
+ this.L2_SLOT_DURATION_IN_S = aztecSlotDuration;
108
+
62
109
  // Set up system without any account nor protocol contracts
63
110
  // and with faster block times and shorter epochs.
64
- const context = await setup(0, {
111
+ const context = await setup(opts.numberOfAccounts ?? 0, {
112
+ automineL1Setup: true,
65
113
  checkIntervalMs: 50,
66
114
  archiverPollingIntervalMS: ARCHIVER_POLL_INTERVAL,
67
115
  worldStateBlockCheckIntervalMS: WORLD_STATE_BLOCK_CHECK_INTERVAL,
68
116
  skipProtocolContracts: true,
69
117
  salt: 1,
70
- aztecEpochDuration: EPOCH_DURATION_IN_L2_SLOTS,
71
- aztecSlotDuration: L1_BLOCK_TIME_IN_S * L2_SLOT_DURATION_IN_L1_SLOTS,
72
- ethereumSlotDuration: L1_BLOCK_TIME_IN_S,
73
- aztecProofSubmissionWindow: EPOCH_DURATION_IN_L2_SLOTS * 2 - 1,
118
+ aztecEpochDuration,
119
+ aztecSlotDuration,
120
+ ethereumSlotDuration,
121
+ aztecProofSubmissionEpochs,
122
+ aztecTargetCommitteeSize: opts.initialValidators?.length ?? 0,
74
123
  minTxsPerBlock: 0,
75
124
  realProofs: false,
76
125
  startProverNode: true,
126
+ proverTestDelayMs: opts.proverTestDelayMs ?? 0,
77
127
  // We use numeric incremental prover ids for simplicity, but we can switch to
78
128
  // using the prover's eth address if the proverId is used for something in the rollup contract
79
- proverId: Fr.fromString('1'),
80
- // This must be enough so that the tx from the prover is delayed properly,
81
- // but not so much to hang the sequencer and timeout the teardown
82
- txPropagationMaxQueryAttempts: 12,
129
+ // Use numeric EthAddress for deterministic prover id
130
+ proverId: EthAddress.fromNumber(1),
83
131
  worldStateBlockHistory: WORLD_STATE_BLOCK_HISTORY,
132
+ exitDelaySeconds: DefaultL1ContractsConfig.exitDelaySeconds,
133
+ slasherFlavor: 'none',
84
134
  ...opts,
85
135
  });
86
136
 
@@ -88,32 +138,38 @@ export class EpochsTestContext {
88
138
  this.proverNodes = context.proverNode ? [context.proverNode] : [];
89
139
  this.nodes = context.aztecNode ? [context.aztecNode as AztecNodeService] : [];
90
140
  this.logger = context.logger;
91
- this.l1Client = context.deployL1ContractsValues.publicClient;
141
+ this.l1Client = context.deployL1ContractsValues.l1Client;
92
142
  this.rollup = RollupContract.getFromConfig(context.config);
143
+ this.epochCache = await EpochCache.create(this.rollup, context.config, { dateProvider: context.dateProvider });
93
144
 
94
145
  // Loop that tracks L1 and L2 block numbers and logs whenever there's a new one.
95
- this.monitor = new ChainMonitor(this.rollup, this.logger).start();
146
+ this.monitor = new ChainMonitor(this.rollup, context.dateProvider, this.logger).start();
96
147
 
97
148
  // This is hideous.
98
149
  // We ought to have a definite reference to the l1TxUtils that we're using in both places, provided by the test context.
99
150
  this.proverDelayer = context.proverNode
100
151
  ? (((context.proverNode as TestProverNode).publisher as ProverNodePublisher).l1TxUtils as DelayedTxUtils).delayer!
101
152
  : undefined!;
102
- this.sequencerDelayer = (
103
- ((context.sequencer as TestSequencerClient).sequencer.publisher as SequencerPublisher).l1TxUtils as DelayedTxUtils
104
- ).delayer!;
153
+ this.sequencerDelayer = context.sequencer
154
+ ? (
155
+ ((context.sequencer as TestSequencerClient).sequencer.publisher as SequencerPublisher)
156
+ .l1TxUtils as DelayedTxUtils
157
+ ).delayer!
158
+ : undefined!;
105
159
 
106
- if ((context.proverNode && !this.proverDelayer) || !this.sequencerDelayer) {
160
+ if ((context.proverNode && !this.proverDelayer) || (context.sequencer && !this.sequencerDelayer)) {
107
161
  throw new Error(`Could not find prover or sequencer delayer`);
108
162
  }
109
163
 
110
164
  // Constants used for time calculation
165
+ this.epochDuration = aztecEpochDuration;
111
166
  this.constants = {
112
- epochDuration: EPOCH_DURATION_IN_L2_SLOTS,
113
- slotDuration: L1_BLOCK_TIME_IN_S * L2_SLOT_DURATION_IN_L1_SLOTS,
167
+ epochDuration: aztecEpochDuration,
168
+ slotDuration: aztecSlotDuration,
114
169
  l1StartBlock: await this.rollup.getL1StartBlock(),
115
170
  l1GenesisTime: await this.rollup.getL1GenesisTime(),
116
- ethereumSlotDuration: L1_BLOCK_TIME_IN_S,
171
+ ethereumSlotDuration,
172
+ proofSubmissionEpochs: Number(await this.rollup.getProofSubmissionEpochs()),
117
173
  };
118
174
 
119
175
  this.logger.info(
@@ -122,38 +178,98 @@ export class EpochsTestContext {
122
178
  }
123
179
 
124
180
  public async teardown() {
125
- this.monitor.stop();
126
- await Promise.all(this.proverNodes.map(node => node.stop()));
127
- await Promise.all(this.nodes.map(node => node.stop()));
181
+ await this.monitor.stop();
182
+ await Promise.all(this.proverNodes.map(node => tryStop(node, this.logger)));
183
+ await Promise.all(this.nodes.map(node => tryStop(node, this.logger)));
128
184
  await this.context.teardown();
129
185
  }
130
186
 
131
- public async createProverNode() {
187
+ public async createProverNode(opts: { dontStart?: boolean } & Partial<ProverNodeConfig> = {}) {
132
188
  this.logger.warn('Creating and syncing a simulated prover node...');
133
189
  const proverNodePrivateKey = this.getNextPrivateKey();
134
190
  const suffix = (this.proverNodes.length + 1).toString();
191
+ const proverId = EthAddress.fromNumber(parseInt(suffix, 10));
135
192
  const proverNode = await withLogNameSuffix(suffix, () =>
136
193
  createAndSyncProverNode(
137
194
  proverNodePrivateKey,
138
- { ...this.context.config, proverId: Fr.fromString(suffix) },
195
+ { ...this.context.config, proverId },
196
+ {
197
+ dataDirectory: join(this.context.config.dataDirectory!, randomBytes(8).toString('hex')),
198
+ proverId,
199
+ ...opts,
200
+ },
139
201
  this.context.aztecNode,
140
- join(this.context.config.dataDirectory!, randomBytes(8).toString('hex')),
202
+ undefined,
203
+ { dateProvider: this.context.dateProvider },
141
204
  ),
142
205
  );
143
206
  this.proverNodes.push(proverNode);
144
207
  return proverNode;
145
208
  }
146
209
 
147
- public async createNonValidatorNode() {
210
+ public createNonValidatorNode(opts: Partial<AztecNodeConfig> = {}) {
148
211
  this.logger.warn('Creating and syncing a node without a validator...');
212
+ return this.createNode({ ...opts, disableValidator: true });
213
+ }
214
+
215
+ public createValidatorNode(
216
+ privateKeys: `0x${string}`[],
217
+ opts: Partial<AztecNodeConfig> & { txDelayerMaxInclusionTimeIntoSlot?: number; dontStartSequencer?: boolean } = {},
218
+ ) {
219
+ this.logger.warn('Creating and syncing a validator node...');
220
+ return this.createNode({ ...opts, disableValidator: false, validatorPrivateKeys: new SecretValue(privateKeys) });
221
+ }
222
+
223
+ private async createNode(
224
+ opts: Partial<AztecNodeConfig> & { txDelayerMaxInclusionTimeIntoSlot?: number; dontStartSequencer?: boolean } = {},
225
+ ) {
149
226
  const suffix = (this.nodes.length + 1).toString();
227
+ const { mockGossipSubNetwork } = this.context;
228
+ const resolvedConfig = { ...this.context.config, ...opts };
229
+ const p2pEnabled = resolvedConfig.p2pEnabled || mockGossipSubNetwork !== undefined;
230
+ const p2pIp = resolvedConfig.p2pIp ?? (p2pEnabled ? '127.0.0.1' : undefined);
150
231
  const node = await withLogNameSuffix(suffix, () =>
151
- AztecNodeService.createAndSync({
152
- ...this.context.config,
153
- disableValidator: true,
154
- dataDirectory: join(this.context.config.dataDirectory!, randomBytes(8).toString('hex')),
155
- }),
232
+ AztecNodeService.createAndSync(
233
+ {
234
+ ...resolvedConfig,
235
+ dataDirectory: join(this.context.config.dataDirectory!, randomBytes(8).toString('hex')),
236
+ validatorPrivateKeys: opts.validatorPrivateKeys ?? new SecretValue([]),
237
+ p2pEnabled,
238
+ p2pIp,
239
+ },
240
+ {
241
+ dateProvider: this.context.dateProvider,
242
+ p2pClientDeps: {
243
+ p2pServiceFactory: mockGossipSubNetwork ? getMockPubSubP2PServiceFactory(mockGossipSubNetwork) : undefined,
244
+ },
245
+ },
246
+ {
247
+ prefilledPublicData: this.context.prefilledPublicData,
248
+ ...opts,
249
+ },
250
+ ),
156
251
  );
252
+
253
+ // REFACTOR: We're getting too much into the internals of the sequencer here.
254
+ // We should have a single method for constructing an aztec node that returns a TestAztecNodeService
255
+ // which directly exposes the delayer and sets any test config.
256
+ if (opts.txDelayerMaxInclusionTimeIntoSlot !== undefined) {
257
+ this.logger.info(
258
+ `Setting tx delayer max inclusion time into slot to ${opts.txDelayerMaxInclusionTimeIntoSlot} seconds`,
259
+ );
260
+ // Here we reach into the sequencer and hook in a tx delayer. The problem is that the sequencer's l1 utils only uses a public client, not a wallet.
261
+ // The delayer needs a wallet (a client that can sign), so we have to create one here.
262
+ const l1Client = createExtendedL1Client(
263
+ resolvedConfig.l1RpcUrls!,
264
+ resolvedConfig.publisherPrivateKeys![0]!.getValue(),
265
+ );
266
+ const sequencer = node.getSequencer() as TestSequencerClient;
267
+ const publisher = sequencer.sequencer.publisher;
268
+ const delayed = DelayedTxUtils.fromL1TxUtils(publisher.l1TxUtils, this.L1_BLOCK_TIME_IN_S, l1Client);
269
+ delayed.delayer!.setMaxInclusionTimeIntoSlot(opts.txDelayerMaxInclusionTimeIntoSlot);
270
+ publisher.l1TxUtils = delayed;
271
+ }
272
+
157
273
  this.nodes.push(node);
158
274
  return node;
159
275
  }
@@ -167,14 +283,19 @@ export class EpochsTestContext {
167
283
  public async waitUntilEpochStarts(epoch: number) {
168
284
  const [start] = getTimestampRangeForEpoch(BigInt(epoch), this.constants);
169
285
  this.logger.info(`Waiting until L1 timestamp ${start} is reached as the start of epoch ${epoch}`);
170
- await waitUntilL1Timestamp(this.l1Client, start - BigInt(L1_BLOCK_TIME_IN_S));
286
+ await waitUntilL1Timestamp(
287
+ this.l1Client,
288
+ start - BigInt(this.L1_BLOCK_TIME_IN_S),
289
+ undefined,
290
+ 30 * this.epochDuration,
291
+ );
171
292
  return start;
172
293
  }
173
294
 
174
295
  /** Waits until the given L2 block number is mined. */
175
296
  public async waitUntilL2BlockNumber(target: number, timeout = 60) {
176
297
  await retryUntil(
177
- () => Promise.resolve(target === this.monitor.l2BlockNumber),
298
+ () => Promise.resolve(target <= this.monitor.l2BlockNumber),
178
299
  `Wait until L2 block ${target}`,
179
300
  timeout,
180
301
  0.1,
@@ -184,34 +305,135 @@ export class EpochsTestContext {
184
305
  /** Waits until the given L2 block number is marked as proven. */
185
306
  public async waitUntilProvenL2BlockNumber(t: number, timeout = 60) {
186
307
  await retryUntil(
187
- () => Promise.resolve(t === this.monitor.l2ProvenBlockNumber),
308
+ () => Promise.resolve(t <= this.monitor.l2ProvenBlockNumber),
188
309
  `Wait proven L2 block ${t}`,
189
310
  timeout,
190
311
  0.1,
191
312
  );
313
+ return this.monitor.l2ProvenBlockNumber;
314
+ }
315
+
316
+ /** Waits until the last slot of the proof submission window for a given epoch. */
317
+ public async waitUntilLastSlotOfProofSubmissionWindow(epochNumber: number | bigint) {
318
+ const deadline = getProofSubmissionDeadlineTimestamp(BigInt(epochNumber), this.constants);
319
+ const oneSlotBefore = deadline - BigInt(this.constants.slotDuration);
320
+ const date = new Date(Number(oneSlotBefore) * 1000);
321
+ this.logger.info(`Waiting until last slot of submission window for epoch ${epochNumber} at ${date}`, {
322
+ oneSlotBefore,
323
+ });
324
+ await waitUntilL1Timestamp(this.l1Client, oneSlotBefore);
192
325
  }
193
326
 
194
327
  /** Waits for the aztec node to sync to the target block number. */
195
- public async waitForNodeToSync(blockNumber: number, type: 'finalised' | 'historic') {
328
+ public async waitForNodeToSync(blockNumber: number, type: 'proven' | 'finalized' | 'historic') {
196
329
  const waitTime = ARCHIVER_POLL_INTERVAL + WORLD_STATE_BLOCK_CHECK_INTERVAL;
197
330
  let synched = false;
198
331
  while (!synched) {
199
332
  await sleep(waitTime);
200
- const syncState = await this.context.aztecNode.getWorldStateSyncStatus();
201
- if (type === 'finalised') {
202
- synched = syncState.finalisedBlockNumber >= blockNumber;
333
+ const [syncState, tips] = await Promise.all([
334
+ this.context.aztecNode.getWorldStateSyncStatus(),
335
+ await this.context.aztecNode.getL2Tips(),
336
+ ]);
337
+ this.logger.info(`Wait for node synch ${blockNumber} ${type}`, { blockNumber, type, syncState, tips });
338
+ if (type === 'proven') {
339
+ synched = tips.proven.number >= blockNumber && syncState.latestBlockNumber >= blockNumber;
340
+ } else if (type === 'finalized') {
341
+ synched = syncState.finalizedBlockNumber >= blockNumber;
203
342
  } else {
204
343
  synched = syncState.oldestHistoricBlockNumber >= blockNumber;
205
344
  }
206
345
  }
207
346
  }
208
347
 
348
+ /** Registers the SpamContract on the given wallet. */
349
+ public async registerSpamContract(wallet: Wallet, salt = Fr.ZERO) {
350
+ const instance = await getContractInstanceFromInstantiationParams(SpamContract.artifact, {
351
+ constructorArgs: [],
352
+ constructorArtifact: undefined,
353
+ salt,
354
+ publicKeys: undefined,
355
+ deployer: undefined,
356
+ });
357
+ await wallet.registerContract({ artifact: SpamContract.artifact, instance });
358
+ return SpamContract.at(instance.address, wallet);
359
+ }
360
+
361
+ /** Creates an L1 client using a fresh account with funds from anvil, with a tx delayer already set up. */
362
+ public async createL1Client() {
363
+ const { client, delayer } = withDelayer(
364
+ createExtendedL1Client(
365
+ [...this.l1Client.chain.rpcUrls.default.http],
366
+ privateKeyToAccount(this.getNextPrivateKey()),
367
+ this.l1Client.chain,
368
+ ),
369
+ this.context.dateProvider!,
370
+ { ethereumSlotDuration: this.L1_BLOCK_TIME_IN_S },
371
+ );
372
+ expect(await client.getBalance({ address: client.account.address })).toBeGreaterThan(0n);
373
+ return { client, delayer };
374
+ }
375
+
209
376
  /** Verifies whether the given block number is found on the aztec node. */
210
377
  public async verifyHistoricBlock(blockNumber: L2BlockNumber, expectedSuccess: boolean) {
378
+ // We use `findLeavesIndexes` here, but could use any function that queries the world-state
379
+ // at a particular block, so we know whether that historic block is available or has been
380
+ // pruned. Note that `getBlock` would not work here, since it only hits the archiver.
211
381
  const result = await this.context.aztecNode
212
- .findBlockNumbersForIndexes(blockNumber, MerkleTreeId.NULLIFIER_TREE, [0n])
382
+ .findLeavesIndexes(blockNumber, MerkleTreeId.NULLIFIER_TREE, [Fr.ZERO])
213
383
  .then(_ => true)
214
384
  .catch(_ => false);
215
385
  expect(result).toBe(expectedSuccess);
216
386
  }
387
+
388
+ public watchSequencerEvents(
389
+ sequencers: SequencerClient[],
390
+ getMetadata: (i: number) => Record<string, any> = () => ({}),
391
+ ) {
392
+ const stateChanges: TrackedSequencerEvent[] = [];
393
+ const failEvents: TrackedSequencerEvent[] = [];
394
+
395
+ // Note we do not include the 'tx-count-check-failed' event here, since it is fine if we dont build
396
+ // due to lack of txs available.
397
+ const failEventsKeys: (keyof SequencerEvents)[] = [
398
+ 'block-build-failed',
399
+ 'block-publish-failed',
400
+ 'proposer-rollup-check-failed',
401
+ ];
402
+
403
+ const makeEvent = (
404
+ i: number,
405
+ eventName: keyof SequencerEvents,
406
+ args: Parameters<SequencerEvents[keyof SequencerEvents]>[0],
407
+ ) =>
408
+ ({
409
+ ...args,
410
+ type: eventName,
411
+ sequencerIndex: i + 2,
412
+ ...getMetadata(i),
413
+ }) as TrackedSequencerEvent;
414
+
415
+ sequencers.forEach((sequencer, i) => {
416
+ const sequencerIndex = i + 2;
417
+ sequencer.getSequencer().on('state-changed', (args: Parameters<SequencerEvents['state-changed']>[0]) => {
418
+ const noisyStates = [SequencerState.IDLE, SequencerState.PROPOSER_CHECK, SequencerState.SYNCHRONIZING];
419
+ if (!noisyStates.includes(args.newState)) {
420
+ const evt = makeEvent(i, 'state-changed', args);
421
+ stateChanges.push(evt);
422
+ this.logger.verbose(
423
+ `Sequencer ${sequencerIndex} transitioned from state ${args.oldState} to state ${args.newState}`,
424
+ evt,
425
+ );
426
+ }
427
+ });
428
+ failEventsKeys.forEach(eventName => {
429
+ sequencer.getSequencer().on(eventName, (args: Parameters<SequencerEvents[typeof eventName]>[0]) => {
430
+ const evt = makeEvent(i, eventName, args);
431
+ failEvents.push(evt);
432
+ this.logger.error(`Failed event ${eventName} from sequencer ${sequencerIndex}`, undefined, evt);
433
+ });
434
+ });
435
+ });
436
+
437
+ return { failEvents, stateChanges };
438
+ }
217
439
  }
@@ -0,0 +1,75 @@
1
+ import { getSchnorrAccount } from '@aztec/accounts/schnorr';
2
+ import { Fr, type Logger, type PXE, sleep } from '@aztec/aztec.js';
3
+ import { Fq } from '@aztec/foundation/fields';
4
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
5
+
6
+ import { jest } from '@jest/globals';
7
+ import type { Hex } from 'viem';
8
+
9
+ import { FeesTest } from './fees_test.js';
10
+
11
+ jest.setTimeout(300_000);
12
+
13
+ // Regression for https://github.com/AztecProtocol/aztec-packages/issues/12366
14
+ // Similar to e2e_fees/account_init but with no automine
15
+ describe('e2e_fees bridging_race', () => {
16
+ const ETHEREUM_SLOT_DURATION = 4;
17
+ const AZTEC_SLOT_DURATION = ETHEREUM_SLOT_DURATION * 2;
18
+
19
+ const t = new FeesTest('bridging_race', 1, {
20
+ ethereumSlotDuration: ETHEREUM_SLOT_DURATION,
21
+ aztecSlotDuration: AZTEC_SLOT_DURATION,
22
+ minTxsPerBlock: 0,
23
+ });
24
+
25
+ beforeAll(async () => {
26
+ await t.applyInitialAccountsSnapshot();
27
+ await t.applyPublicDeployAccountsSnapshot();
28
+ await t.applySetupFeeJuiceSnapshot();
29
+
30
+ ({ pxe, logger } = await t.setup());
31
+ });
32
+
33
+ afterAll(async () => {
34
+ await t.teardown();
35
+ });
36
+
37
+ let logger: Logger;
38
+ let pxe: PXE;
39
+ let bobsAddress: AztecAddress;
40
+
41
+ beforeEach(async () => {
42
+ const bobsSecretKey = Fr.random();
43
+ const bobsPrivateSigningKey = Fq.random();
44
+ const bobsAccountManager = await getSchnorrAccount(pxe, bobsSecretKey, bobsPrivateSigningKey, Fr.random());
45
+ const bobsCompleteAddress = await bobsAccountManager.getCompleteAddress();
46
+ bobsAddress = bobsCompleteAddress.address;
47
+ await bobsAccountManager.getWallet();
48
+ await bobsAccountManager.register();
49
+ });
50
+
51
+ it('Alice bridges funds to Bob', async () => {
52
+ // Tweak the token manager so the bridging happens immediately before the end of the current L2 slot
53
+ // This caused the message to be "not in state" when tried to be used
54
+ const l1TokenManager = t.feeJuiceBridgeTestHarness.l1TokenManager;
55
+ const origApprove = l1TokenManager.approve.bind(l1TokenManager);
56
+ l1TokenManager.approve = async (amount: bigint, address: Hex, addressName = '') => {
57
+ await origApprove(amount, address, addressName);
58
+ const sleepTime = (Number(t.chainMonitor.l2BlockTimestamp) + AZTEC_SLOT_DURATION) * 1000 - Date.now() - 500;
59
+ logger.info(`Sleeping for ${sleepTime}ms until near end of L2 slot before sending L1 fee juice to L2 inbox`);
60
+ await sleep(sleepTime);
61
+ };
62
+
63
+ // Waiting for the archiver to sync the message _before_ waiting for the mandatory 2 L2 blocks to pass fixed it
64
+ // This was added everywhere we wait for two blocks, which is spread across three different places in the codebase
65
+ // Yes, we need to REFACTOR it at some point
66
+ const claim = await t.feeJuiceBridgeTestHarness.prepareTokensOnL1(bobsAddress);
67
+ const { claimSecret: secret, messageLeafIndex: index } = claim;
68
+ await t.feeJuiceContract.methods
69
+ .claim(bobsAddress, claim.claimAmount, secret, index)
70
+ .send({ from: bobsAddress })
71
+ .wait();
72
+ const [balance] = await t.getGasBalanceFn(bobsAddress);
73
+ expect(balance).toEqual(claim.claimAmount);
74
+ });
75
+ });