@aztec/end-to-end 0.0.1-commit.4d79d1f2d → 0.0.1-commit.5358163d3
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.
- package/dest/bench/client_flows/client_flows_benchmark.d.ts +1 -1
- package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -1
- package/dest/bench/client_flows/client_flows_benchmark.js +1 -0
- package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +2 -2
- package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts.map +1 -1
- package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.js +3 -3
- package/dest/e2e_epochs/epochs_test.d.ts +9 -7
- package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
- package/dest/e2e_epochs/epochs_test.js +53 -34
- package/dest/e2e_fees/fees_test.js +1 -1
- package/dest/e2e_p2p/p2p_network.d.ts +3 -2
- package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
- package/dest/e2e_p2p/p2p_network.js +21 -3
- package/dest/e2e_p2p/reqresp/utils.d.ts +3 -3
- package/dest/e2e_p2p/reqresp/utils.d.ts.map +1 -1
- package/dest/e2e_p2p/reqresp/utils.js +32 -8
- package/dest/e2e_p2p/shared.d.ts +15 -1
- package/dest/e2e_p2p/shared.d.ts.map +1 -1
- package/dest/e2e_p2p/shared.js +24 -1
- package/dest/e2e_token_contract/token_contract_test.d.ts +2 -2
- package/dest/e2e_token_contract/token_contract_test.d.ts.map +1 -1
- package/dest/e2e_token_contract/token_contract_test.js +3 -3
- package/dest/fixtures/authwit_proxy.d.ts +15 -0
- package/dest/fixtures/authwit_proxy.d.ts.map +1 -0
- package/dest/fixtures/authwit_proxy.js +30 -0
- package/dest/fixtures/e2e_prover_test.d.ts +3 -3
- package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
- package/dest/fixtures/e2e_prover_test.js +27 -34
- package/dest/fixtures/elu_monitor.d.ts +21 -0
- package/dest/fixtures/elu_monitor.d.ts.map +1 -0
- package/dest/fixtures/elu_monitor.js +102 -0
- package/dest/fixtures/fixtures.d.ts +5 -1
- package/dest/fixtures/fixtures.d.ts.map +1 -1
- package/dest/fixtures/fixtures.js +6 -0
- package/dest/fixtures/ha_setup.d.ts +1 -1
- package/dest/fixtures/ha_setup.d.ts.map +1 -1
- package/dest/fixtures/ha_setup.js +3 -1
- package/dest/fixtures/setup.d.ts +25 -9
- package/dest/fixtures/setup.d.ts.map +1 -1
- package/dest/fixtures/setup.js +52 -78
- package/dest/fixtures/setup_p2p_test.d.ts +6 -3
- package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
- package/dest/fixtures/setup_p2p_test.js +12 -9
- package/dest/fixtures/token_utils.d.ts +2 -2
- package/dest/fixtures/token_utils.d.ts.map +1 -1
- package/dest/fixtures/token_utils.js +3 -2
- package/dest/shared/index.d.ts +2 -1
- package/dest/shared/index.d.ts.map +1 -1
- package/dest/shared/index.js +1 -0
- package/dest/shared/jest_setup.js +41 -1
- package/dest/shared/mock_state_view.d.ts +86 -0
- package/dest/shared/mock_state_view.d.ts.map +1 -0
- package/dest/shared/mock_state_view.js +186 -0
- package/dest/shared/submit-transactions.d.ts +1 -1
- package/dest/shared/submit-transactions.d.ts.map +1 -1
- package/dest/spartan/setup_test_wallets.d.ts +8 -1
- package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
- package/dest/spartan/setup_test_wallets.js +28 -0
- package/dest/spartan/tx_metrics.js +1 -1
- package/dest/spartan/utils/bot.d.ts +3 -2
- package/dest/spartan/utils/bot.d.ts.map +1 -1
- package/dest/spartan/utils/bot.js +2 -1
- package/dest/spartan/utils/config.d.ts +4 -1
- package/dest/spartan/utils/config.d.ts.map +1 -1
- package/dest/spartan/utils/config.js +2 -1
- package/dest/spartan/utils/index.d.ts +3 -2
- package/dest/spartan/utils/index.d.ts.map +1 -1
- package/dest/spartan/utils/index.js +3 -1
- package/dest/spartan/utils/k8s.d.ts +3 -1
- package/dest/spartan/utils/k8s.d.ts.map +1 -1
- package/dest/spartan/utils/k8s.js +6 -0
- package/dest/spartan/utils/nodes.d.ts +4 -5
- package/dest/spartan/utils/nodes.d.ts.map +1 -1
- package/dest/spartan/utils/nodes.js +9 -9
- package/dest/test-wallet/test_wallet.d.ts +4 -3
- package/dest/test-wallet/test_wallet.d.ts.map +1 -1
- package/dest/test-wallet/test_wallet.js +3 -3
- package/dest/test-wallet/wallet_worker_script.d.ts +2 -0
- package/dest/test-wallet/wallet_worker_script.d.ts.map +1 -0
- package/dest/test-wallet/wallet_worker_script.js +48 -0
- package/dest/test-wallet/worker_wallet.d.ts +52 -0
- package/dest/test-wallet/worker_wallet.d.ts.map +1 -0
- package/dest/test-wallet/worker_wallet.js +151 -0
- package/dest/test-wallet/worker_wallet_schema.d.ts +274 -0
- package/dest/test-wallet/worker_wallet_schema.d.ts.map +1 -0
- package/dest/test-wallet/worker_wallet_schema.js +10 -0
- package/package.json +43 -44
- package/src/bench/client_flows/client_flows_benchmark.ts +1 -0
- package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +3 -3
- package/src/e2e_epochs/epochs_test.ts +66 -66
- package/src/e2e_fees/fees_test.ts +1 -1
- package/src/e2e_p2p/p2p_network.ts +27 -2
- package/src/e2e_p2p/reqresp/utils.ts +36 -8
- package/src/e2e_p2p/shared.ts +44 -1
- package/src/e2e_token_contract/token_contract_test.ts +3 -3
- package/src/fixtures/authwit_proxy.ts +50 -0
- package/src/fixtures/dumps/epoch_proof_result.json +1 -1
- package/src/fixtures/e2e_prover_test.ts +25 -35
- package/src/fixtures/elu_monitor.ts +126 -0
- package/src/fixtures/fixtures.ts +10 -0
- package/src/fixtures/ha_setup.ts +3 -1
- package/src/fixtures/setup.ts +72 -109
- package/src/fixtures/setup_p2p_test.ts +9 -17
- package/src/fixtures/token_utils.ts +2 -1
- package/src/shared/index.ts +1 -0
- package/src/shared/jest_setup.ts +51 -1
- package/src/shared/mock_state_view.ts +188 -0
- package/src/shared/submit-transactions.ts +4 -1
- package/src/spartan/setup_test_wallets.ts +55 -3
- package/src/spartan/tx_metrics.ts +1 -1
- package/src/spartan/utils/bot.ts +4 -1
- package/src/spartan/utils/config.ts +1 -0
- package/src/spartan/utils/index.ts +4 -0
- package/src/spartan/utils/k8s.ts +8 -0
- package/src/spartan/utils/nodes.ts +15 -10
- package/src/test-wallet/test_wallet.ts +5 -4
- package/src/test-wallet/wallet_worker_script.ts +60 -0
- package/src/test-wallet/worker_wallet.ts +213 -0
- package/src/test-wallet/worker_wallet_schema.ts +13 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Archiver } from '@aztec/archiver';
|
|
1
2
|
import { type AztecNodeConfig, AztecNodeService } from '@aztec/aztec-node';
|
|
2
3
|
import { getTimestampRangeForEpoch } from '@aztec/aztec.js/block';
|
|
3
4
|
import { getContractInstanceFromInstantiationParams } from '@aztec/aztec.js/contracts';
|
|
@@ -9,7 +10,8 @@ import { EpochCache } from '@aztec/epoch-cache';
|
|
|
9
10
|
import { createExtendedL1Client } from '@aztec/ethereum/client';
|
|
10
11
|
import { DefaultL1ContractsConfig } from '@aztec/ethereum/config';
|
|
11
12
|
import { RollupContract } from '@aztec/ethereum/contracts';
|
|
12
|
-
import {
|
|
13
|
+
import { Delayer, createDelayer, waitUntilL1Timestamp, wrapClientWithDelayer } from '@aztec/ethereum/l1-tx-utils';
|
|
14
|
+
import { ChainMonitor } from '@aztec/ethereum/test';
|
|
13
15
|
import type { ExtendedViemWalletClient } from '@aztec/ethereum/types';
|
|
14
16
|
import { BlockNumber, CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types';
|
|
15
17
|
import { SecretValue } from '@aztec/foundation/config';
|
|
@@ -20,16 +22,9 @@ import { sleep } from '@aztec/foundation/sleep';
|
|
|
20
22
|
import { SpamContract } from '@aztec/noir-test-contracts.js/Spam';
|
|
21
23
|
import { TestContract } from '@aztec/noir-test-contracts.js/Test';
|
|
22
24
|
import { getMockPubSubP2PServiceFactory } from '@aztec/p2p/test-helpers';
|
|
23
|
-
import {
|
|
24
|
-
import type { TestProverNode } from '@aztec/prover-node/test';
|
|
25
|
+
import type { ProverNodeConfig } from '@aztec/prover-node';
|
|
25
26
|
import type { PXEConfig } from '@aztec/pxe/config';
|
|
26
|
-
import {
|
|
27
|
-
type SequencerClient,
|
|
28
|
-
type SequencerEvents,
|
|
29
|
-
type SequencerPublisher,
|
|
30
|
-
SequencerState,
|
|
31
|
-
} from '@aztec/sequencer-client';
|
|
32
|
-
import type { TestSequencerClient } from '@aztec/sequencer-client/test';
|
|
27
|
+
import { type SequencerClient, type SequencerEvents, SequencerState } from '@aztec/sequencer-client';
|
|
33
28
|
import { type BlockParameter, EthAddress } from '@aztec/stdlib/block';
|
|
34
29
|
import { type L1RollupConstants, getProofSubmissionDeadlineTimestamp } from '@aztec/stdlib/epoch-helpers';
|
|
35
30
|
import { tryStop } from '@aztec/stdlib/interfaces/server';
|
|
@@ -46,7 +41,7 @@ import {
|
|
|
46
41
|
setup,
|
|
47
42
|
} from '../fixtures/utils.js';
|
|
48
43
|
|
|
49
|
-
export const
|
|
44
|
+
export const WORLD_STATE_CHECKPOINT_HISTORY = 2;
|
|
50
45
|
export const WORLD_STATE_BLOCK_CHECK_INTERVAL = 50;
|
|
51
46
|
export const ARCHIVER_POLL_INTERVAL = 50;
|
|
52
47
|
export const DEFAULT_L1_BLOCK_TIME = process.env.CI ? 12 : 8;
|
|
@@ -81,7 +76,7 @@ export class EpochsTestContext {
|
|
|
81
76
|
public proverDelayer!: Delayer;
|
|
82
77
|
public sequencerDelayer!: Delayer;
|
|
83
78
|
|
|
84
|
-
public proverNodes:
|
|
79
|
+
public proverNodes: AztecNodeService[] = [];
|
|
85
80
|
public nodes: AztecNodeService[] = [];
|
|
86
81
|
|
|
87
82
|
public epochDuration!: number;
|
|
@@ -147,7 +142,7 @@ export class EpochsTestContext {
|
|
|
147
142
|
// using the prover's eth address if the proverId is used for something in the rollup contract
|
|
148
143
|
// Use numeric EthAddress for deterministic prover id
|
|
149
144
|
proverId: EthAddress.fromNumber(1),
|
|
150
|
-
|
|
145
|
+
worldStateCheckpointHistory: WORLD_STATE_CHECKPOINT_HISTORY,
|
|
151
146
|
exitDelaySeconds: DefaultL1ContractsConfig.exitDelaySeconds,
|
|
152
147
|
slasherFlavor: 'none',
|
|
153
148
|
l1PublishingTime,
|
|
@@ -169,17 +164,8 @@ export class EpochsTestContext {
|
|
|
169
164
|
// Loop that tracks L1 and L2 block numbers and logs whenever there's a new one.
|
|
170
165
|
this.monitor = new ChainMonitor(this.rollup, context.dateProvider, this.logger).start();
|
|
171
166
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
this.proverDelayer = context.proverNode
|
|
175
|
-
? (((context.proverNode as TestProverNode).publisher as ProverNodePublisher).l1TxUtils as DelayedTxUtils).delayer!
|
|
176
|
-
: undefined!;
|
|
177
|
-
this.sequencerDelayer = context.sequencer
|
|
178
|
-
? (
|
|
179
|
-
((context.sequencer as TestSequencerClient).sequencer.publisher as SequencerPublisher)
|
|
180
|
-
.l1TxUtils as DelayedTxUtils
|
|
181
|
-
).delayer!
|
|
182
|
-
: undefined!;
|
|
167
|
+
this.proverDelayer = context.proverDelayer!;
|
|
168
|
+
this.sequencerDelayer = context.sequencerDelayer!;
|
|
183
169
|
|
|
184
170
|
if ((context.proverNode && !this.proverDelayer) || (context.sequencer && !this.sequencerDelayer)) {
|
|
185
171
|
throw new Error(`Could not find prover or sequencer delayer`);
|
|
@@ -214,26 +200,29 @@ export class EpochsTestContext {
|
|
|
214
200
|
const proverNodePrivateKey = this.getNextPrivateKey();
|
|
215
201
|
const proverIndex = this.proverNodes.length + 1;
|
|
216
202
|
const { mockGossipSubNetwork } = this.context;
|
|
217
|
-
const proverNode = await withLoggerBindings({ actor: `prover-${proverIndex}` }, () =>
|
|
203
|
+
const { proverNode } = await withLoggerBindings({ actor: `prover-${proverIndex}` }, () =>
|
|
218
204
|
createAndSyncProverNode(
|
|
219
205
|
proverNodePrivateKey,
|
|
220
206
|
{
|
|
221
207
|
...this.context.config,
|
|
222
208
|
p2pEnabled: this.context.config.p2pEnabled || mockGossipSubNetwork !== undefined,
|
|
223
|
-
},
|
|
224
|
-
{
|
|
225
|
-
dataDirectory: join(this.context.config.dataDirectory!, randomBytes(8).toString('hex')),
|
|
226
209
|
proverId: EthAddress.fromNumber(proverIndex),
|
|
227
210
|
dontStart: opts.dontStart,
|
|
228
211
|
...opts,
|
|
229
212
|
},
|
|
230
|
-
|
|
231
|
-
|
|
213
|
+
{
|
|
214
|
+
dataDirectory: join(this.context.config.dataDirectory!, randomBytes(8).toString('hex')),
|
|
215
|
+
},
|
|
232
216
|
{
|
|
233
217
|
dateProvider: this.context.dateProvider,
|
|
234
|
-
p2pClientDeps:
|
|
235
|
-
|
|
236
|
-
:
|
|
218
|
+
p2pClientDeps: {
|
|
219
|
+
p2pServiceFactory: mockGossipSubNetwork ? getMockPubSubP2PServiceFactory(mockGossipSubNetwork) : undefined,
|
|
220
|
+
rpcTxProviders: [this.context.aztecNode],
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
prefilledPublicData: this.context.prefilledPublicData ?? [],
|
|
225
|
+
dontStart: opts.dontStart,
|
|
237
226
|
},
|
|
238
227
|
),
|
|
239
228
|
);
|
|
@@ -248,15 +237,13 @@ export class EpochsTestContext {
|
|
|
248
237
|
|
|
249
238
|
public createValidatorNode(
|
|
250
239
|
privateKeys: `0x${string}`[],
|
|
251
|
-
opts: Partial<AztecNodeConfig> & {
|
|
240
|
+
opts: Partial<AztecNodeConfig> & { dontStartSequencer?: boolean } = {},
|
|
252
241
|
) {
|
|
253
242
|
this.logger.warn('Creating and syncing a validator node...');
|
|
254
243
|
return this.createNode({ ...opts, disableValidator: false, validatorPrivateKeys: new SecretValue(privateKeys) });
|
|
255
244
|
}
|
|
256
245
|
|
|
257
|
-
private async createNode(
|
|
258
|
-
opts: Partial<AztecNodeConfig> & { txDelayerMaxInclusionTimeIntoSlot?: number; dontStartSequencer?: boolean } = {},
|
|
259
|
-
) {
|
|
246
|
+
private async createNode(opts: Partial<AztecNodeConfig> & { dontStartSequencer?: boolean } = {}) {
|
|
260
247
|
const nodeIndex = this.nodes.length + 1;
|
|
261
248
|
const actorPrefix = opts.disableValidator ? 'node' : 'validator';
|
|
262
249
|
const { mockGossipSubNetwork } = this.context;
|
|
@@ -285,26 +272,6 @@ export class EpochsTestContext {
|
|
|
285
272
|
),
|
|
286
273
|
);
|
|
287
274
|
|
|
288
|
-
// REFACTOR: We're getting too much into the internals of the sequencer here.
|
|
289
|
-
// We should have a single method for constructing an aztec node that returns a TestAztecNodeService
|
|
290
|
-
// which directly exposes the delayer and sets any test config.
|
|
291
|
-
if (opts.txDelayerMaxInclusionTimeIntoSlot !== undefined) {
|
|
292
|
-
this.logger.info(
|
|
293
|
-
`Setting tx delayer max inclusion time into slot to ${opts.txDelayerMaxInclusionTimeIntoSlot} seconds`,
|
|
294
|
-
);
|
|
295
|
-
// 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.
|
|
296
|
-
// The delayer needs a wallet (a client that can sign), so we have to create one here.
|
|
297
|
-
const l1Client = createExtendedL1Client(
|
|
298
|
-
resolvedConfig.l1RpcUrls!,
|
|
299
|
-
resolvedConfig.publisherPrivateKeys![0]!.getValue(),
|
|
300
|
-
);
|
|
301
|
-
const sequencer = node.getSequencer() as TestSequencerClient;
|
|
302
|
-
const publisher = sequencer.sequencer.publisher;
|
|
303
|
-
const delayed = DelayedTxUtils.fromL1TxUtils(publisher.l1TxUtils, this.L1_BLOCK_TIME_IN_S, l1Client);
|
|
304
|
-
delayed.delayer!.setMaxInclusionTimeIntoSlot(opts.txDelayerMaxInclusionTimeIntoSlot);
|
|
305
|
-
publisher.l1TxUtils = delayed;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
275
|
this.nodes.push(node);
|
|
309
276
|
return node;
|
|
310
277
|
}
|
|
@@ -356,7 +323,10 @@ export class EpochsTestContext {
|
|
|
356
323
|
this.logger.info(`Waiting until last slot of submission window for epoch ${epochNumber} at ${date}`, {
|
|
357
324
|
oneSlotBefore,
|
|
358
325
|
});
|
|
359
|
-
|
|
326
|
+
// Use a timeout that accounts for the full proof submission window
|
|
327
|
+
const proofSubmissionWindowDuration =
|
|
328
|
+
this.constants.proofSubmissionEpochs * this.epochDuration * this.L2_SLOT_DURATION_IN_S;
|
|
329
|
+
await waitUntilL1Timestamp(this.l1Client, oneSlotBefore, undefined, proofSubmissionWindowDuration * 2);
|
|
360
330
|
}
|
|
361
331
|
|
|
362
332
|
/** Waits for the aztec node to sync to the target block number. */
|
|
@@ -408,15 +378,13 @@ export class EpochsTestContext {
|
|
|
408
378
|
|
|
409
379
|
/** Creates an L1 client using a fresh account with funds from anvil, with a tx delayer already set up. */
|
|
410
380
|
public async createL1Client() {
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
this.l1Client.chain,
|
|
416
|
-
),
|
|
417
|
-
this.context.dateProvider,
|
|
418
|
-
{ ethereumSlotDuration: this.L1_BLOCK_TIME_IN_S },
|
|
381
|
+
const rawClient = createExtendedL1Client(
|
|
382
|
+
[...this.l1Client.chain.rpcUrls.default.http],
|
|
383
|
+
privateKeyToAccount(this.getNextPrivateKey()),
|
|
384
|
+
this.l1Client.chain,
|
|
419
385
|
);
|
|
386
|
+
const delayer = createDelayer(this.context.dateProvider, { ethereumSlotDuration: this.L1_BLOCK_TIME_IN_S }, {});
|
|
387
|
+
const client = wrapClientWithDelayer(rawClient, delayer);
|
|
420
388
|
expect(await client.getBalance({ address: client.account.address })).toBeGreaterThan(0n);
|
|
421
389
|
return { client, delayer };
|
|
422
390
|
}
|
|
@@ -433,6 +401,38 @@ export class EpochsTestContext {
|
|
|
433
401
|
expect(result).toBe(expectedSuccess);
|
|
434
402
|
}
|
|
435
403
|
|
|
404
|
+
/** Verifies at least one checkpoint has the target number of blocks (for MBPS validation). */
|
|
405
|
+
public async assertMultipleBlocksPerSlot(targetBlockCount: number) {
|
|
406
|
+
const archiver = (this.context.aztecNode as AztecNodeService).getBlockSource() as Archiver;
|
|
407
|
+
const checkpoints = await archiver.getCheckpoints(CheckpointNumber(1), 50);
|
|
408
|
+
|
|
409
|
+
this.logger.warn(`Retrieved ${checkpoints.length} checkpoints from archiver`, {
|
|
410
|
+
checkpoints: checkpoints.map(pc => pc.checkpoint.getStats()),
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
let expectedBlockNumber = checkpoints[0].checkpoint.blocks[0].number;
|
|
414
|
+
let targetFound = false;
|
|
415
|
+
|
|
416
|
+
for (const checkpoint of checkpoints) {
|
|
417
|
+
const blockCount = checkpoint.checkpoint.blocks.length;
|
|
418
|
+
targetFound = targetFound || blockCount >= targetBlockCount;
|
|
419
|
+
|
|
420
|
+
this.logger.verbose(`Checkpoint ${checkpoint.checkpoint.number} has ${blockCount} blocks`, {
|
|
421
|
+
checkpoint: checkpoint.checkpoint.getStats(),
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
for (let i = 0; i < blockCount; i++) {
|
|
425
|
+
const block = checkpoint.checkpoint.blocks[i];
|
|
426
|
+
expect(block.indexWithinCheckpoint).toBe(i);
|
|
427
|
+
expect(block.checkpointNumber).toBe(checkpoint.checkpoint.number);
|
|
428
|
+
expect(block.number).toBe(expectedBlockNumber);
|
|
429
|
+
expectedBlockNumber++;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
expect(targetFound).toBe(true);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
436
|
public watchSequencerEvents(
|
|
437
437
|
sequencers: SequencerClient[],
|
|
438
438
|
getMetadata: (i: number) => Record<string, any> = () => ({}),
|
|
@@ -275,7 +275,7 @@ export class FeesTest {
|
|
|
275
275
|
|
|
276
276
|
// @todo @lherskind As we deal with #13601
|
|
277
277
|
// Right now the value is from `FeeLib.sol`
|
|
278
|
-
const L1_GAS_PER_EPOCH_VERIFIED =
|
|
278
|
+
const L1_GAS_PER_EPOCH_VERIFIED = 3600000n;
|
|
279
279
|
|
|
280
280
|
// We round up
|
|
281
281
|
const mulDiv = (a: bigint, b: bigint, c: bigint) => (a * b) / c + ((a * b) % c > 0n ? 1n : 0n);
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
import type { Operator } from '@aztec/ethereum/deploy-aztec-l1-contracts';
|
|
13
13
|
import { deployL1Contract } from '@aztec/ethereum/deploy-l1-contract';
|
|
14
14
|
import { MultiAdderArtifact } from '@aztec/ethereum/l1-artifacts';
|
|
15
|
-
import {
|
|
15
|
+
import { createL1TxUtils } from '@aztec/ethereum/l1-tx-utils';
|
|
16
16
|
import { ChainMonitor } from '@aztec/ethereum/test';
|
|
17
17
|
import type { ExtendedViemWalletClient, ViemClient } from '@aztec/ethereum/types';
|
|
18
18
|
import { EpochNumber } from '@aztec/foundation/branded-types';
|
|
@@ -25,6 +25,7 @@ import type { BootstrapNode } from '@aztec/p2p/bootstrap';
|
|
|
25
25
|
import { createBootstrapNodeFromPrivateKey, getBootstrapNodeEnr } from '@aztec/p2p/test-helpers';
|
|
26
26
|
import { tryStop } from '@aztec/stdlib/interfaces/server';
|
|
27
27
|
import { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
|
|
28
|
+
import { TopicType } from '@aztec/stdlib/p2p';
|
|
28
29
|
import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
|
|
29
30
|
import { ZkPassportProofParams } from '@aztec/stdlib/zkpassport';
|
|
30
31
|
import { getGenesisValues } from '@aztec/world-state/testing';
|
|
@@ -343,7 +344,7 @@ export class P2PNetworkTest {
|
|
|
343
344
|
}
|
|
344
345
|
|
|
345
346
|
private async _sendDummyTx(l1Client: ExtendedViemWalletClient) {
|
|
346
|
-
const l1TxUtils =
|
|
347
|
+
const l1TxUtils = createL1TxUtils(l1Client);
|
|
347
348
|
return await l1TxUtils.sendAndMonitorTransaction({
|
|
348
349
|
to: l1Client.account!.address,
|
|
349
350
|
value: 1n,
|
|
@@ -406,6 +407,7 @@ export class P2PNetworkTest {
|
|
|
406
407
|
expectedNodeCount?: number,
|
|
407
408
|
timeoutSeconds = 30,
|
|
408
409
|
checkIntervalSeconds = 0.1,
|
|
410
|
+
topics: TopicType[] = [TopicType.tx],
|
|
409
411
|
) {
|
|
410
412
|
const nodeCount = expectedNodeCount ?? nodes.length;
|
|
411
413
|
const minPeerCount = nodeCount - 1;
|
|
@@ -431,6 +433,29 @@ export class P2PNetworkTest {
|
|
|
431
433
|
);
|
|
432
434
|
|
|
433
435
|
this.logger.warn('All nodes connected to P2P mesh');
|
|
436
|
+
|
|
437
|
+
// Wait for GossipSub mesh to form for all specified topics.
|
|
438
|
+
// We only require at least 1 mesh peer per node because GossipSub
|
|
439
|
+
// stops grafting once it reaches Dlo peers and won't fill the mesh to all available peers.
|
|
440
|
+
for (const topic of topics) {
|
|
441
|
+
this.logger.warn(`Waiting for GossipSub mesh to form for ${topic} topic...`);
|
|
442
|
+
await Promise.all(
|
|
443
|
+
nodes.map(async (node, index) => {
|
|
444
|
+
const p2p = node.getP2P();
|
|
445
|
+
await retryUntil(
|
|
446
|
+
async () => {
|
|
447
|
+
const meshPeers = await p2p.getGossipMeshPeerCount(topic);
|
|
448
|
+
this.logger.debug(`Node ${index} has ${meshPeers} gossip mesh peers for ${topic} topic`);
|
|
449
|
+
return meshPeers >= 1 ? true : undefined;
|
|
450
|
+
},
|
|
451
|
+
`Node ${index} to have gossip mesh peers for ${topic} topic`,
|
|
452
|
+
timeoutSeconds,
|
|
453
|
+
checkIntervalSeconds,
|
|
454
|
+
);
|
|
455
|
+
}),
|
|
456
|
+
);
|
|
457
|
+
this.logger.warn(`All nodes have gossip mesh peers for ${topic} topic`);
|
|
458
|
+
}
|
|
434
459
|
}
|
|
435
460
|
|
|
436
461
|
async teardown() {
|
|
@@ -3,24 +3,24 @@ import { createLogger } from '@aztec/aztec.js/log';
|
|
|
3
3
|
import { waitForTx } from '@aztec/aztec.js/node';
|
|
4
4
|
import { Tx } from '@aztec/aztec.js/tx';
|
|
5
5
|
import { RollupContract } from '@aztec/ethereum/contracts';
|
|
6
|
-
import { SlotNumber } from '@aztec/foundation/branded-types';
|
|
6
|
+
import { CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
7
7
|
import { timesAsync } from '@aztec/foundation/collection';
|
|
8
8
|
import { retryUntil } from '@aztec/foundation/retry';
|
|
9
9
|
|
|
10
|
-
import { jest } from '@jest/globals';
|
|
10
|
+
import { expect, jest } from '@jest/globals';
|
|
11
11
|
import fs from 'fs';
|
|
12
12
|
import os from 'os';
|
|
13
13
|
import path from 'path';
|
|
14
14
|
|
|
15
|
-
import { shouldCollectMetrics } from '../../fixtures/fixtures.js';
|
|
15
|
+
import { getBootNodeUdpPort, shouldCollectMetrics } from '../../fixtures/fixtures.js';
|
|
16
16
|
import { createNodes } from '../../fixtures/setup_p2p_test.js';
|
|
17
|
-
import { P2PNetworkTest,
|
|
17
|
+
import { P2PNetworkTest, WAIT_FOR_TX_TIMEOUT } from '../p2p_network.js';
|
|
18
18
|
import { prepareTransactions } from '../shared.js';
|
|
19
19
|
|
|
20
20
|
// Don't set this to a higher value than 9 because each node will use a different L1 publisher account and anvil seeds
|
|
21
21
|
export const NUM_VALIDATORS = 6;
|
|
22
|
-
export const NUM_TXS_PER_NODE =
|
|
23
|
-
export const BOOT_NODE_UDP_PORT =
|
|
22
|
+
export const NUM_TXS_PER_NODE = 4;
|
|
23
|
+
export const BOOT_NODE_UDP_PORT = getBootNodeUdpPort();
|
|
24
24
|
|
|
25
25
|
export const createReqrespDataDir = () => fs.mkdtempSync(path.join(os.tmpdir(), 'reqresp-'));
|
|
26
26
|
|
|
@@ -38,8 +38,14 @@ export async function createReqrespTest(options: ReqrespOptions = {}): Promise<P
|
|
|
38
38
|
// To collect metrics - run in aztec-packages `docker compose --profile metrics up`
|
|
39
39
|
metricsPort: shouldCollectMetrics(),
|
|
40
40
|
initialConfig: {
|
|
41
|
-
|
|
42
|
-
aztecSlotDuration:
|
|
41
|
+
ethereumSlotDuration: 8,
|
|
42
|
+
aztecSlotDuration: 36,
|
|
43
|
+
blockDurationMs: 6000,
|
|
44
|
+
l1PublishingTime: 8,
|
|
45
|
+
minTxsPerBlock: 1,
|
|
46
|
+
maxTxsPerBlock: 2,
|
|
47
|
+
enforceTimeTable: true,
|
|
48
|
+
aztecProofSubmissionEpochs: 1024, // effectively do not reorg
|
|
43
49
|
...(disableStatusHandshake ? { p2pDisableStatusHandshake: true } : {}),
|
|
44
50
|
listenAddress: '127.0.0.1',
|
|
45
51
|
aztecEpochDuration: 64, // stable committee
|
|
@@ -170,6 +176,28 @@ export async function runReqrespTxTest(params: {
|
|
|
170
176
|
|
|
171
177
|
t.logger.info('All transactions mined');
|
|
172
178
|
|
|
179
|
+
// Assert that multiple blocks were built for at least one slot
|
|
180
|
+
t.logger.info('Verifying multiple blocks for at least one checkpoint');
|
|
181
|
+
const checkpoints = await nodes[0].getCheckpoints(CheckpointNumber(1), 50);
|
|
182
|
+
expect(checkpoints.length).toBeGreaterThan(0);
|
|
183
|
+
|
|
184
|
+
let mbpsFound = false;
|
|
185
|
+
let expectedBlockNumber = checkpoints[0].checkpoint.blocks[0].number;
|
|
186
|
+
|
|
187
|
+
for (const published of checkpoints) {
|
|
188
|
+
const blockCount = published.checkpoint.blocks.length;
|
|
189
|
+
mbpsFound = mbpsFound || blockCount >= 2;
|
|
190
|
+
|
|
191
|
+
for (let i = 0; i < blockCount; i++) {
|
|
192
|
+
const block = published.checkpoint.blocks[i];
|
|
193
|
+
expect(block.indexWithinCheckpoint).toBe(i);
|
|
194
|
+
expect(block.checkpointNumber).toBe(published.checkpoint.number);
|
|
195
|
+
expect(block.number).toBe(expectedBlockNumber);
|
|
196
|
+
expectedBlockNumber++;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
expect(mbpsFound).toBe(true);
|
|
173
201
|
return nodes;
|
|
174
202
|
}
|
|
175
203
|
|
package/src/e2e_p2p/shared.ts
CHANGED
|
@@ -6,12 +6,13 @@ import { Fr } from '@aztec/aztec.js/fields';
|
|
|
6
6
|
import type { Logger } from '@aztec/aztec.js/log';
|
|
7
7
|
import { TxHash } from '@aztec/aztec.js/tx';
|
|
8
8
|
import type { RollupCheatCodes } from '@aztec/aztec/testing';
|
|
9
|
+
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
9
10
|
import type {
|
|
10
11
|
EmpireSlashingProposerContract,
|
|
11
12
|
RollupContract,
|
|
12
13
|
TallySlashingProposerContract,
|
|
13
14
|
} from '@aztec/ethereum/contracts';
|
|
14
|
-
import { EpochNumber } from '@aztec/foundation/branded-types';
|
|
15
|
+
import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
15
16
|
import { timesAsync, unique } from '@aztec/foundation/collection';
|
|
16
17
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
17
18
|
import { retryUntil } from '@aztec/foundation/retry';
|
|
@@ -150,6 +151,48 @@ export async function awaitCommitteeExists({
|
|
|
150
151
|
return committee!.map(c => c.toString() as `0x${string}`);
|
|
151
152
|
}
|
|
152
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Advance epochs until we find one where the target proposer is selected for at least one slot.
|
|
156
|
+
* With N validators and M slots per epoch, a specific proposer may not be selected in any given epoch.
|
|
157
|
+
* For example, with 4 validators and 2 slots/epoch, there is about a 44% chance per epoch.
|
|
158
|
+
*/
|
|
159
|
+
export async function awaitEpochWithProposer({
|
|
160
|
+
epochCache,
|
|
161
|
+
cheatCodes,
|
|
162
|
+
targetProposer,
|
|
163
|
+
logger,
|
|
164
|
+
maxAttempts = 20,
|
|
165
|
+
}: {
|
|
166
|
+
epochCache: EpochCacheInterface;
|
|
167
|
+
cheatCodes: RollupCheatCodes;
|
|
168
|
+
targetProposer: EthAddress;
|
|
169
|
+
logger: Logger;
|
|
170
|
+
maxAttempts?: number;
|
|
171
|
+
}): Promise<void> {
|
|
172
|
+
const { epochDuration } = await cheatCodes.getConfig();
|
|
173
|
+
|
|
174
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
175
|
+
const currentEpoch = await cheatCodes.getEpoch();
|
|
176
|
+
const startSlot = Number(currentEpoch) * Number(epochDuration);
|
|
177
|
+
const endSlot = startSlot + Number(epochDuration);
|
|
178
|
+
|
|
179
|
+
logger.info(`Checking epoch ${currentEpoch} (slots ${startSlot}-${endSlot - 1}) for proposer ${targetProposer}`);
|
|
180
|
+
|
|
181
|
+
for (let s = startSlot; s < endSlot; s++) {
|
|
182
|
+
const proposer = await epochCache.getProposerAttesterAddressInSlot(SlotNumber(s));
|
|
183
|
+
if (proposer && proposer.equals(targetProposer)) {
|
|
184
|
+
logger.warn(`Found target proposer ${targetProposer} in slot ${s} of epoch ${currentEpoch}`);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
logger.info(`Target proposer not found in epoch ${currentEpoch}, advancing to next epoch`);
|
|
190
|
+
await cheatCodes.advanceToNextEpoch();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
throw new Error(`Target proposer ${targetProposer} not found in any slot after ${maxAttempts} epoch attempts`);
|
|
194
|
+
}
|
|
195
|
+
|
|
153
196
|
export async function awaitOffenseDetected({
|
|
154
197
|
logger,
|
|
155
198
|
nodeAdmin,
|
|
@@ -26,7 +26,7 @@ export class TokenContractTest {
|
|
|
26
26
|
node!: AztecNode;
|
|
27
27
|
|
|
28
28
|
badAccount!: InvalidAccountContract;
|
|
29
|
-
|
|
29
|
+
authwitProxy!: GenericProxyContract;
|
|
30
30
|
wallet!: TestWallet;
|
|
31
31
|
adminAddress!: AztecAddress;
|
|
32
32
|
account1Address!: AztecAddress;
|
|
@@ -98,8 +98,8 @@ export class TokenContractTest {
|
|
|
98
98
|
// (so their notes are in scope), but msg_sender in the target must differ from the note owner
|
|
99
99
|
// to trigger authwit validation. The proxy forwards calls so that msg_sender != tx sender.
|
|
100
100
|
this.logger.verbose(`Deploying generic proxy...`);
|
|
101
|
-
this.
|
|
102
|
-
this.logger.verbose(`Deployed to ${this.
|
|
101
|
+
this.authwitProxy = await GenericProxyContract.deploy(this.wallet).send({ from: this.adminAddress });
|
|
102
|
+
this.logger.verbose(`Deployed to ${this.authwitProxy.address}.`);
|
|
103
103
|
|
|
104
104
|
this.tokenSim = new TokenSimulator(this.asset, this.wallet, this.adminAddress, this.logger, [
|
|
105
105
|
this.adminAddress,
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ContractFunctionInteraction,
|
|
3
|
+
SendInteractionOptions,
|
|
4
|
+
SimulateInteractionOptions,
|
|
5
|
+
} from '@aztec/aztec.js/contracts';
|
|
6
|
+
import type { GenericProxyContract } from '@aztec/noir-test-contracts.js/GenericProxy';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Builds a proxy forwarding call from an action, selecting the right forward_private_N method.
|
|
10
|
+
*/
|
|
11
|
+
async function buildProxyCall(proxy: GenericProxyContract, action: ContractFunctionInteraction) {
|
|
12
|
+
const call = await action.getFunctionCall();
|
|
13
|
+
const argCount = call.args.length;
|
|
14
|
+
if (argCount === 2) {
|
|
15
|
+
return proxy.methods.forward_private_2(call.to, call.selector, call.args);
|
|
16
|
+
} else if (argCount === 3) {
|
|
17
|
+
return proxy.methods.forward_private_3(call.to, call.selector, call.args);
|
|
18
|
+
} else if (argCount === 4) {
|
|
19
|
+
return proxy.methods.forward_private_4(call.to, call.selector, call.args);
|
|
20
|
+
}
|
|
21
|
+
throw new Error(`No forward_private_${argCount} method on proxy`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Sends a contract call through the authwit proxy.
|
|
26
|
+
* The proxy becomes msg_sender in the target (triggering authwit validation),
|
|
27
|
+
* while the actual tx sender retains their keys in scope.
|
|
28
|
+
*/
|
|
29
|
+
export async function sendThroughAuthwitProxy(
|
|
30
|
+
proxy: GenericProxyContract,
|
|
31
|
+
action: ContractFunctionInteraction,
|
|
32
|
+
options: SendInteractionOptions,
|
|
33
|
+
) {
|
|
34
|
+
const proxyCall = await buildProxyCall(proxy, action);
|
|
35
|
+
return proxyCall.send(options);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Simulates a contract call through the authwit proxy.
|
|
40
|
+
* The proxy becomes msg_sender in the target (triggering authwit validation),
|
|
41
|
+
* while the actual tx sender retains their keys in scope.
|
|
42
|
+
*/
|
|
43
|
+
export async function simulateThroughAuthwitProxy(
|
|
44
|
+
proxy: GenericProxyContract,
|
|
45
|
+
action: ContractFunctionInteraction,
|
|
46
|
+
options: SimulateInteractionOptions,
|
|
47
|
+
) {
|
|
48
|
+
const proxyCall = await buildProxyCall(proxy, action);
|
|
49
|
+
return proxyCall.simulate(options);
|
|
50
|
+
}
|