@aztec/end-to-end 0.0.1-commit.1bb068fb5 → 0.0.1-commit.1de2a32
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 +16 -8
- package/dest/bench/utils.d.ts +1 -1
- package/dest/bench/utils.d.ts.map +1 -1
- package/dest/bench/utils.js +6 -3
- package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +1 -1
- 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 +14 -14
- 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.d.ts +1 -1
- package/dest/e2e_fees/fees_test.d.ts.map +1 -1
- package/dest/e2e_fees/fees_test.js +13 -6
- package/dest/e2e_nested_contract/nested_contract_test.d.ts +1 -1
- package/dest/e2e_nested_contract/nested_contract_test.d.ts.map +1 -1
- package/dest/e2e_nested_contract/nested_contract_test.js +4 -6
- package/dest/e2e_p2p/p2p_network.d.ts +4 -3
- package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
- package/dest/e2e_p2p/p2p_network.js +24 -7
- 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 +25 -2
- package/dest/e2e_token_contract/token_contract_test.d.ts +1 -1
- package/dest/e2e_token_contract/token_contract_test.d.ts.map +1 -1
- package/dest/e2e_token_contract/token_contract_test.js +11 -11
- package/dest/fixtures/authwit_proxy.d.ts +3 -3
- package/dest/fixtures/authwit_proxy.d.ts.map +1 -1
- 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 +33 -40
- 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/setup.d.ts +25 -9
- package/dest/fixtures/setup.d.ts.map +1 -1
- package/dest/fixtures/setup.js +49 -80
- 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 +5 -4
- package/dest/shared/cross_chain_test_harness.d.ts +1 -1
- package/dest/shared/cross_chain_test_harness.d.ts.map +1 -1
- package/dest/shared/cross_chain_test_harness.js +13 -13
- package/dest/shared/gas_portal_test_harness.js +2 -2
- package/dest/shared/jest_setup.js +41 -1
- package/dest/shared/submit-transactions.js +1 -1
- package/dest/shared/uniswap_l1_l2.d.ts +1 -1
- package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
- package/dest/shared/uniswap_l1_l2.js +5 -5
- package/dest/simulators/lending_simulator.d.ts +1 -1
- package/dest/simulators/lending_simulator.d.ts.map +1 -1
- package/dest/simulators/lending_simulator.js +2 -2
- package/dest/simulators/token_simulator.d.ts +1 -1
- package/dest/simulators/token_simulator.d.ts.map +1 -1
- package/dest/simulators/token_simulator.js +2 -2
- 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 +32 -3
- 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.js +1 -1
- 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 +38 -30
- package/src/bench/utils.ts +7 -2
- package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +18 -14
- package/src/e2e_epochs/epochs_test.ts +66 -66
- package/src/e2e_fees/fees_test.ts +13 -6
- package/src/e2e_nested_contract/nested_contract_test.ts +6 -4
- package/src/e2e_p2p/p2p_network.ts +31 -5
- package/src/e2e_p2p/reqresp/utils.ts +36 -8
- package/src/e2e_p2p/shared.ts +45 -2
- package/src/e2e_token_contract/token_contract_test.ts +16 -8
- package/src/fixtures/dumps/epoch_proof_result.json +1 -1
- package/src/fixtures/e2e_prover_test.ts +36 -40
- package/src/fixtures/elu_monitor.ts +126 -0
- package/src/fixtures/fixtures.ts +10 -0
- package/src/fixtures/setup.ts +68 -110
- package/src/fixtures/setup_p2p_test.ts +9 -17
- package/src/fixtures/token_utils.ts +6 -3
- package/src/shared/cross_chain_test_harness.ts +13 -9
- package/src/shared/gas_portal_test_harness.ts +1 -1
- package/src/shared/jest_setup.ts +51 -1
- package/src/shared/submit-transactions.ts +1 -1
- package/src/shared/uniswap_l1_l2.ts +6 -4
- package/src/simulators/lending_simulator.ts +4 -2
- package/src/simulators/token_simulator.ts +6 -2
- package/src/spartan/setup_test_wallets.ts +56 -11
- package/src/spartan/tx_metrics.ts +1 -1
- package/src/spartan/utils/bot.ts +3 -0
- 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 +1 -1
- 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,5 +1,5 @@
|
|
|
1
1
|
import type { InitialAccountData } from '@aztec/accounts/testing';
|
|
2
|
-
import {
|
|
2
|
+
import { AztecNodeService } from '@aztec/aztec-node';
|
|
3
3
|
import { AztecAddress, EthAddress } from '@aztec/aztec.js/addresses';
|
|
4
4
|
import { type Logger, createLogger } from '@aztec/aztec.js/log';
|
|
5
5
|
import type { AztecNode } from '@aztec/aztec.js/node';
|
|
@@ -11,13 +11,11 @@ import {
|
|
|
11
11
|
TestCircuitVerifier,
|
|
12
12
|
} from '@aztec/bb-prover';
|
|
13
13
|
import { BackendType, Barretenberg } from '@aztec/bb.js';
|
|
14
|
-
import { createBlobClientWithFileStores } from '@aztec/blob-client/client';
|
|
15
14
|
import type { DeployAztecL1ContractsReturnType } from '@aztec/ethereum/deploy-aztec-l1-contracts';
|
|
16
15
|
import { Buffer32 } from '@aztec/foundation/buffer';
|
|
17
16
|
import { SecretValue } from '@aztec/foundation/config';
|
|
18
17
|
import { FeeAssetHandlerAbi } from '@aztec/l1-artifacts';
|
|
19
18
|
import { TokenContract } from '@aztec/noir-contracts.js/Token';
|
|
20
|
-
import { type ProverNode, type ProverNodeConfig, createProverNode } from '@aztec/prover-node';
|
|
21
19
|
import type { ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
22
20
|
import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
|
|
23
21
|
import { getGenesisValues } from '@aztec/world-state/testing';
|
|
@@ -73,8 +71,8 @@ export class FullProverTest {
|
|
|
73
71
|
circuitProofVerifier?: ClientProtocolCircuitVerifier;
|
|
74
72
|
provenAsset!: TokenContract;
|
|
75
73
|
context!: EndToEndContext;
|
|
76
|
-
private
|
|
77
|
-
private
|
|
74
|
+
private proverAztecNode!: AztecNodeService;
|
|
75
|
+
private simulatedProverAztecNode!: AztecNodeService;
|
|
78
76
|
public l1Contracts!: DeployAztecL1ContractsReturnType;
|
|
79
77
|
public proverAddress!: EthAddress;
|
|
80
78
|
private minNumberOfTxsPerBlock: number;
|
|
@@ -108,7 +106,9 @@ export class FullProverTest {
|
|
|
108
106
|
await publicDeployAccounts(this.wallet, this.accounts.slice(0, 2));
|
|
109
107
|
|
|
110
108
|
this.logger.info('Applying base setup: deploying token contract');
|
|
111
|
-
const {
|
|
109
|
+
const {
|
|
110
|
+
receipt: { contract: asset, instance },
|
|
111
|
+
} = await TokenContract.deploy(
|
|
112
112
|
this.wallet,
|
|
113
113
|
this.accounts[0],
|
|
114
114
|
FullProverTest.TOKEN_NAME,
|
|
@@ -123,7 +123,7 @@ export class FullProverTest {
|
|
|
123
123
|
|
|
124
124
|
this.tokenSim = new TokenSimulator(this.fakeProofsAsset, this.wallet, this.accounts[0], this.logger, this.accounts);
|
|
125
125
|
|
|
126
|
-
expect(await this.fakeProofsAsset.methods.get_admin().simulate({ from: this.accounts[0] })).toBe(
|
|
126
|
+
expect((await this.fakeProofsAsset.methods.get_admin().simulate({ from: this.accounts[0] })).result).toBe(
|
|
127
127
|
this.accounts[0].toBigInt(),
|
|
128
128
|
);
|
|
129
129
|
}
|
|
@@ -146,7 +146,7 @@ export class FullProverTest {
|
|
|
146
146
|
// We don't wish to mark as proven automatically, so we set the flag to false
|
|
147
147
|
this.context.watcher.setIsMarkingAsProven(false);
|
|
148
148
|
|
|
149
|
-
this.
|
|
149
|
+
this.simulatedProverAztecNode = this.context.proverNode!;
|
|
150
150
|
({
|
|
151
151
|
aztecNode: this.aztecNode,
|
|
152
152
|
deployL1ContractsValues: this.l1Contracts,
|
|
@@ -155,7 +155,6 @@ export class FullProverTest {
|
|
|
155
155
|
this.aztecNodeAdmin = this.context.aztecNodeService;
|
|
156
156
|
|
|
157
157
|
const config = this.context.aztecNodeConfig;
|
|
158
|
-
const blobClient = await createBlobClientWithFileStores(config, this.logger);
|
|
159
158
|
|
|
160
159
|
// Configure a full prover PXE
|
|
161
160
|
let acvmConfig: Awaited<ReturnType<typeof getACVMConfig>> | undefined;
|
|
@@ -217,20 +216,13 @@ export class FullProverTest {
|
|
|
217
216
|
this.provenWallet = provenWallet;
|
|
218
217
|
this.logger.info(`Full prover PXE started`);
|
|
219
218
|
|
|
220
|
-
// Shutdown the current, simulated prover node
|
|
219
|
+
// Shutdown the current, simulated prover node (by stopping its hosting aztec node)
|
|
221
220
|
this.logger.verbose('Shutting down simulated prover node');
|
|
222
|
-
await this.
|
|
223
|
-
|
|
224
|
-
// Creating temp store and archiver for fully proven prover node
|
|
225
|
-
this.logger.verbose('Starting archiver for new prover node');
|
|
226
|
-
const archiver = await createArchiver(
|
|
227
|
-
{ ...this.context.aztecNodeConfig, dataDirectory: undefined },
|
|
228
|
-
{ blobClient, dateProvider: this.context.dateProvider },
|
|
229
|
-
{ blockUntilSync: true },
|
|
230
|
-
);
|
|
221
|
+
await this.simulatedProverAztecNode.stop();
|
|
231
222
|
|
|
232
223
|
// The simulated prover node (now shutdown) used private key index 2
|
|
233
224
|
const proverNodePrivateKey = getPrivateKeyFromIndex(2);
|
|
225
|
+
const proverNodePrivateKeyHex = `0x${proverNodePrivateKey!.toString('hex')}` as const;
|
|
234
226
|
const proverNodeSenderAddress = privateKeyToAddress(new Buffer32(proverNodePrivateKey!).toString());
|
|
235
227
|
this.proverAddress = EthAddress.fromString(proverNodeSenderAddress);
|
|
236
228
|
|
|
@@ -238,14 +230,21 @@ export class FullProverTest {
|
|
|
238
230
|
await this.mintFeeJuice(proverNodeSenderAddress);
|
|
239
231
|
|
|
240
232
|
this.logger.verbose('Starting prover node');
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
|
|
233
|
+
const sponsoredFPCAddress = await getSponsoredFPCAddress();
|
|
234
|
+
const { prefilledPublicData } = await getGenesisValues(
|
|
235
|
+
this.context.initialFundedAccounts.map(a => a.address).concat(sponsoredFPCAddress),
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
const proverNodeConfig: Parameters<typeof AztecNodeService.createAndSync>[0] = {
|
|
239
|
+
...config,
|
|
240
|
+
enableProverNode: true,
|
|
241
|
+
disableValidator: true,
|
|
244
242
|
dataDirectory: undefined,
|
|
243
|
+
txCollectionNodeRpcUrls: [],
|
|
245
244
|
proverId: this.proverAddress,
|
|
246
245
|
realProofs: this.realProofs,
|
|
247
246
|
proverAgentCount: 2,
|
|
248
|
-
|
|
247
|
+
proverPublisherPrivateKeys: [new SecretValue(proverNodePrivateKeyHex)],
|
|
249
248
|
proverNodeMaxPendingJobs: 100,
|
|
250
249
|
proverNodeMaxParallelBlocksPerEpoch: 32,
|
|
251
250
|
proverNodePollingIntervalMs: 100,
|
|
@@ -255,21 +254,14 @@ export class FullProverTest {
|
|
|
255
254
|
txGatheringTimeoutMs: 24_000,
|
|
256
255
|
proverNodeFailedEpochStore: undefined,
|
|
257
256
|
proverNodeEpochProvingDelayMs: undefined,
|
|
257
|
+
validatorPrivateKeys: new SecretValue([]),
|
|
258
258
|
};
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
this.proverNode = await createProverNode(
|
|
264
|
-
proverConfig,
|
|
265
|
-
{
|
|
266
|
-
aztecNodeTxProvider: this.aztecNode,
|
|
267
|
-
archiver: archiver as Archiver,
|
|
268
|
-
},
|
|
259
|
+
|
|
260
|
+
this.proverAztecNode = await AztecNodeService.createAndSync(
|
|
261
|
+
proverNodeConfig,
|
|
262
|
+
{ dateProvider: this.context.dateProvider, p2pClientDeps: { rpcTxProviders: [this.aztecNode] } },
|
|
269
263
|
{ prefilledPublicData },
|
|
270
264
|
);
|
|
271
|
-
await this.proverNode.start();
|
|
272
|
-
|
|
273
265
|
this.logger.warn(`Proofs are now enabled`, { realProofs: this.realProofs });
|
|
274
266
|
return this;
|
|
275
267
|
}
|
|
@@ -289,8 +281,8 @@ export class FullProverTest {
|
|
|
289
281
|
await this.provenComponents[i].teardown();
|
|
290
282
|
}
|
|
291
283
|
|
|
292
|
-
// clean up the full prover node
|
|
293
|
-
await this.
|
|
284
|
+
// clean up the full prover node (by stopping its hosting aztec node)
|
|
285
|
+
await this.proverAztecNode.stop();
|
|
294
286
|
|
|
295
287
|
await Barretenberg.destroySingleton();
|
|
296
288
|
await this.bbConfigCleanup?.();
|
|
@@ -320,16 +312,20 @@ export class FullProverTest {
|
|
|
320
312
|
} = this;
|
|
321
313
|
tokenSim.mintPublic(address, publicAmount);
|
|
322
314
|
|
|
323
|
-
const publicBalance = await fakeProofsAsset.methods
|
|
315
|
+
const { result: publicBalance } = await fakeProofsAsset.methods
|
|
316
|
+
.balance_of_public(address)
|
|
317
|
+
.simulate({ from: address });
|
|
324
318
|
this.logger.verbose(`Public balance of wallet 0: ${publicBalance}`);
|
|
325
319
|
expect(publicBalance).toEqual(this.tokenSim.balanceOfPublic(address));
|
|
326
320
|
|
|
327
321
|
tokenSim.mintPrivate(address, publicAmount);
|
|
328
|
-
const privateBalance = await fakeProofsAsset.methods
|
|
322
|
+
const { result: privateBalance } = await fakeProofsAsset.methods
|
|
323
|
+
.balance_of_private(address)
|
|
324
|
+
.simulate({ from: address });
|
|
329
325
|
this.logger.verbose(`Private balance of wallet 0: ${privateBalance}`);
|
|
330
326
|
expect(privateBalance).toEqual(tokenSim.balanceOfPrivate(address));
|
|
331
327
|
|
|
332
|
-
const totalSupply = await fakeProofsAsset.methods.total_supply().simulate({ from: address });
|
|
328
|
+
const { result: totalSupply } = await fakeProofsAsset.methods.total_supply().simulate({ from: address });
|
|
333
329
|
this.logger.verbose(`Total supply: ${totalSupply}`);
|
|
334
330
|
expect(totalSupply).toEqual(tokenSim.totalSupply);
|
|
335
331
|
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { appendFileSync } from 'node:fs';
|
|
2
|
+
import { type EventLoopUtilization, type IntervalHistogram, monitorEventLoopDelay, performance } from 'node:perf_hooks';
|
|
3
|
+
|
|
4
|
+
const NANOS_PER_MS = 1_000_000;
|
|
5
|
+
|
|
6
|
+
/** Samples event-loop utilization, delay histogram, and heap usage per test, writing columnar text to a file. */
|
|
7
|
+
export class EluMonitor {
|
|
8
|
+
private filePath: string;
|
|
9
|
+
private intervalMs: number;
|
|
10
|
+
private timer: ReturnType<typeof setInterval> | undefined;
|
|
11
|
+
private lastELU: EventLoopUtilization | undefined;
|
|
12
|
+
private histogram: IntervalHistogram;
|
|
13
|
+
private testName: string | undefined;
|
|
14
|
+
private testStart: number | undefined;
|
|
15
|
+
private eluSamples: number[] = [];
|
|
16
|
+
|
|
17
|
+
constructor(filePath: string, intervalMs?: number) {
|
|
18
|
+
this.filePath = filePath;
|
|
19
|
+
this.intervalMs = intervalMs ?? 2000;
|
|
20
|
+
this.histogram = monitorEventLoopDelay({ resolution: 20 });
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Begin sampling for a test. Writes a header line and starts the periodic sampler. */
|
|
24
|
+
startTest(testName: string): void {
|
|
25
|
+
this.stopTest();
|
|
26
|
+
|
|
27
|
+
this.testName = testName;
|
|
28
|
+
this.testStart = performance.now();
|
|
29
|
+
this.eluSamples = [];
|
|
30
|
+
|
|
31
|
+
appendFileSync(this.filePath, `\n=== Test: ${testName} ===\n`);
|
|
32
|
+
appendFileSync(
|
|
33
|
+
this.filePath,
|
|
34
|
+
padColumns('TIME', 'ELU', 'EL_DLY_P50', 'EL_DLY_P99', 'EL_DLY_MAX', 'HEAP_MB') + '\n',
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
this.lastELU = performance.eventLoopUtilization();
|
|
38
|
+
this.histogram.enable();
|
|
39
|
+
|
|
40
|
+
this.timer = setInterval(() => this.sample(), this.intervalMs);
|
|
41
|
+
// Allow the process to exit even if the timer is still running.
|
|
42
|
+
this.timer.unref();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Stop sampling and write a summary line. */
|
|
46
|
+
stopTest(): void {
|
|
47
|
+
if (!this.timer) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Take a final sample before stopping.
|
|
52
|
+
this.sample();
|
|
53
|
+
|
|
54
|
+
clearInterval(this.timer);
|
|
55
|
+
this.timer = undefined;
|
|
56
|
+
this.histogram.disable();
|
|
57
|
+
this.histogram.reset();
|
|
58
|
+
|
|
59
|
+
this.writeSummary();
|
|
60
|
+
|
|
61
|
+
this.lastELU = undefined;
|
|
62
|
+
this.testName = undefined;
|
|
63
|
+
this.testStart = undefined;
|
|
64
|
+
this.eluSamples = [];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Alias for stopTest — call on process exit to flush any remaining data. */
|
|
68
|
+
stop(): void {
|
|
69
|
+
this.stopTest();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private sample(): void {
|
|
73
|
+
const newELU = performance.eventLoopUtilization();
|
|
74
|
+
const delta = performance.eventLoopUtilization(newELU, this.lastELU);
|
|
75
|
+
this.lastELU = newELU;
|
|
76
|
+
|
|
77
|
+
const elu = delta.utilization;
|
|
78
|
+
this.eluSamples.push(elu);
|
|
79
|
+
|
|
80
|
+
const p50 = this.histogram.percentile(50) / NANOS_PER_MS;
|
|
81
|
+
const p99 = this.histogram.percentile(99) / NANOS_PER_MS;
|
|
82
|
+
const max = this.histogram.max / NANOS_PER_MS;
|
|
83
|
+
const heapMb = Math.round(process.memoryUsage().heapUsed / (1024 * 1024));
|
|
84
|
+
|
|
85
|
+
const now = new Date();
|
|
86
|
+
const time = [now.getHours(), now.getMinutes(), now.getSeconds()].map(n => String(n).padStart(2, '0')).join(':');
|
|
87
|
+
|
|
88
|
+
const line = padColumns(
|
|
89
|
+
time,
|
|
90
|
+
elu.toFixed(2),
|
|
91
|
+
`${p50.toFixed(1)}ms`,
|
|
92
|
+
`${p99.toFixed(1)}ms`,
|
|
93
|
+
`${max.toFixed(1)}ms`,
|
|
94
|
+
String(heapMb),
|
|
95
|
+
);
|
|
96
|
+
appendFileSync(this.filePath, line + '\n');
|
|
97
|
+
|
|
98
|
+
// Reset histogram so next sample only reflects the new interval.
|
|
99
|
+
this.histogram.reset();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private writeSummary(): void {
|
|
103
|
+
if (this.eluSamples.length === 0 || this.testStart === undefined) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const mean = this.eluSamples.reduce((a, b) => a + b, 0) / this.eluSamples.length;
|
|
108
|
+
const maxElu = Math.max(...this.eluSamples);
|
|
109
|
+
const sorted = [...this.eluSamples].sort((a, b) => a - b);
|
|
110
|
+
const p90Elu = sorted[Math.floor(sorted.length * 0.9)] ?? maxElu;
|
|
111
|
+
const durationS = ((performance.now() - this.testStart) / 1000).toFixed(1);
|
|
112
|
+
|
|
113
|
+
let summary = `--- Summary: mean_elu=${mean.toFixed(2)} max_elu=${maxElu.toFixed(2)} p90_elu=${p90Elu.toFixed(2)} duration=${durationS}s`;
|
|
114
|
+
if (maxElu > 0.85) {
|
|
115
|
+
summary += ' WARNING:ELU>0.85';
|
|
116
|
+
}
|
|
117
|
+
summary += ' ---\n';
|
|
118
|
+
|
|
119
|
+
appendFileSync(this.filePath, summary);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function padColumns(...cols: string[]): string {
|
|
124
|
+
const widths = [11, 7, 12, 12, 12, 8];
|
|
125
|
+
return cols.map((col, i) => col.padEnd(widths[i] ?? 10)).join('');
|
|
126
|
+
}
|
package/src/fixtures/fixtures.ts
CHANGED
|
@@ -7,6 +7,16 @@ export const shouldCollectMetrics = () => {
|
|
|
7
7
|
return undefined;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
|
+
/** Returns the boot node UDP port from environment variable or default value. */
|
|
11
|
+
export function getBootNodeUdpPort(): number {
|
|
12
|
+
return process.env.BOOT_NODE_UDP_PORT ? parseInt(process.env.BOOT_NODE_UDP_PORT, 10) : 4500;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Returns the anvil port from environment variable or default value. */
|
|
16
|
+
export function getAnvilPort(): number {
|
|
17
|
+
return process.env.ANVIL_PORT ? parseInt(process.env.ANVIL_PORT, 10) : 8545;
|
|
18
|
+
}
|
|
19
|
+
|
|
10
20
|
export const TEST_PEER_CHECK_INTERVAL_MS = 1000;
|
|
11
21
|
export const TEST_MAX_PENDING_TX_POOL_COUNT = 10_000; // Number of max pending TXs ~ 1.56GB
|
|
12
22
|
|
package/src/fixtures/setup.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { SchnorrAccountContractArtifact } from '@aztec/accounts/schnorr';
|
|
2
2
|
import { type InitialAccountData, generateSchnorrAccounts } from '@aztec/accounts/testing';
|
|
3
|
-
import { type Archiver, createArchiver } from '@aztec/archiver';
|
|
4
3
|
import { type AztecNodeConfig, AztecNodeService, getConfigEnvVars } from '@aztec/aztec-node';
|
|
5
4
|
import { AztecAddress, EthAddress } from '@aztec/aztec.js/addresses';
|
|
6
5
|
import {
|
|
@@ -16,7 +15,6 @@ import { type Logger, createLogger } from '@aztec/aztec.js/log';
|
|
|
16
15
|
import type { AztecNode } from '@aztec/aztec.js/node';
|
|
17
16
|
import type { Wallet } from '@aztec/aztec.js/wallet';
|
|
18
17
|
import { AnvilTestWatcher, CheatCodes } from '@aztec/aztec/testing';
|
|
19
|
-
import { createBlobClientWithFileStores } from '@aztec/blob-client/client';
|
|
20
18
|
import { SPONSORED_FPC_SALT } from '@aztec/constants';
|
|
21
19
|
import { isAnvilTestChain } from '@aztec/ethereum/chain';
|
|
22
20
|
import { createExtendedL1Client } from '@aztec/ethereum/client';
|
|
@@ -30,13 +28,9 @@ import {
|
|
|
30
28
|
type ZKPassportArgs,
|
|
31
29
|
deployAztecL1Contracts,
|
|
32
30
|
} from '@aztec/ethereum/deploy-aztec-l1-contracts';
|
|
33
|
-
import {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
EthCheatCodesWithState,
|
|
37
|
-
createDelayedL1TxUtilsFromViemWallet,
|
|
38
|
-
startAnvil,
|
|
39
|
-
} from '@aztec/ethereum/test';
|
|
31
|
+
import type { Delayer } from '@aztec/ethereum/l1-tx-utils';
|
|
32
|
+
import { EthCheatCodes, EthCheatCodesWithState, startAnvil } from '@aztec/ethereum/test';
|
|
33
|
+
import type { Anvil } from '@aztec/ethereum/test';
|
|
40
34
|
import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
|
|
41
35
|
import { SecretValue } from '@aztec/foundation/config';
|
|
42
36
|
import { randomBytes } from '@aztec/foundation/crypto/random';
|
|
@@ -45,20 +39,17 @@ import { withLoggerBindings } from '@aztec/foundation/log/server';
|
|
|
45
39
|
import { retryUntil } from '@aztec/foundation/retry';
|
|
46
40
|
import { sleep } from '@aztec/foundation/sleep';
|
|
47
41
|
import { DateProvider, TestDateProvider } from '@aztec/foundation/timer';
|
|
48
|
-
import type { DataStoreConfig } from '@aztec/kv-store/config';
|
|
49
42
|
import { SponsoredFPCContract } from '@aztec/noir-contracts.js/SponsoredFPC';
|
|
50
43
|
import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
|
|
51
44
|
import type { P2PClientDeps } from '@aztec/p2p';
|
|
52
45
|
import { MockGossipSubNetwork, getMockPubSubP2PServiceFactory } from '@aztec/p2p/test-helpers';
|
|
53
46
|
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
54
|
-
import
|
|
47
|
+
import type { ProverNodeConfig } from '@aztec/prover-node';
|
|
55
48
|
import { type PXEConfig, getPXEConfig } from '@aztec/pxe/server';
|
|
56
49
|
import type { SequencerClient } from '@aztec/sequencer-client';
|
|
57
|
-
import type { TestSequencerClient } from '@aztec/sequencer-client/test';
|
|
58
50
|
import { type ContractInstanceWithAddress, getContractInstanceFromInstantiationParams } from '@aztec/stdlib/contract';
|
|
59
51
|
import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
|
|
60
52
|
import { tryStop } from '@aztec/stdlib/interfaces/server';
|
|
61
|
-
import type { P2PClientType } from '@aztec/stdlib/p2p';
|
|
62
53
|
import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
|
|
63
54
|
import {
|
|
64
55
|
type TelemetryClient,
|
|
@@ -70,7 +61,6 @@ import { BenchmarkTelemetryClient } from '@aztec/telemetry-client/bench';
|
|
|
70
61
|
import { deployFundedSchnorrAccounts } from '@aztec/wallets/testing';
|
|
71
62
|
import { getGenesisValues } from '@aztec/world-state/testing';
|
|
72
63
|
|
|
73
|
-
import type { Anvil } from '@viem/anvil';
|
|
74
64
|
import fs from 'fs/promises';
|
|
75
65
|
import { tmpdir } from 'os';
|
|
76
66
|
import path from 'path';
|
|
@@ -219,8 +209,8 @@ export type EndToEndContext = {
|
|
|
219
209
|
aztecNodeService: AztecNodeService;
|
|
220
210
|
/** Client to the Aztec Node admin interface. */
|
|
221
211
|
aztecNodeAdmin: AztecNodeAdmin;
|
|
222
|
-
/** The prover node
|
|
223
|
-
proverNode:
|
|
212
|
+
/** The aztec node running the prover node subsystem (only set if startProverNode is true). */
|
|
213
|
+
proverNode: AztecNodeService | undefined;
|
|
224
214
|
/** A client to the sequencer service. */
|
|
225
215
|
sequencer: SequencerClient | undefined;
|
|
226
216
|
/** Return values from deployAztecL1Contracts function. */
|
|
@@ -249,6 +239,10 @@ export type EndToEndContext = {
|
|
|
249
239
|
telemetryClient: TelemetryClient;
|
|
250
240
|
/** Mock gossip sub network used for gossipping messages (only if mockGossipSubNetwork was set to true in opts) */
|
|
251
241
|
mockGossipSubNetwork: MockGossipSubNetwork | undefined;
|
|
242
|
+
/** Delayer for sequencer L1 txs (only when enableDelayer is true). */
|
|
243
|
+
sequencerDelayer: Delayer | undefined;
|
|
244
|
+
/** Delayer for prover node L1 txs (only when enableDelayer and startProverNode are true). */
|
|
245
|
+
proverDelayer: Delayer | undefined;
|
|
252
246
|
/** Prefilled public data used for setting up nodes. */
|
|
253
247
|
prefilledPublicData: PublicDataTreeLeaf[] | undefined;
|
|
254
248
|
/** ACVM config (only set if running locally). */
|
|
@@ -288,6 +282,8 @@ export async function setup(
|
|
|
288
282
|
config.realProofs = !!opts.realProofs;
|
|
289
283
|
// Only enforce the time table if requested
|
|
290
284
|
config.enforceTimeTable = !!opts.enforceTimeTable;
|
|
285
|
+
// Enable the tx delayer for tests (default config has it disabled, so we force-enable it here)
|
|
286
|
+
config.enableDelayer = true;
|
|
291
287
|
config.listenAddress = '127.0.0.1';
|
|
292
288
|
|
|
293
289
|
config.minTxPoolAgeMs = opts.minTxPoolAgeMs ?? 0;
|
|
@@ -339,11 +335,11 @@ export async function setup(
|
|
|
339
335
|
publisherPrivKeyHex = opts.l1PublisherKey.getValue();
|
|
340
336
|
publisherHdAccount = privateKeyToAccount(publisherPrivKeyHex);
|
|
341
337
|
} else if (
|
|
342
|
-
config.
|
|
343
|
-
config.
|
|
344
|
-
config.
|
|
338
|
+
config.sequencerPublisherPrivateKeys &&
|
|
339
|
+
config.sequencerPublisherPrivateKeys.length > 0 &&
|
|
340
|
+
config.sequencerPublisherPrivateKeys[0].getValue() != NULL_KEY
|
|
345
341
|
) {
|
|
346
|
-
publisherPrivKeyHex = config.
|
|
342
|
+
publisherPrivKeyHex = config.sequencerPublisherPrivateKeys[0].getValue();
|
|
347
343
|
publisherHdAccount = privateKeyToAccount(publisherPrivKeyHex);
|
|
348
344
|
} else if (!MNEMONIC) {
|
|
349
345
|
throw new Error(`Mnemonic not provided and no publisher private key`);
|
|
@@ -352,7 +348,7 @@ export async function setup(
|
|
|
352
348
|
const publisherPrivKeyRaw = publisherHdAccount.getHdKey().privateKey;
|
|
353
349
|
const publisherPrivKey = publisherPrivKeyRaw === null ? null : Buffer.from(publisherPrivKeyRaw);
|
|
354
350
|
publisherPrivKeyHex = `0x${publisherPrivKey!.toString('hex')}` as const;
|
|
355
|
-
config.
|
|
351
|
+
config.sequencerPublisherPrivateKeys = [new SecretValue(publisherPrivKeyHex)];
|
|
356
352
|
}
|
|
357
353
|
|
|
358
354
|
if (config.coinbase === undefined) {
|
|
@@ -459,7 +455,7 @@ export async function setup(
|
|
|
459
455
|
}
|
|
460
456
|
|
|
461
457
|
let mockGossipSubNetwork: MockGossipSubNetwork | undefined;
|
|
462
|
-
let p2pClientDeps: P2PClientDeps
|
|
458
|
+
let p2pClientDeps: P2PClientDeps | undefined = undefined;
|
|
463
459
|
|
|
464
460
|
if (opts.mockGossipSubNetwork) {
|
|
465
461
|
mockGossipSubNetwork = new MockGossipSubNetwork();
|
|
@@ -499,36 +495,33 @@ export async function setup(
|
|
|
499
495
|
);
|
|
500
496
|
const sequencerClient = aztecNodeService.getSequencer();
|
|
501
497
|
|
|
502
|
-
|
|
503
|
-
const publisher = (sequencerClient as TestSequencerClient).sequencer.publisher;
|
|
504
|
-
publisher.l1TxUtils = DelayedTxUtils.fromL1TxUtils(publisher.l1TxUtils, config.ethereumSlotDuration, l1Client);
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
let proverNode: ProverNode | undefined = undefined;
|
|
498
|
+
let proverNode: AztecNodeService | undefined = undefined;
|
|
508
499
|
if (opts.startProverNode) {
|
|
509
500
|
logger.verbose('Creating and syncing a simulated prover node...');
|
|
510
501
|
const proverNodePrivateKey = getPrivateKeyFromIndex(2);
|
|
511
502
|
const proverNodePrivateKeyHex: Hex = `0x${proverNodePrivateKey!.toString('hex')}`;
|
|
512
503
|
const proverNodeDataDirectory = path.join(directoryToCleanup, randomBytes(8).toString('hex'));
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
504
|
+
|
|
505
|
+
const p2pClientDeps: Partial<P2PClientDeps> = {
|
|
506
|
+
p2pServiceFactory: mockGossipSubNetwork && getMockPubSubP2PServiceFactory(mockGossipSubNetwork!),
|
|
507
|
+
rpcTxProviders: [aztecNodeService],
|
|
517
508
|
};
|
|
518
|
-
|
|
509
|
+
|
|
510
|
+
({ proverNode } = await createAndSyncProverNode(
|
|
519
511
|
proverNodePrivateKeyHex,
|
|
520
512
|
config,
|
|
521
|
-
proverNodeConfig,
|
|
522
|
-
aztecNodeService,
|
|
523
|
-
prefilledPublicData,
|
|
524
513
|
{
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
: undefined,
|
|
514
|
+
...config.proverNodeConfig,
|
|
515
|
+
dataDirectory: proverNodeDataDirectory,
|
|
528
516
|
},
|
|
529
|
-
|
|
517
|
+
{ dateProvider, p2pClientDeps, telemetry: telemetryClient },
|
|
518
|
+
{ prefilledPublicData },
|
|
519
|
+
));
|
|
530
520
|
}
|
|
531
521
|
|
|
522
|
+
const sequencerDelayer = sequencerClient?.getDelayer();
|
|
523
|
+
const proverDelayer = proverNode?.getProverNode()?.getDelayer();
|
|
524
|
+
|
|
532
525
|
logger.verbose('Creating a pxe...');
|
|
533
526
|
const pxeConfig = { ...getPXEConfig(), ...pxeOpts };
|
|
534
527
|
pxeConfig.dataDirectory = path.join(directoryToCleanup, randomBytes(8).toString('hex'));
|
|
@@ -629,6 +622,8 @@ export async function setup(
|
|
|
629
622
|
mockGossipSubNetwork,
|
|
630
623
|
prefilledPublicData,
|
|
631
624
|
proverNode,
|
|
625
|
+
sequencerDelayer,
|
|
626
|
+
proverDelayer,
|
|
632
627
|
sequencer: sequencerClient,
|
|
633
628
|
teardown,
|
|
634
629
|
telemetryClient,
|
|
@@ -712,81 +707,42 @@ export async function waitForProvenChain(node: AztecNode, targetBlock?: BlockNum
|
|
|
712
707
|
);
|
|
713
708
|
}
|
|
714
709
|
|
|
710
|
+
/**
|
|
711
|
+
* Creates an AztecNodeService with the prover node enabled as a subsystem.
|
|
712
|
+
* Returns both the aztec node service (for lifecycle management) and the prover node (for test internals access).
|
|
713
|
+
*/
|
|
715
714
|
export function createAndSyncProverNode(
|
|
716
715
|
proverNodePrivateKey: `0x${string}`,
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
716
|
+
baseConfig: AztecNodeConfig,
|
|
717
|
+
configOverrides: Pick<AztecNodeConfig, 'dataDirectory'>,
|
|
718
|
+
deps: {
|
|
719
|
+
telemetry?: TelemetryClient;
|
|
720
|
+
dateProvider: DateProvider;
|
|
721
|
+
p2pClientDeps?: P2PClientDeps;
|
|
722
|
+
},
|
|
723
|
+
options: { prefilledPublicData: PublicDataTreeLeaf[]; dontStart?: boolean },
|
|
724
|
+
): Promise<{ proverNode: AztecNodeService }> {
|
|
723
725
|
return withLoggerBindings({ actor: 'prover-0' }, async () => {
|
|
724
|
-
const
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
{ blobClient, dateProvider: proverNodeDeps.dateProvider },
|
|
736
|
-
{ blockUntilSync: true },
|
|
737
|
-
);
|
|
738
|
-
|
|
739
|
-
const proverConfig: ProverNodeConfig = {
|
|
740
|
-
...aztecNodeConfig,
|
|
741
|
-
txCollectionNodeRpcUrls: [],
|
|
742
|
-
realProofs: false,
|
|
743
|
-
proverAgentCount: 2,
|
|
744
|
-
publisherPrivateKeys: [new SecretValue(proverNodePrivateKey)],
|
|
745
|
-
proverNodeMaxPendingJobs: 10,
|
|
746
|
-
proverNodeMaxParallelBlocksPerEpoch: 32,
|
|
747
|
-
proverNodePollingIntervalMs: 200,
|
|
748
|
-
txGatheringIntervalMs: 1000,
|
|
749
|
-
txGatheringBatchSize: 10,
|
|
750
|
-
txGatheringMaxParallelRequestsPerNode: 10,
|
|
751
|
-
txGatheringTimeoutMs: 24_000,
|
|
752
|
-
proverNodeFailedEpochStore: undefined,
|
|
753
|
-
proverId: EthAddress.fromNumber(1),
|
|
754
|
-
proverNodeEpochProvingDelayMs: undefined,
|
|
755
|
-
...proverNodeConfig,
|
|
756
|
-
};
|
|
757
|
-
|
|
758
|
-
const l1TxUtils = createDelayedL1TxUtils(
|
|
759
|
-
aztecNodeConfig,
|
|
760
|
-
proverNodePrivateKey,
|
|
761
|
-
'prover-node',
|
|
762
|
-
proverNodeDeps.dateProvider,
|
|
726
|
+
const proverNode = await AztecNodeService.createAndSync(
|
|
727
|
+
{
|
|
728
|
+
...baseConfig,
|
|
729
|
+
...configOverrides,
|
|
730
|
+
p2pPort: 0,
|
|
731
|
+
enableProverNode: true,
|
|
732
|
+
disableValidator: true,
|
|
733
|
+
proverPublisherPrivateKeys: [new SecretValue(proverNodePrivateKey)],
|
|
734
|
+
},
|
|
735
|
+
deps,
|
|
736
|
+
{ ...options, dontStartProverNode: options.dontStart },
|
|
763
737
|
);
|
|
764
738
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
{ ...proverNodeDeps, aztecNodeTxProvider, archiver: archiver as Archiver, l1TxUtils },
|
|
768
|
-
{ prefilledPublicData },
|
|
769
|
-
);
|
|
770
|
-
getLogger().info(`Created and synced prover node`, { publisherAddress: l1TxUtils.client.account!.address });
|
|
771
|
-
if (!proverNodeConfig.dontStart) {
|
|
772
|
-
await proverNode.start();
|
|
739
|
+
if (!proverNode.getProverNode()) {
|
|
740
|
+
throw new Error('Prover node subsystem was not created despite enableProverNode being set');
|
|
773
741
|
}
|
|
774
|
-
return proverNode;
|
|
775
|
-
});
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
function createDelayedL1TxUtils(
|
|
779
|
-
aztecNodeConfig: AztecNodeConfig,
|
|
780
|
-
privateKey: `0x${string}`,
|
|
781
|
-
logName: string,
|
|
782
|
-
dateProvider?: DateProvider,
|
|
783
|
-
) {
|
|
784
|
-
const l1Client = createExtendedL1Client(aztecNodeConfig.l1RpcUrls, privateKey, foundry);
|
|
785
742
|
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
return l1TxUtils;
|
|
743
|
+
getLogger().info(`Created and synced prover node`);
|
|
744
|
+
return { proverNode };
|
|
745
|
+
});
|
|
790
746
|
}
|
|
791
747
|
|
|
792
748
|
export type BalancesFn = ReturnType<typeof getBalancesFn>;
|
|
@@ -797,7 +753,9 @@ export function getBalancesFn(
|
|
|
797
753
|
): (...addresses: (AztecAddress | { address: AztecAddress })[]) => Promise<bigint[]> {
|
|
798
754
|
const balances = async (...addressLikes: (AztecAddress | { address: AztecAddress })[]) => {
|
|
799
755
|
const addresses = addressLikes.map(addressLike => ('address' in addressLike ? addressLike.address : addressLike));
|
|
800
|
-
const b = await Promise.all(
|
|
756
|
+
const b = await Promise.all(
|
|
757
|
+
addresses.map(async address => (await method(address).simulate({ from: address })).result),
|
|
758
|
+
);
|
|
801
759
|
const debugString = `${symbol} balances: ${addresses.map((address, i) => `${address}: ${b[i]}`).join(', ')}`;
|
|
802
760
|
logger.verbose(debugString);
|
|
803
761
|
return b;
|
|
@@ -915,7 +873,7 @@ export async function publicDeployAccounts(
|
|
|
915
873
|
|
|
916
874
|
const batch = new BatchCall(wallet, calls);
|
|
917
875
|
|
|
918
|
-
const txReceipt = await batch.send({ from: accountsToDeploy[0] });
|
|
876
|
+
const { receipt: txReceipt } = await batch.send({ from: accountsToDeploy[0] });
|
|
919
877
|
if (waitUntilProven) {
|
|
920
878
|
if (!node) {
|
|
921
879
|
throw new Error('Need to provide an AztecNode to wait for proven.');
|