@aztec/end-to-end 0.0.1-commit.3e3d0c9cd → 0.0.1-commit.3f5453c7b
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/README.md +27 -0
- 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 +13 -28
- package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +3 -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 +1 -1
- package/dest/e2e_epochs/epochs_test.d.ts +3 -1
- package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
- package/dest/e2e_epochs/epochs_test.js +6 -4
- package/dest/e2e_fees/fees_test.js +1 -1
- package/dest/e2e_p2p/inactivity_slash_test.js +3 -3
- package/dest/e2e_p2p/p2p_network.d.ts +5 -7
- package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
- package/dest/e2e_p2p/p2p_network.js +14 -13
- package/dest/e2e_p2p/reqresp/utils.js +1 -1
- package/dest/e2e_p2p/shared.d.ts +5 -7
- package/dest/e2e_p2p/shared.d.ts.map +1 -1
- package/dest/e2e_p2p/shared.js +16 -42
- package/dest/fixtures/authwit_proxy.d.ts +1 -1
- package/dest/fixtures/authwit_proxy.d.ts.map +1 -1
- package/dest/fixtures/authwit_proxy.js +4 -0
- package/dest/fixtures/e2e_prover_test.d.ts +4 -3
- package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
- package/dest/fixtures/e2e_prover_test.js +7 -12
- package/dest/fixtures/get_bb_config.d.ts +1 -1
- package/dest/fixtures/get_bb_config.d.ts.map +1 -1
- package/dest/fixtures/get_bb_config.js +5 -5
- package/dest/fixtures/setup.d.ts +11 -8
- package/dest/fixtures/setup.d.ts.map +1 -1
- package/dest/fixtures/setup.js +23 -18
- package/dest/fixtures/setup_p2p_test.d.ts +6 -6
- package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
- package/dest/fixtures/setup_p2p_test.js +8 -8
- package/dest/fixtures/token_utils.d.ts +1 -1
- package/dest/fixtures/token_utils.d.ts.map +1 -1
- package/dest/fixtures/token_utils.js +2 -5
- package/dest/legacy-jest-resolver.d.cts +3 -0
- package/dest/legacy-jest-resolver.d.cts.map +1 -0
- 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.js +1 -1
- package/dest/spartan/setup_test_wallets.d.ts +1 -1
- package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
- package/dest/spartan/setup_test_wallets.js +63 -45
- package/dest/test-wallet/test_wallet.d.ts +24 -23
- package/dest/test-wallet/test_wallet.d.ts.map +1 -1
- package/dest/test-wallet/test_wallet.js +115 -80
- package/dest/test-wallet/worker_wallet.d.ts +4 -4
- package/dest/test-wallet/worker_wallet.d.ts.map +1 -1
- package/dest/test-wallet/worker_wallet_schema.d.ts +9 -4
- package/dest/test-wallet/worker_wallet_schema.d.ts.map +1 -1
- package/package.json +40 -39
- package/src/bench/client_flows/client_flows_benchmark.ts +31 -22
- package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +3 -6
- package/src/e2e_epochs/epochs_test.ts +16 -5
- package/src/e2e_fees/fees_test.ts +1 -1
- package/src/e2e_p2p/inactivity_slash_test.ts +3 -3
- package/src/e2e_p2p/p2p_network.ts +22 -27
- package/src/e2e_p2p/reqresp/utils.ts +1 -1
- package/src/e2e_p2p/shared.ts +16 -57
- package/src/fixtures/authwit_proxy.ts +4 -0
- package/src/fixtures/e2e_prover_test.ts +12 -17
- package/src/fixtures/get_bb_config.ts +7 -6
- package/src/fixtures/setup.ts +32 -25
- package/src/fixtures/setup_p2p_test.ts +9 -9
- package/src/fixtures/token_utils.ts +1 -4
- package/src/legacy-jest-resolver.cjs +135 -0
- package/src/simulators/lending_simulator.ts +4 -2
- package/src/simulators/token_simulator.ts +1 -1
- package/src/spartan/setup_test_wallets.ts +63 -39
- package/src/test-wallet/test_wallet.ts +144 -99
- package/src/test-wallet/worker_wallet.ts +3 -2
package/src/fixtures/setup.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { SchnorrAccountContractArtifact } from '@aztec/accounts/schnorr';
|
|
2
2
|
import { type InitialAccountData, generateSchnorrAccounts } from '@aztec/accounts/testing';
|
|
3
3
|
import { type AztecNodeConfig, AztecNodeService, getConfigEnvVars } from '@aztec/aztec-node';
|
|
4
|
+
import { NO_FROM } from '@aztec/aztec.js/account';
|
|
4
5
|
import { AztecAddress, EthAddress } from '@aztec/aztec.js/addresses';
|
|
5
6
|
import {
|
|
6
7
|
BatchCall,
|
|
7
8
|
type ContractFunctionInteraction,
|
|
8
9
|
type ContractMethod,
|
|
10
|
+
type DeployInteractionWaitOptions,
|
|
11
|
+
type DeployOptions,
|
|
9
12
|
getContractClassFromArtifact,
|
|
10
13
|
waitForProven,
|
|
11
14
|
} from '@aztec/aztec.js/contracts';
|
|
@@ -48,9 +51,10 @@ import type { ProverNodeConfig } from '@aztec/prover-node';
|
|
|
48
51
|
import { type PXEConfig, getPXEConfig } from '@aztec/pxe/server';
|
|
49
52
|
import type { SequencerClient } from '@aztec/sequencer-client';
|
|
50
53
|
import { type ContractInstanceWithAddress, getContractInstanceFromInstantiationParams } from '@aztec/stdlib/contract';
|
|
51
|
-
import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
|
|
54
|
+
import type { AztecNodeAdmin, AztecNodeDebug } from '@aztec/stdlib/interfaces/client';
|
|
52
55
|
import { tryStop } from '@aztec/stdlib/interfaces/server';
|
|
53
56
|
import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
|
|
57
|
+
import type { GenesisData } from '@aztec/stdlib/world-state';
|
|
54
58
|
import {
|
|
55
59
|
type TelemetryClient,
|
|
56
60
|
type TelemetryClientConfig,
|
|
@@ -177,6 +181,8 @@ export type SetupOptions = {
|
|
|
177
181
|
proverNodeConfig?: Partial<ProverNodeConfig>;
|
|
178
182
|
/** Whether to use a mock gossip sub network for p2p clients. */
|
|
179
183
|
mockGossipSubNetwork?: boolean;
|
|
184
|
+
/** Whether to add simulated latency to the mock gossipsub network (in ms) */
|
|
185
|
+
mockGossipSubNetworkLatency?: number;
|
|
180
186
|
/** Whether to disable the anvil test watcher (can still be manually started) */
|
|
181
187
|
disableAnvilTestWatcher?: boolean;
|
|
182
188
|
/** Whether to enable anvil automine during deployment of L1 contracts (consider defaulting this to true). */
|
|
@@ -209,7 +215,7 @@ export type EndToEndContext = {
|
|
|
209
215
|
/** The Anvil instance (only set if anvil was started locally). */
|
|
210
216
|
anvil: Anvil | undefined;
|
|
211
217
|
/** The Aztec Node service or client a connected to it. */
|
|
212
|
-
aztecNode: AztecNode;
|
|
218
|
+
aztecNode: AztecNode & AztecNodeDebug;
|
|
213
219
|
/** The Aztec Node as a service. */
|
|
214
220
|
aztecNodeService: AztecNodeService;
|
|
215
221
|
/** Client to the Aztec Node admin interface. */
|
|
@@ -248,8 +254,8 @@ export type EndToEndContext = {
|
|
|
248
254
|
sequencerDelayer: Delayer | undefined;
|
|
249
255
|
/** Delayer for prover node L1 txs (only when enableDelayer and startProverNode are true). */
|
|
250
256
|
proverDelayer: Delayer | undefined;
|
|
251
|
-
/**
|
|
252
|
-
|
|
257
|
+
/** Genesis data used for setting up nodes. */
|
|
258
|
+
genesis: GenesisData | undefined;
|
|
253
259
|
/** ACVM config (only set if running locally). */
|
|
254
260
|
acvmConfig: Awaited<ReturnType<typeof getACVMConfig>>;
|
|
255
261
|
/** BB config (only set if running locally). */
|
|
@@ -275,7 +281,7 @@ export async function setup(
|
|
|
275
281
|
let anvil: Anvil | undefined;
|
|
276
282
|
try {
|
|
277
283
|
opts.aztecTargetCommitteeSize ??= 0;
|
|
278
|
-
opts.
|
|
284
|
+
opts.slasherEnabled ??= false;
|
|
279
285
|
|
|
280
286
|
const config: AztecNodeConfig & SetupOptions = { ...getConfigEnvVars(), ...opts };
|
|
281
287
|
// use initialValidators for the node config
|
|
@@ -302,6 +308,8 @@ export async function setup(
|
|
|
302
308
|
config.dataDirectory = directoryToCleanup;
|
|
303
309
|
}
|
|
304
310
|
|
|
311
|
+
const dateProvider = new TestDateProvider();
|
|
312
|
+
|
|
305
313
|
if (!config.l1RpcUrls?.length) {
|
|
306
314
|
if (!isAnvilTestChain(chain.id)) {
|
|
307
315
|
throw new Error(`No ETHEREUM_HOSTS set but non anvil chain requested`);
|
|
@@ -311,6 +319,7 @@ export async function setup(
|
|
|
311
319
|
accounts: opts.anvilAccounts,
|
|
312
320
|
port: opts.anvilPort ?? (process.env.ANVIL_PORT ? parseInt(process.env.ANVIL_PORT) : undefined),
|
|
313
321
|
slotsInAnEpoch: opts.anvilSlotsInAnEpoch,
|
|
322
|
+
dateProvider,
|
|
314
323
|
});
|
|
315
324
|
anvil = res.anvil;
|
|
316
325
|
config.l1RpcUrls = [res.rpcUrl];
|
|
@@ -322,8 +331,6 @@ export async function setup(
|
|
|
322
331
|
logger.info(`Logging metrics to ${filename}`);
|
|
323
332
|
setupMetricsLogger(filename);
|
|
324
333
|
}
|
|
325
|
-
|
|
326
|
-
const dateProvider = new TestDateProvider();
|
|
327
334
|
const ethCheatCodes = new EthCheatCodesWithState(config.l1RpcUrls, dateProvider);
|
|
328
335
|
|
|
329
336
|
if (opts.stateLoad) {
|
|
@@ -373,10 +380,12 @@ export async function setup(
|
|
|
373
380
|
addressesToFund.push(sponsoredFPCAddress);
|
|
374
381
|
}
|
|
375
382
|
|
|
376
|
-
const
|
|
383
|
+
const genesisTimestamp = BigInt(Math.floor(Date.now() / 1000));
|
|
384
|
+
const { genesisArchiveRoot, genesis, fundingNeeded } = await getGenesisValues(
|
|
377
385
|
addressesToFund,
|
|
378
386
|
opts.initialAccountFeeJuice,
|
|
379
387
|
opts.genesisPublicData,
|
|
388
|
+
genesisTimestamp,
|
|
380
389
|
);
|
|
381
390
|
|
|
382
391
|
const wasAutomining = await ethCheatCodes.isAutoMining();
|
|
@@ -419,11 +428,12 @@ export async function setup(
|
|
|
419
428
|
await ethCheatCodes.setIntervalMining(config.ethereumSlotDuration);
|
|
420
429
|
}
|
|
421
430
|
|
|
422
|
-
//
|
|
423
|
-
//
|
|
424
|
-
//
|
|
425
|
-
|
|
426
|
-
|
|
431
|
+
// In compose mode (no local anvil), sync dateProvider to L1 time since it may have drifted
|
|
432
|
+
// ahead of system time due to the local-network watcher warping time forward on each filled slot.
|
|
433
|
+
// When running with a local anvil, the dateProvider is kept in sync via the stdout listener.
|
|
434
|
+
if (!anvil) {
|
|
435
|
+
dateProvider.setTime((await ethCheatCodes.lastBlockTimestamp()) * 1000);
|
|
436
|
+
}
|
|
427
437
|
|
|
428
438
|
if (opts.l2StartTime) {
|
|
429
439
|
await ethCheatCodes.warp(opts.l2StartTime, { resetBlockInterval: true });
|
|
@@ -464,7 +474,7 @@ export async function setup(
|
|
|
464
474
|
let p2pClientDeps: P2PClientDeps | undefined = undefined;
|
|
465
475
|
|
|
466
476
|
if (opts.mockGossipSubNetwork) {
|
|
467
|
-
mockGossipSubNetwork = new MockGossipSubNetwork();
|
|
477
|
+
mockGossipSubNetwork = new MockGossipSubNetwork(opts.mockGossipSubNetworkLatency);
|
|
468
478
|
p2pClientDeps = { p2pServiceFactory: getMockPubSubP2PServiceFactory(mockGossipSubNetwork) };
|
|
469
479
|
}
|
|
470
480
|
|
|
@@ -493,11 +503,7 @@ export async function setup(
|
|
|
493
503
|
}
|
|
494
504
|
|
|
495
505
|
const aztecNodeService = await withLoggerBindings({ actor: 'node-0' }, () =>
|
|
496
|
-
AztecNodeService.createAndSync(
|
|
497
|
-
config,
|
|
498
|
-
{ dateProvider, telemetry: telemetryClient, p2pClientDeps },
|
|
499
|
-
{ prefilledPublicData },
|
|
500
|
-
),
|
|
506
|
+
AztecNodeService.createAndSync(config, { dateProvider, telemetry: telemetryClient, p2pClientDeps }, { genesis }),
|
|
501
507
|
);
|
|
502
508
|
const sequencerClient = aztecNodeService.getSequencer();
|
|
503
509
|
|
|
@@ -521,7 +527,7 @@ export async function setup(
|
|
|
521
527
|
dataDirectory: proverNodeDataDirectory,
|
|
522
528
|
},
|
|
523
529
|
{ dateProvider, p2pClientDeps, telemetry: telemetryClient },
|
|
524
|
-
{
|
|
530
|
+
{ genesis },
|
|
525
531
|
));
|
|
526
532
|
}
|
|
527
533
|
|
|
@@ -626,7 +632,7 @@ export async function setup(
|
|
|
626
632
|
initialFundedAccounts,
|
|
627
633
|
logger,
|
|
628
634
|
mockGossipSubNetwork,
|
|
629
|
-
|
|
635
|
+
genesis,
|
|
630
636
|
proverNode,
|
|
631
637
|
sequencerDelayer,
|
|
632
638
|
proverDelayer,
|
|
@@ -726,7 +732,7 @@ export function createAndSyncProverNode(
|
|
|
726
732
|
dateProvider: DateProvider;
|
|
727
733
|
p2pClientDeps?: P2PClientDeps;
|
|
728
734
|
},
|
|
729
|
-
options: {
|
|
735
|
+
options: { genesis?: GenesisData; dontStart?: boolean },
|
|
730
736
|
): Promise<{ proverNode: AztecNodeService }> {
|
|
731
737
|
return withLoggerBindings({ actor: 'prover-0' }, async () => {
|
|
732
738
|
const proverNode = await AztecNodeService.createAndSync(
|
|
@@ -739,7 +745,7 @@ export function createAndSyncProverNode(
|
|
|
739
745
|
proverPublisherPrivateKeys: [new SecretValue(proverNodePrivateKey)],
|
|
740
746
|
},
|
|
741
747
|
deps,
|
|
742
|
-
{
|
|
748
|
+
{ genesis: options.genesis, dontStartProverNode: options.dontStart },
|
|
743
749
|
);
|
|
744
750
|
|
|
745
751
|
if (!proverNode.getProverNode()) {
|
|
@@ -830,7 +836,7 @@ export async function ensureAccountContractsPublished(wallet: Wallet, accountsTo
|
|
|
830
836
|
* Returns deployed account data that can be used by tests.
|
|
831
837
|
*/
|
|
832
838
|
export const deployAccounts =
|
|
833
|
-
(numberOfAccounts: number, logger: Logger) =>
|
|
839
|
+
(numberOfAccounts: number, logger: Logger, deployOptions?: Partial<DeployOptions<DeployInteractionWaitOptions>>) =>
|
|
834
840
|
async ({ wallet, initialFundedAccounts }: { wallet: TestWallet; initialFundedAccounts: InitialAccountData[] }) => {
|
|
835
841
|
if (initialFundedAccounts.length < numberOfAccounts) {
|
|
836
842
|
throw new Error(`Cannot deploy more than ${initialFundedAccounts.length} initial accounts.`);
|
|
@@ -847,8 +853,9 @@ export const deployAccounts =
|
|
|
847
853
|
);
|
|
848
854
|
const deployMethod = await accountManager.getDeployMethod();
|
|
849
855
|
await deployMethod.send({
|
|
850
|
-
from:
|
|
856
|
+
from: NO_FROM,
|
|
851
857
|
skipClassPublication: i !== 0, // Publish the contract class at most once.
|
|
858
|
+
...deployOptions,
|
|
852
859
|
});
|
|
853
860
|
}
|
|
854
861
|
|
|
@@ -7,7 +7,7 @@ import { SecretValue } from '@aztec/foundation/config';
|
|
|
7
7
|
import { withLoggerBindings } from '@aztec/foundation/log/server';
|
|
8
8
|
import { bufferToHex } from '@aztec/foundation/string';
|
|
9
9
|
import type { DateProvider } from '@aztec/foundation/timer';
|
|
10
|
-
import type {
|
|
10
|
+
import type { GenesisData } from '@aztec/stdlib/world-state';
|
|
11
11
|
|
|
12
12
|
import getPort from 'get-port';
|
|
13
13
|
|
|
@@ -40,7 +40,7 @@ export async function createNodes(
|
|
|
40
40
|
bootstrapNodeEnr: string,
|
|
41
41
|
numNodes: number,
|
|
42
42
|
bootNodePort: number,
|
|
43
|
-
|
|
43
|
+
genesis?: GenesisData,
|
|
44
44
|
dataDirectory?: string,
|
|
45
45
|
metricsPort?: number,
|
|
46
46
|
indexOffset = 0,
|
|
@@ -65,7 +65,7 @@ export async function createNodes(
|
|
|
65
65
|
port,
|
|
66
66
|
bootstrapNodeEnr,
|
|
67
67
|
validatorIndices,
|
|
68
|
-
|
|
68
|
+
genesis,
|
|
69
69
|
dataDir,
|
|
70
70
|
metricsPort,
|
|
71
71
|
);
|
|
@@ -97,7 +97,7 @@ export async function createNode(
|
|
|
97
97
|
tcpPort: number,
|
|
98
98
|
bootstrapNode: string | undefined,
|
|
99
99
|
addressIndex: number | number[],
|
|
100
|
-
|
|
100
|
+
genesis?: GenesisData,
|
|
101
101
|
dataDirectory?: string,
|
|
102
102
|
metricsPort?: number,
|
|
103
103
|
) {
|
|
@@ -108,7 +108,7 @@ export async function createNode(
|
|
|
108
108
|
return await AztecNodeService.createAndSync(
|
|
109
109
|
validatorConfig,
|
|
110
110
|
{ telemetry, dateProvider },
|
|
111
|
-
{
|
|
111
|
+
{ genesis, dontStartSequencer: config.dontStartSequencer },
|
|
112
112
|
);
|
|
113
113
|
});
|
|
114
114
|
}
|
|
@@ -119,7 +119,7 @@ export async function createNonValidatorNode(
|
|
|
119
119
|
dateProvider: DateProvider,
|
|
120
120
|
tcpPort: number,
|
|
121
121
|
bootstrapNode: string | undefined,
|
|
122
|
-
|
|
122
|
+
genesis?: GenesisData,
|
|
123
123
|
dataDirectory?: string,
|
|
124
124
|
metricsPort?: number,
|
|
125
125
|
) {
|
|
@@ -133,7 +133,7 @@ export async function createNonValidatorNode(
|
|
|
133
133
|
sequencerPublisherPrivateKeys: [],
|
|
134
134
|
};
|
|
135
135
|
const telemetry = await getEndToEndTestTelemetryClient(metricsPort);
|
|
136
|
-
return await AztecNodeService.createAndSync(config, { telemetry, dateProvider }, {
|
|
136
|
+
return await AztecNodeService.createAndSync(config, { telemetry, dateProvider }, { genesis });
|
|
137
137
|
});
|
|
138
138
|
}
|
|
139
139
|
|
|
@@ -143,7 +143,7 @@ export async function createProverNode(
|
|
|
143
143
|
bootstrapNode: string | undefined,
|
|
144
144
|
addressIndex: number,
|
|
145
145
|
deps: { dateProvider: DateProvider },
|
|
146
|
-
|
|
146
|
+
genesis?: GenesisData,
|
|
147
147
|
dataDirectory?: string,
|
|
148
148
|
metricsPort?: number,
|
|
149
149
|
): Promise<{ proverNode: AztecNodeService }> {
|
|
@@ -159,7 +159,7 @@ export async function createProverNode(
|
|
|
159
159
|
{ ...config, ...p2pConfig },
|
|
160
160
|
{ dataDirectory },
|
|
161
161
|
{ ...deps, telemetry },
|
|
162
|
-
{
|
|
162
|
+
{ genesis },
|
|
163
163
|
);
|
|
164
164
|
});
|
|
165
165
|
}
|
|
@@ -6,11 +6,8 @@ import { TokenContract } from '@aztec/noir-contracts.js/Token';
|
|
|
6
6
|
|
|
7
7
|
export async function deployToken(wallet: Wallet, admin: AztecAddress, initialAdminBalance: bigint, logger: Logger) {
|
|
8
8
|
logger.info(`Deploying Token contract...`);
|
|
9
|
-
const {
|
|
10
|
-
receipt: { contract, instance },
|
|
11
|
-
} = await TokenContract.deploy(wallet, admin, 'TokenName', 'TokenSymbol', 18).send({
|
|
9
|
+
const { contract, instance } = await TokenContract.deploy(wallet, admin, 'TokenName', 'TokenSymbol', 18).send({
|
|
12
10
|
from: admin,
|
|
13
|
-
wait: { returnReceipt: true },
|
|
14
11
|
});
|
|
15
12
|
|
|
16
13
|
if (initialAdminBalance > 0n) {
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// Custom Jest resolver. When CONTRACT_ARTIFACTS_VERSION is set, redirects *only* JSON artifact files under
|
|
2
|
+
// @aztec/noir-contracts.js/artifacts/, @aztec/noir-test-contracts.js/artifacts/, and @aztec/accounts/artifacts/ to a local cache of the pinned
|
|
3
|
+
// legacy versions. TypeScript wrapper classes (e.g. Token.ts) continue to load from the current workspace and use the
|
|
4
|
+
// current @aztec/aztec.js — only the artifact JSON (the deployed-contract ABI / bytecode / notes surface) is swapped.
|
|
5
|
+
//
|
|
6
|
+
// Why JSON-only: the JSON artifact is the actual interchange surface a "deployed contract" exposes. The TS wrapper is
|
|
7
|
+
// generated client-side ergonomics that's tightly coupled to the current @aztec/aztec.js API. Redirecting the wrapper
|
|
8
|
+
// would couple this test to a moving aztec.js surface and break at import time on unrelated breaking changes; we want
|
|
9
|
+
// to fail only on actual artifact-compat regressions.
|
|
10
|
+
//
|
|
11
|
+
// The cache is populated on demand by running `npm install` into .legacy-contracts/<version>/.
|
|
12
|
+
//
|
|
13
|
+
// Activated by env var; passthrough otherwise.
|
|
14
|
+
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
15
|
+
|
|
16
|
+
const path = require('path');
|
|
17
|
+
const fs = require('fs');
|
|
18
|
+
const { execSync } = require('child_process');
|
|
19
|
+
|
|
20
|
+
const version = process.env.CONTRACT_ARTIFACTS_VERSION;
|
|
21
|
+
const REDIRECTED = ['@aztec/noir-contracts.js', '@aztec/noir-test-contracts.js', '@aztec/accounts'];
|
|
22
|
+
|
|
23
|
+
// Jest sets rootDir to <e2e>/src; this file lives there too.
|
|
24
|
+
const e2eRoot = path.resolve(__dirname, '..');
|
|
25
|
+
const cacheRoot = version ? path.join(e2eRoot, '.legacy-contracts', version) : null;
|
|
26
|
+
|
|
27
|
+
function pkgJsonPath(name) {
|
|
28
|
+
return path.join(cacheRoot, 'node_modules', name, 'package.json');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function ensureCache() {
|
|
32
|
+
const missing = REDIRECTED.some(p => !fs.existsSync(pkgJsonPath(p)));
|
|
33
|
+
if (!missing) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
fs.mkdirSync(cacheRoot, { recursive: true });
|
|
37
|
+
// Seed a standalone package.json so `npm install --prefix` treats cacheRoot as its own project. Without this, npm
|
|
38
|
+
// walks up and finds the yarn-project workspace root, which breaks on `workspace:` protocol deps and risks
|
|
39
|
+
// clobbering the monorepo's node_modules.
|
|
40
|
+
const seed = path.join(cacheRoot, 'package.json');
|
|
41
|
+
if (!fs.existsSync(seed)) {
|
|
42
|
+
fs.writeFileSync(seed, JSON.stringify({ name: 'legacy-contracts-cache', private: true }));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const specs = REDIRECTED.map(p => `${p}@${version}`).join(' ');
|
|
46
|
+
process.stderr.write(`[legacy-contracts] installing ${specs} into ${cacheRoot}\n`);
|
|
47
|
+
// --prefix: install into cacheRoot instead of cwd, so the cache is isolated from the monorepo.
|
|
48
|
+
// --no-save: don't write the installed packages back to the seeded package.json.
|
|
49
|
+
// --ignore-scripts: skip lifecycle scripts (preinstall/postinstall) of the legacy packages and their transitive
|
|
50
|
+
// deps; we only want the files on disk, not to run any build steps.
|
|
51
|
+
// --legacy-peer-deps: tolerate peer-dependency mismatches between the pinned legacy @aztec/* graph and whatever
|
|
52
|
+
// current versions npm would otherwise try to reconcile.
|
|
53
|
+
execSync(`npm install --prefix "${cacheRoot}" --no-save --ignore-scripts --legacy-peer-deps ${specs}`, {
|
|
54
|
+
stdio: 'inherit',
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Verify versions on disk match the requested version.
|
|
58
|
+
for (const p of REDIRECTED) {
|
|
59
|
+
const onDisk = JSON.parse(fs.readFileSync(pkgJsonPath(p), 'utf8')).version;
|
|
60
|
+
if (onDisk !== version) {
|
|
61
|
+
throw new Error(`[legacy-contracts] ${p} on disk is ${onDisk}, expected ${version}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (version) {
|
|
67
|
+
ensureCache();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
let bannerPrinted = false;
|
|
71
|
+
const seen = new Set();
|
|
72
|
+
|
|
73
|
+
function printBannerOnce() {
|
|
74
|
+
if (bannerPrinted || !version) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
bannerPrinted = true;
|
|
78
|
+
const lines = ['='.repeat(60), `[legacy-contracts][jest] CONTRACT_ARTIFACTS_VERSION=${version}`];
|
|
79
|
+
for (const p of REDIRECTED) {
|
|
80
|
+
const v = JSON.parse(fs.readFileSync(pkgJsonPath(p), 'utf8')).version;
|
|
81
|
+
if (v !== version) {
|
|
82
|
+
throw new Error(`[legacy-contracts] ${p} on disk is ${v}, expected ${version}`);
|
|
83
|
+
}
|
|
84
|
+
lines.push(`[legacy-contracts][jest] redirecting ${p}/artifacts/*.json -> .legacy-contracts/${version}/...`);
|
|
85
|
+
}
|
|
86
|
+
lines.push('='.repeat(60));
|
|
87
|
+
process.stderr.write(lines.join('\n') + '\n');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Match a resolved absolute path against the workspace artifacts dirs and return the legacy cache equivalent, or null
|
|
91
|
+
// if it's not an artifact path we should redirect.
|
|
92
|
+
function legacyArtifactPath(resolved) {
|
|
93
|
+
if (!resolved.endsWith('.json')) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
for (const pkg of REDIRECTED) {
|
|
97
|
+
// pkg = '@aztec/noir-contracts.js' -> match '/noir-contracts.js/artifacts/'
|
|
98
|
+
const dirName = pkg.split('/')[1];
|
|
99
|
+
const marker = `/${dirName}/artifacts/`;
|
|
100
|
+
const idx = resolved.indexOf(marker);
|
|
101
|
+
if (idx === -1) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const basename = resolved.slice(idx + marker.length);
|
|
105
|
+
return path.join(cacheRoot, 'node_modules', pkg, 'artifacts', basename);
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
module.exports = function legacyResolver(request, options) {
|
|
111
|
+
// Always run the default resolver first. We only inspect (and possibly rewrite) the *result*; this catches both
|
|
112
|
+
// bare-specifier imports of `@aztec/noir-contracts.js/artifacts/foo.json` and the relative `../artifacts/foo.json`
|
|
113
|
+
// imports inside the workspace TS wrapper classes — both resolve to the same workspace artifact path that we then
|
|
114
|
+
// redirect.
|
|
115
|
+
const resolved = options.defaultResolver(request, options);
|
|
116
|
+
if (!version) {
|
|
117
|
+
return resolved;
|
|
118
|
+
}
|
|
119
|
+
printBannerOnce();
|
|
120
|
+
const legacy = legacyArtifactPath(resolved);
|
|
121
|
+
if (!legacy) {
|
|
122
|
+
return resolved;
|
|
123
|
+
}
|
|
124
|
+
if (!fs.existsSync(legacy)) {
|
|
125
|
+
throw new Error(
|
|
126
|
+
`[legacy-contracts] artifact ${path.basename(legacy)} not present in legacy cache @${version}; ` +
|
|
127
|
+
`the contract may have been added after that release. Pin a newer CONTRACT_ARTIFACTS_VERSION or skip this test.`,
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
if (!seen.has(resolved)) {
|
|
131
|
+
seen.add(resolved);
|
|
132
|
+
process.stderr.write(`[legacy-contracts][jest] redirected ${path.basename(legacy)} -> ${legacy}\n`);
|
|
133
|
+
}
|
|
134
|
+
return legacy;
|
|
135
|
+
};
|
|
@@ -94,7 +94,9 @@ export class LendingSimulator {
|
|
|
94
94
|
|
|
95
95
|
async prepare() {
|
|
96
96
|
this.accumulator = BASE;
|
|
97
|
-
const slot = await this.rollup.getSlotAt(
|
|
97
|
+
const slot = await this.rollup.getSlotAt(
|
|
98
|
+
BigInt(await this.cc.eth.lastBlockTimestamp()) + BigInt(this.ethereumSlotDuration),
|
|
99
|
+
);
|
|
98
100
|
this.time = Number(await this.rollup.getTimestampForSlot(slot));
|
|
99
101
|
}
|
|
100
102
|
|
|
@@ -103,7 +105,7 @@ export class LendingSimulator {
|
|
|
103
105
|
return;
|
|
104
106
|
}
|
|
105
107
|
|
|
106
|
-
const slot = await this.rollup.getSlotAt(BigInt(await this.cc.eth.
|
|
108
|
+
const slot = await this.rollup.getSlotAt(BigInt(await this.cc.eth.lastBlockTimestamp()));
|
|
107
109
|
const targetSlot = SlotNumber(slot + diff);
|
|
108
110
|
const ts = Number(await this.rollup.getTimestampForSlot(targetSlot));
|
|
109
111
|
const timeDiff = ts - this.time;
|
|
@@ -110,7 +110,7 @@ export class TokenSimulator {
|
|
|
110
110
|
chunk(calls, 5).map(batch => new BatchCall(this.defaultWallet, batch).simulate({ from: this.defaultAddress })),
|
|
111
111
|
)
|
|
112
112
|
)
|
|
113
|
-
.
|
|
113
|
+
.flatMap(r => r.result)
|
|
114
114
|
.map(r => r.result);
|
|
115
115
|
expect(results[0]).toEqual(this.totalSupply);
|
|
116
116
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { generateSchnorrAccounts } from '@aztec/accounts/testing';
|
|
2
|
+
import { NO_FROM } from '@aztec/aztec.js/account';
|
|
2
3
|
import { AztecAddress } from '@aztec/aztec.js/addresses';
|
|
3
4
|
import { NO_WAIT } from '@aztec/aztec.js/contracts';
|
|
4
5
|
import { L1FeeJuicePortalManager } from '@aztec/aztec.js/ethereum';
|
|
@@ -10,7 +11,7 @@ import type { Wallet } from '@aztec/aztec.js/wallet';
|
|
|
10
11
|
import { createEthereumChain } from '@aztec/ethereum/chain';
|
|
11
12
|
import { createExtendedL1Client } from '@aztec/ethereum/client';
|
|
12
13
|
import type { Logger } from '@aztec/foundation/log';
|
|
13
|
-
import { retryUntil } from '@aztec/foundation/retry';
|
|
14
|
+
import { makeBackoff, retry, retryUntil } from '@aztec/foundation/retry';
|
|
14
15
|
import { TokenContract } from '@aztec/noir-contracts.js/Token';
|
|
15
16
|
import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
|
|
16
17
|
import { registerInitialLocalNetworkAccountsInWallet } from '@aztec/wallets/testing';
|
|
@@ -89,7 +90,7 @@ export async function deploySponsoredTestAccountsWithTokens(
|
|
|
89
90
|
const paymentMethod = new SponsoredFeePaymentMethod(await getSponsoredFPCAddress());
|
|
90
91
|
const recipientDeployMethod = await recipientAccount.getDeployMethod();
|
|
91
92
|
await recipientDeployMethod.send({
|
|
92
|
-
from:
|
|
93
|
+
from: NO_FROM,
|
|
93
94
|
fee: { paymentMethod },
|
|
94
95
|
wait: { timeout: 2400 },
|
|
95
96
|
});
|
|
@@ -97,7 +98,7 @@ export async function deploySponsoredTestAccountsWithTokens(
|
|
|
97
98
|
fundedAccounts.map(async a => {
|
|
98
99
|
const deployMethod = await a.getDeployMethod();
|
|
99
100
|
await deployMethod.send({
|
|
100
|
-
from:
|
|
101
|
+
from: NO_FROM,
|
|
101
102
|
fee: { paymentMethod },
|
|
102
103
|
wait: { timeout: 2400 },
|
|
103
104
|
}); // increase timeout on purpose in order to account for two empty epochs
|
|
@@ -137,38 +138,57 @@ async function deployAccountWithDiagnostics(
|
|
|
137
138
|
estimateGas?: boolean,
|
|
138
139
|
): Promise<void> {
|
|
139
140
|
const deployMethod = await account.getDeployMethod();
|
|
140
|
-
let
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
gasSettings = sim.estimatedGas;
|
|
146
|
-
logger.info(`${accountLabel} estimated gas: DA=${gasSettings.gasLimits.daGas} L2=${gasSettings.gasLimits.l2Gas}`);
|
|
147
|
-
}
|
|
148
|
-
const deployResult = await deployMethod.send({
|
|
149
|
-
from: AztecAddress.ZERO,
|
|
150
|
-
fee: { paymentMethod, gasSettings },
|
|
151
|
-
wait: NO_WAIT,
|
|
152
|
-
});
|
|
153
|
-
txHash = deployResult.txHash;
|
|
154
|
-
await waitForTx(aztecNode, txHash, { timeout: 2400 });
|
|
155
|
-
logger.info(`${accountLabel} deployed at ${account.address}`);
|
|
156
|
-
} catch (error) {
|
|
157
|
-
const blockNumber = await aztecNode.getBlockNumber();
|
|
158
|
-
let receipt;
|
|
159
|
-
try {
|
|
160
|
-
receipt = await aztecNode.getTxReceipt(txHash);
|
|
161
|
-
} catch {
|
|
162
|
-
receipt = 'unavailable';
|
|
163
|
-
}
|
|
164
|
-
logger.error(`${accountLabel} deployment failed`, {
|
|
165
|
-
txHash: txHash.toString(),
|
|
166
|
-
receipt: JSON.stringify(receipt),
|
|
167
|
-
currentBlockNumber: blockNumber,
|
|
168
|
-
error: String(error),
|
|
169
|
-
});
|
|
170
|
-
throw error;
|
|
141
|
+
let gasSettings: any;
|
|
142
|
+
if (estimateGas) {
|
|
143
|
+
const sim = await deployMethod.simulate({ from: NO_FROM, fee: { paymentMethod } });
|
|
144
|
+
gasSettings = sim.estimatedGas;
|
|
145
|
+
logger.info(`${accountLabel} estimated gas: DA=${gasSettings.gasLimits.daGas} L2=${gasSettings.gasLimits.l2Gas}`);
|
|
171
146
|
}
|
|
147
|
+
|
|
148
|
+
// Track the tx hash across retries so we don't re-send when the previous tx is still pending.
|
|
149
|
+
let sentTxHash: { txHash: any } | undefined;
|
|
150
|
+
|
|
151
|
+
await retry(
|
|
152
|
+
async () => {
|
|
153
|
+
// Check if already deployed (handles case where previous attempt succeeded but waitForTx timed out)
|
|
154
|
+
const existing = await aztecNode.getContract(account.address);
|
|
155
|
+
if (existing) {
|
|
156
|
+
logger.info(`${accountLabel} already deployed at ${account.address}, skipping`);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// If we already sent a tx, check if it was dropped before deciding to re-send.
|
|
161
|
+
if (sentTxHash) {
|
|
162
|
+
const prevReceipt = await aztecNode.getTxReceipt(sentTxHash.txHash);
|
|
163
|
+
if (prevReceipt.isDropped()) {
|
|
164
|
+
logger.info(`${accountLabel} previous tx ${sentTxHash.txHash} was dropped, re-sending`);
|
|
165
|
+
sentTxHash = undefined;
|
|
166
|
+
} else {
|
|
167
|
+
logger.info(`${accountLabel} previous tx ${sentTxHash.txHash} still pending, waiting again...`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (!sentTxHash) {
|
|
172
|
+
const deployResult = await deployMethod.send({
|
|
173
|
+
from: NO_FROM,
|
|
174
|
+
fee: { paymentMethod, gasSettings },
|
|
175
|
+
wait: NO_WAIT,
|
|
176
|
+
});
|
|
177
|
+
sentTxHash = { txHash: deployResult.txHash };
|
|
178
|
+
logger.info(`${accountLabel} tx sent`, { txHash: sentTxHash.txHash.toString() });
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const receipt = await waitForTx(aztecNode, sentTxHash.txHash, { timeout: 600 });
|
|
182
|
+
if (receipt.isDropped()) {
|
|
183
|
+
sentTxHash = undefined;
|
|
184
|
+
throw new Error(`${accountLabel} tx was dropped, retrying...`);
|
|
185
|
+
}
|
|
186
|
+
logger.info(`${accountLabel} deployed at ${account.address}`);
|
|
187
|
+
},
|
|
188
|
+
`deploy ${accountLabel}`,
|
|
189
|
+
makeBackoff([1, 2, 4, 8, 16]),
|
|
190
|
+
logger,
|
|
191
|
+
);
|
|
172
192
|
}
|
|
173
193
|
|
|
174
194
|
async function deployAccountsInBatches(
|
|
@@ -269,7 +289,7 @@ export async function deployTestAccountsWithTokens(
|
|
|
269
289
|
fundedAccounts.map(async (a, i) => {
|
|
270
290
|
const paymentMethod = new FeeJuicePaymentMethodWithClaim(a.address, claims[i]);
|
|
271
291
|
const deployMethod = await a.getDeployMethod();
|
|
272
|
-
await deployMethod.send({ from:
|
|
292
|
+
await deployMethod.send({ from: NO_FROM, fee: { paymentMethod } });
|
|
273
293
|
logger.info(`Account deployed at ${a.address}`);
|
|
274
294
|
}),
|
|
275
295
|
);
|
|
@@ -345,14 +365,18 @@ async function deployTokenAndMint(
|
|
|
345
365
|
logger: Logger,
|
|
346
366
|
) {
|
|
347
367
|
logger.verbose(`Deploying TokenContract...`);
|
|
348
|
-
const {
|
|
349
|
-
|
|
350
|
-
|
|
368
|
+
const { contract: tokenContract } = await TokenContract.deploy(
|
|
369
|
+
wallet,
|
|
370
|
+
admin,
|
|
371
|
+
TOKEN_NAME,
|
|
372
|
+
TOKEN_SYMBOL,
|
|
373
|
+
TOKEN_DECIMALS,
|
|
374
|
+
).send({
|
|
351
375
|
from: admin,
|
|
352
376
|
fee: {
|
|
353
377
|
paymentMethod,
|
|
354
378
|
},
|
|
355
|
-
wait: { timeout: 600
|
|
379
|
+
wait: { timeout: 600 },
|
|
356
380
|
});
|
|
357
381
|
|
|
358
382
|
const tokenAddress = tokenContract.address;
|