@aztec/end-to-end 0.0.1-commit.e588bc7e5 → 0.0.1-commit.e5a3663dd
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.js +3 -3
- 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_cross_chain_messaging/cross_chain_messaging_test.js +1 -1
- package/dest/e2e_epochs/epochs_test.d.ts +16 -1
- package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
- package/dest/e2e_epochs/epochs_test.js +56 -8
- 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 +4 -4
- package/dest/e2e_p2p/inactivity_slash_test.js +2 -2
- package/dest/e2e_p2p/p2p_network.d.ts +10 -9
- package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
- package/dest/e2e_p2p/p2p_network.js +46 -27
- package/dest/e2e_p2p/reqresp/utils.d.ts +1 -1
- package/dest/e2e_p2p/reqresp/utils.d.ts.map +1 -1
- package/dest/e2e_p2p/reqresp/utils.js +10 -7
- 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 +36 -47
- 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 +1 -1
- package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
- package/dest/fixtures/e2e_prover_test.js +2 -2
- package/dest/fixtures/fixtures.d.ts +12 -1
- package/dest/fixtures/fixtures.d.ts.map +1 -1
- package/dest/fixtures/fixtures.js +10 -0
- package/dest/fixtures/ha_setup.d.ts +2 -2
- package/dest/fixtures/ha_setup.d.ts.map +1 -1
- package/dest/fixtures/ha_setup.js +1 -1
- package/dest/fixtures/schnorr_hardcoded_account_contract.d.ts +25 -0
- package/dest/fixtures/schnorr_hardcoded_account_contract.d.ts.map +1 -0
- package/dest/fixtures/schnorr_hardcoded_account_contract.js +39 -0
- package/dest/fixtures/setup.d.ts +17 -10
- package/dest/fixtures/setup.d.ts.map +1 -1
- package/dest/fixtures/setup.js +29 -13
- 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/forward-compatibility/wallet_rpc_client.d.ts +7 -0
- package/dest/forward-compatibility/wallet_rpc_client.d.ts.map +1 -0
- package/dest/forward-compatibility/wallet_rpc_client.js +15 -0
- package/dest/forward-compatibility/wallet_service.d.ts +3 -0
- package/dest/forward-compatibility/wallet_service.d.ts.map +1 -0
- package/dest/forward-compatibility/wallet_service.js +109 -0
- package/dest/legacy-jest-resolver.d.cts +3 -0
- package/dest/legacy-jest-resolver.d.cts.map +1 -0
- package/dest/shared/gas_portal_test_harness.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 +0 -4
- 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 +6 -37
- package/dest/spartan/tx_metrics.d.ts +1 -1
- package/dest/spartan/tx_metrics.d.ts.map +1 -1
- package/dest/spartan/tx_metrics.js +18 -2
- package/dest/test-wallet/test_wallet.d.ts +16 -8
- package/dest/test-wallet/test_wallet.d.ts.map +1 -1
- package/dest/test-wallet/test_wallet.js +91 -49
- 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 +7 -2
- 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 +3 -3
- package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +3 -6
- package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +1 -1
- package/src/e2e_epochs/epochs_test.ts +56 -7
- package/src/e2e_fees/fees_test.ts +5 -3
- package/src/e2e_p2p/inactivity_slash_test.ts +2 -2
- package/src/e2e_p2p/p2p_network.ts +57 -39
- package/src/e2e_p2p/reqresp/utils.ts +8 -7
- package/src/e2e_p2p/shared.ts +33 -61
- package/src/fixtures/authwit_proxy.ts +4 -0
- package/src/fixtures/e2e_prover_test.ts +5 -2
- package/src/fixtures/fixtures.ts +22 -0
- package/src/fixtures/ha_setup.ts +4 -2
- package/src/fixtures/schnorr_hardcoded_account_contract.ts +49 -0
- package/src/fixtures/setup.ts +44 -18
- package/src/fixtures/setup_p2p_test.ts +9 -9
- package/src/forward-compatibility/wallet_rpc_client.ts +14 -0
- package/src/forward-compatibility/wallet_service.ts +104 -0
- package/src/guides/up_quick_start.sh +0 -2
- package/src/legacy-jest-resolver.cjs +135 -0
- package/src/shared/gas_portal_test_harness.ts +0 -1
- package/src/shared/uniswap_l1_l2.ts +0 -4
- package/src/spartan/setup_test_wallets.ts +4 -30
- package/src/spartan/tx_metrics.ts +16 -4
- package/src/test-wallet/test_wallet.ts +108 -52
- package/src/test-wallet/worker_wallet.ts +3 -2
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { DefaultAccountContract } from '@aztec/accounts/defaults';
|
|
2
|
+
import type { ContractArtifact } from '@aztec/aztec.js/abi';
|
|
3
|
+
import type { AuthWitnessProvider } from '@aztec/aztec.js/account';
|
|
4
|
+
import type { CompleteAddress } from '@aztec/aztec.js/addresses';
|
|
5
|
+
import { AuthWitness } from '@aztec/aztec.js/authorization';
|
|
6
|
+
import type { Fr } from '@aztec/aztec.js/fields';
|
|
7
|
+
import { Schnorr } from '@aztec/foundation/crypto/schnorr';
|
|
8
|
+
import { GrumpkinScalar } from '@aztec/foundation/curves/grumpkin';
|
|
9
|
+
import { SchnorrHardcodedAccountContractArtifact } from '@aztec/noir-contracts.js/SchnorrHardcodedAccount';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The private key that matches the hardcoded public key in the SchnorrHardcodedAccountContract.
|
|
13
|
+
* The corresponding public key is baked into the Noir contract as a global constant.
|
|
14
|
+
*/
|
|
15
|
+
export const SCHNORR_HARDCODED_PRIVATE_KEY = GrumpkinScalar.fromHexString(
|
|
16
|
+
'0xd35d743ac0dfe3d6dbe6be8c877cb524a00ab1e3d52d7bada095dfc8894ccfa',
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Account contract backed by the SchnorrHardcodedAccount Noir contract.
|
|
21
|
+
* This contract verifies Schnorr signatures against a public key that is hardcoded
|
|
22
|
+
* in the contract artifact (not stored in a note), so it does not require on-chain
|
|
23
|
+
* deployment or initialization. Useful for tests that need a working account without
|
|
24
|
+
* mining any blocks.
|
|
25
|
+
*/
|
|
26
|
+
export class SchnorrHardcodedKeyAccountContract extends DefaultAccountContract {
|
|
27
|
+
constructor(private privateKey: GrumpkinScalar = SCHNORR_HARDCODED_PRIVATE_KEY) {
|
|
28
|
+
super();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
override getContractArtifact(): Promise<ContractArtifact> {
|
|
32
|
+
return Promise.resolve(SchnorrHardcodedAccountContractArtifact);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
getInitializationFunctionAndArgs() {
|
|
36
|
+
return Promise.resolve(undefined);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
getAuthWitnessProvider(_address: CompleteAddress): AuthWitnessProvider {
|
|
40
|
+
const privateKey = this.privateKey;
|
|
41
|
+
return {
|
|
42
|
+
async createAuthWit(messageHash: Fr): Promise<AuthWitness> {
|
|
43
|
+
const signer = new Schnorr();
|
|
44
|
+
const signature = await signer.constructSignature(messageHash.toBuffer(), privateKey);
|
|
45
|
+
return new AuthWitness(messageHash, [...signature.toBuffer()]);
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
package/src/fixtures/setup.ts
CHANGED
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
BatchCall,
|
|
8
8
|
type ContractFunctionInteraction,
|
|
9
9
|
type ContractMethod,
|
|
10
|
+
type DeployInteractionWaitOptions,
|
|
11
|
+
type DeployOptions,
|
|
10
12
|
getContractClassFromArtifact,
|
|
11
13
|
waitForProven,
|
|
12
14
|
} from '@aztec/aztec.js/contracts';
|
|
@@ -15,7 +17,7 @@ import { Fr } from '@aztec/aztec.js/fields';
|
|
|
15
17
|
import { type Logger, createLogger } from '@aztec/aztec.js/log';
|
|
16
18
|
import type { AztecNode } from '@aztec/aztec.js/node';
|
|
17
19
|
import type { Wallet } from '@aztec/aztec.js/wallet';
|
|
18
|
-
import { AnvilTestWatcher, CheatCodes } from '@aztec/aztec/testing';
|
|
20
|
+
import { AnvilTestWatcher, type AnvilTestWatcherOpts, CheatCodes } from '@aztec/aztec/testing';
|
|
19
21
|
import { SPONSORED_FPC_SALT } from '@aztec/constants';
|
|
20
22
|
import { isAnvilTestChain } from '@aztec/ethereum/chain';
|
|
21
23
|
import { createExtendedL1Client } from '@aztec/ethereum/client';
|
|
@@ -49,9 +51,10 @@ import type { ProverNodeConfig } from '@aztec/prover-node';
|
|
|
49
51
|
import { type PXEConfig, getPXEConfig } from '@aztec/pxe/server';
|
|
50
52
|
import type { SequencerClient } from '@aztec/sequencer-client';
|
|
51
53
|
import { type ContractInstanceWithAddress, getContractInstanceFromInstantiationParams } from '@aztec/stdlib/contract';
|
|
52
|
-
import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
|
|
54
|
+
import type { AztecNodeAdmin, AztecNodeDebug } from '@aztec/stdlib/interfaces/client';
|
|
53
55
|
import { tryStop } from '@aztec/stdlib/interfaces/server';
|
|
54
56
|
import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees';
|
|
57
|
+
import type { GenesisData } from '@aztec/stdlib/world-state';
|
|
55
58
|
import {
|
|
56
59
|
type TelemetryClient,
|
|
57
60
|
type TelemetryClientConfig,
|
|
@@ -178,8 +181,11 @@ export type SetupOptions = {
|
|
|
178
181
|
proverNodeConfig?: Partial<ProverNodeConfig>;
|
|
179
182
|
/** Whether to use a mock gossip sub network for p2p clients. */
|
|
180
183
|
mockGossipSubNetwork?: boolean;
|
|
184
|
+
/** Whether to add simulated latency to the mock gossipsub network (in ms) */
|
|
185
|
+
mockGossipSubNetworkLatency?: number;
|
|
181
186
|
/** Whether to disable the anvil test watcher (can still be manually started) */
|
|
182
187
|
disableAnvilTestWatcher?: boolean;
|
|
188
|
+
anvilTestWatcherOpts?: AnvilTestWatcherOpts;
|
|
183
189
|
/** Whether to enable anvil automine during deployment of L1 contracts (consider defaulting this to true). */
|
|
184
190
|
automineL1Setup?: boolean;
|
|
185
191
|
/** How many accounts to seed and unlock in anvil. */
|
|
@@ -201,8 +207,11 @@ export type SetupOptions = {
|
|
|
201
207
|
skipAccountDeployment?: boolean;
|
|
202
208
|
/** L1 contracts deployment arguments. */
|
|
203
209
|
l1ContractsArgs?: Partial<DeployAztecL1ContractsArgs>;
|
|
204
|
-
/** Wallet minimum fee padding multiplier
|
|
210
|
+
/** Wallet minimum fee padding multiplier */
|
|
205
211
|
walletMinFeePadding?: number;
|
|
212
|
+
/** Whether the initial node should be a lightweight RPC-only node (no sequencer, no validator).
|
|
213
|
+
* Use for tests that create their own validator nodes and don't need the initial sequencer. */
|
|
214
|
+
skipInitialSequencer?: boolean;
|
|
206
215
|
} & Partial<AztecNodeConfig>;
|
|
207
216
|
|
|
208
217
|
/** Context for an end-to-end test as returned by the `setup` function */
|
|
@@ -210,7 +219,7 @@ export type EndToEndContext = {
|
|
|
210
219
|
/** The Anvil instance (only set if anvil was started locally). */
|
|
211
220
|
anvil: Anvil | undefined;
|
|
212
221
|
/** The Aztec Node service or client a connected to it. */
|
|
213
|
-
aztecNode: AztecNode;
|
|
222
|
+
aztecNode: AztecNode & AztecNodeDebug;
|
|
214
223
|
/** The Aztec Node as a service. */
|
|
215
224
|
aztecNodeService: AztecNodeService;
|
|
216
225
|
/** Client to the Aztec Node admin interface. */
|
|
@@ -249,8 +258,8 @@ export type EndToEndContext = {
|
|
|
249
258
|
sequencerDelayer: Delayer | undefined;
|
|
250
259
|
/** Delayer for prover node L1 txs (only when enableDelayer and startProverNode are true). */
|
|
251
260
|
proverDelayer: Delayer | undefined;
|
|
252
|
-
/**
|
|
253
|
-
|
|
261
|
+
/** Genesis data used for setting up nodes. */
|
|
262
|
+
genesis: GenesisData | undefined;
|
|
254
263
|
/** ACVM config (only set if running locally). */
|
|
255
264
|
acvmConfig: Awaited<ReturnType<typeof getACVMConfig>>;
|
|
256
265
|
/** BB config (only set if running locally). */
|
|
@@ -276,7 +285,7 @@ export async function setup(
|
|
|
276
285
|
let anvil: Anvil | undefined;
|
|
277
286
|
try {
|
|
278
287
|
opts.aztecTargetCommitteeSize ??= 0;
|
|
279
|
-
opts.
|
|
288
|
+
opts.slasherEnabled ??= false;
|
|
280
289
|
|
|
281
290
|
const config: AztecNodeConfig & SetupOptions = { ...getConfigEnvVars(), ...opts };
|
|
282
291
|
// use initialValidators for the node config
|
|
@@ -375,10 +384,12 @@ export async function setup(
|
|
|
375
384
|
addressesToFund.push(sponsoredFPCAddress);
|
|
376
385
|
}
|
|
377
386
|
|
|
378
|
-
const
|
|
387
|
+
const genesisTimestamp = BigInt(Math.floor(Date.now() / 1000));
|
|
388
|
+
const { genesisArchiveRoot, genesis, fundingNeeded } = await getGenesisValues(
|
|
379
389
|
addressesToFund,
|
|
380
390
|
opts.initialAccountFeeJuice,
|
|
381
391
|
opts.genesisPublicData,
|
|
392
|
+
genesisTimestamp,
|
|
382
393
|
);
|
|
383
394
|
|
|
384
395
|
const wasAutomining = await ethCheatCodes.isAutoMining();
|
|
@@ -437,6 +448,7 @@ export async function setup(
|
|
|
437
448
|
deployL1ContractsValues.l1ContractAddresses.rollupAddress,
|
|
438
449
|
deployL1ContractsValues.l1Client,
|
|
439
450
|
dateProvider,
|
|
451
|
+
opts.anvilTestWatcherOpts,
|
|
440
452
|
);
|
|
441
453
|
if (!opts.disableAnvilTestWatcher) {
|
|
442
454
|
await watcher.start();
|
|
@@ -467,7 +479,7 @@ export async function setup(
|
|
|
467
479
|
let p2pClientDeps: P2PClientDeps | undefined = undefined;
|
|
468
480
|
|
|
469
481
|
if (opts.mockGossipSubNetwork) {
|
|
470
|
-
mockGossipSubNetwork = new MockGossipSubNetwork();
|
|
482
|
+
mockGossipSubNetwork = new MockGossipSubNetwork(opts.mockGossipSubNetworkLatency);
|
|
471
483
|
p2pClientDeps = { p2pServiceFactory: getMockPubSubP2PServiceFactory(mockGossipSubNetwork) };
|
|
472
484
|
}
|
|
473
485
|
|
|
@@ -495,11 +507,22 @@ export async function setup(
|
|
|
495
507
|
}
|
|
496
508
|
}
|
|
497
509
|
|
|
510
|
+
// When skipInitialSequencer is set, the initial node is a lightweight RPC-only node.
|
|
511
|
+
// We apply these overrides to a copy so they don't leak into the returned config.
|
|
512
|
+
// Keep P2P enabled if mockGossipSubNetwork is used (needed for tx propagation to validators).
|
|
513
|
+
const initialNodeConfig = opts.skipInitialSequencer
|
|
514
|
+
? {
|
|
515
|
+
...config,
|
|
516
|
+
disableValidator: true,
|
|
517
|
+
...(opts.mockGossipSubNetwork ? {} : { p2pEnabled: false, bootstrapNodes: [] as string[] }),
|
|
518
|
+
}
|
|
519
|
+
: config;
|
|
520
|
+
|
|
498
521
|
const aztecNodeService = await withLoggerBindings({ actor: 'node-0' }, () =>
|
|
499
522
|
AztecNodeService.createAndSync(
|
|
500
|
-
|
|
523
|
+
initialNodeConfig,
|
|
501
524
|
{ dateProvider, telemetry: telemetryClient, p2pClientDeps },
|
|
502
|
-
{
|
|
525
|
+
{ genesis, dontStartSequencer: opts.skipInitialSequencer },
|
|
503
526
|
),
|
|
504
527
|
);
|
|
505
528
|
const sequencerClient = aztecNodeService.getSequencer();
|
|
@@ -524,7 +547,7 @@ export async function setup(
|
|
|
524
547
|
dataDirectory: proverNodeDataDirectory,
|
|
525
548
|
},
|
|
526
549
|
{ dateProvider, p2pClientDeps, telemetry: telemetryClient },
|
|
527
|
-
{
|
|
550
|
+
{ genesis },
|
|
528
551
|
));
|
|
529
552
|
}
|
|
530
553
|
|
|
@@ -560,7 +583,9 @@ export async function setup(
|
|
|
560
583
|
|
|
561
584
|
let accounts: AztecAddress[] = [];
|
|
562
585
|
|
|
563
|
-
if (
|
|
586
|
+
if (opts.skipInitialSequencer) {
|
|
587
|
+
logger.info('Sequencer not started on initial node, skipping block progression');
|
|
588
|
+
} else if (shouldDeployAccounts) {
|
|
564
589
|
logger.info(
|
|
565
590
|
`${numberOfAccounts} accounts are being deployed. Reliably progressing past genesis by setting minTxsPerBlock to 1 and waiting for the accounts to be deployed`,
|
|
566
591
|
);
|
|
@@ -629,7 +654,7 @@ export async function setup(
|
|
|
629
654
|
initialFundedAccounts,
|
|
630
655
|
logger,
|
|
631
656
|
mockGossipSubNetwork,
|
|
632
|
-
|
|
657
|
+
genesis,
|
|
633
658
|
proverNode,
|
|
634
659
|
sequencerDelayer,
|
|
635
660
|
proverDelayer,
|
|
@@ -709,7 +734,7 @@ export async function waitForProvenChain(node: AztecNode, targetBlock?: BlockNum
|
|
|
709
734
|
targetBlock ??= await node.getBlockNumber();
|
|
710
735
|
|
|
711
736
|
await retryUntil(
|
|
712
|
-
async () => (await node.
|
|
737
|
+
async () => (await node.getBlockNumber('proven')) >= targetBlock,
|
|
713
738
|
'proven chain status',
|
|
714
739
|
timeoutSec,
|
|
715
740
|
intervalSec,
|
|
@@ -729,7 +754,7 @@ export function createAndSyncProverNode(
|
|
|
729
754
|
dateProvider: DateProvider;
|
|
730
755
|
p2pClientDeps?: P2PClientDeps;
|
|
731
756
|
},
|
|
732
|
-
options: {
|
|
757
|
+
options: { genesis?: GenesisData; dontStart?: boolean },
|
|
733
758
|
): Promise<{ proverNode: AztecNodeService }> {
|
|
734
759
|
return withLoggerBindings({ actor: 'prover-0' }, async () => {
|
|
735
760
|
const proverNode = await AztecNodeService.createAndSync(
|
|
@@ -742,7 +767,7 @@ export function createAndSyncProverNode(
|
|
|
742
767
|
proverPublisherPrivateKeys: [new SecretValue(proverNodePrivateKey)],
|
|
743
768
|
},
|
|
744
769
|
deps,
|
|
745
|
-
{
|
|
770
|
+
{ genesis: options.genesis, dontStartProverNode: options.dontStart },
|
|
746
771
|
);
|
|
747
772
|
|
|
748
773
|
if (!proverNode.getProverNode()) {
|
|
@@ -833,7 +858,7 @@ export async function ensureAccountContractsPublished(wallet: Wallet, accountsTo
|
|
|
833
858
|
* Returns deployed account data that can be used by tests.
|
|
834
859
|
*/
|
|
835
860
|
export const deployAccounts =
|
|
836
|
-
(numberOfAccounts: number, logger: Logger) =>
|
|
861
|
+
(numberOfAccounts: number, logger: Logger, deployOptions?: Partial<DeployOptions<DeployInteractionWaitOptions>>) =>
|
|
837
862
|
async ({ wallet, initialFundedAccounts }: { wallet: TestWallet; initialFundedAccounts: InitialAccountData[] }) => {
|
|
838
863
|
if (initialFundedAccounts.length < numberOfAccounts) {
|
|
839
864
|
throw new Error(`Cannot deploy more than ${initialFundedAccounts.length} initial accounts.`);
|
|
@@ -852,6 +877,7 @@ export const deployAccounts =
|
|
|
852
877
|
await deployMethod.send({
|
|
853
878
|
from: NO_FROM,
|
|
854
879
|
skipClassPublication: i !== 0, // Publish the contract class at most once.
|
|
880
|
+
...deployOptions,
|
|
855
881
|
});
|
|
856
882
|
}
|
|
857
883
|
|
|
@@ -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
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Wallet } from '@aztec/aztec.js/wallet';
|
|
2
|
+
import { WalletSchema } from '@aztec/aztec.js/wallet';
|
|
3
|
+
import { createSafeJsonRpcClient, makeFetch } from '@aztec/foundation/json-rpc/client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a JSON-RPC client that connects to a remote wallet service.
|
|
7
|
+
* The returned object implements the {@link Wallet} interface, proxying all calls over HTTP to the specified URL.
|
|
8
|
+
*/
|
|
9
|
+
export function createWalletClient(url: string): Wallet {
|
|
10
|
+
return createSafeJsonRpcClient<Wallet>(url, WalletSchema, {
|
|
11
|
+
namespaceMethods: 'wallet',
|
|
12
|
+
fetch: makeFetch([1, 2, 3], false),
|
|
13
|
+
});
|
|
14
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --no-warnings
|
|
2
|
+
/**
|
|
3
|
+
* Standalone entrypoint that spins up a local Aztec network (L1 + node) and exposes a {@link NodeEmbeddedWallet} over
|
|
4
|
+
* JSON-RPC.
|
|
5
|
+
*
|
|
6
|
+
* Intended for forward-compatibility testing: an **old** release image runs this script so that **new** tests can send
|
|
7
|
+
* new artifacts to old runtime code (loadContractArtifact, ACIR simulator, class-ID computation, entrypoint encoding,
|
|
8
|
+
* etc.).
|
|
9
|
+
*/
|
|
10
|
+
import { getSchnorrAccountContractAddress } from '@aztec/accounts/schnorr';
|
|
11
|
+
import { getInitialTestAccountsData } from '@aztec/accounts/testing';
|
|
12
|
+
import { createLocalNetwork } from '@aztec/aztec';
|
|
13
|
+
import { Fr } from '@aztec/aztec.js/fields';
|
|
14
|
+
import { WalletSchema } from '@aztec/aztec.js/wallet';
|
|
15
|
+
import { GrumpkinScalar } from '@aztec/foundation/curves/grumpkin';
|
|
16
|
+
import { createNamespacedSafeJsonRpcServer, startHttpRpcServer } from '@aztec/foundation/json-rpc/server';
|
|
17
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
18
|
+
import { AztecNodeApiSchema } from '@aztec/stdlib/interfaces/client';
|
|
19
|
+
import { EmbeddedWallet } from '@aztec/wallets/embedded';
|
|
20
|
+
|
|
21
|
+
const logger = createLogger('wallet-service');
|
|
22
|
+
|
|
23
|
+
const { ETHEREUM_HOSTS = 'http://localhost:8545', NODE_PORT = '8080', WALLET_PORT = '8081' } = process.env;
|
|
24
|
+
|
|
25
|
+
async function main() {
|
|
26
|
+
const l1RpcUrls = ETHEREUM_HOSTS.split(',').map(url => url.trim());
|
|
27
|
+
|
|
28
|
+
// Some tests (e.g. AMM) need 4 accounts but only 3 are funded via genesis. Generate deterministic keys for a 4th
|
|
29
|
+
// account so we can compute its address before network startup and include it in genesis funding. We cannot do this
|
|
30
|
+
// in the test because Wallet interface does not expose account creation functionality (only TestWallet exposes that
|
|
31
|
+
// but that's not used in forward compatibility testing).
|
|
32
|
+
const extraAccountSecret = Fr.fromHexString('0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef');
|
|
33
|
+
const extraAccountSalt = Fr.ZERO;
|
|
34
|
+
const extraAccountSigningKey = GrumpkinScalar.random();
|
|
35
|
+
const extraAccountAddress = await getSchnorrAccountContractAddress(
|
|
36
|
+
extraAccountSecret,
|
|
37
|
+
extraAccountSalt,
|
|
38
|
+
extraAccountSigningKey,
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
logger.info('Starting wallet service...', { l1RpcUrls });
|
|
42
|
+
|
|
43
|
+
// createLocalNetwork deploys L1 contracts, starts the node, and optionally deploys funded test accounts (when
|
|
44
|
+
// TEST_ACCOUNTS=true via env). We are not proving anything just like is done when local network is started by
|
|
45
|
+
// the `aztecStart` function. The extra account address is passed via prefundAddresses so it gets fee juice at genesis.
|
|
46
|
+
const { node, stop: stopNetwork } = await createLocalNetwork(
|
|
47
|
+
{ l1RpcUrls, realProofs: false, prefundAddresses: [extraAccountAddress.toString()] },
|
|
48
|
+
logger.info,
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
// Create an ephemeral embedded wallet backed by the local node.
|
|
52
|
+
const wallet = await EmbeddedWallet.create(node, { ephemeral: true });
|
|
53
|
+
|
|
54
|
+
// Re-register the initial test accounts so they are available via wallet.getAccounts(). createLocalNetwork deploys
|
|
55
|
+
// them onchain but uses a temporary wallet that is then stopped.
|
|
56
|
+
//
|
|
57
|
+
// We use the non-lazy import path (@aztec/accounts/testing, not /lazy) to avoid the dynamic JSON import that is
|
|
58
|
+
// incompatible with Node.js import attribute enforcement.
|
|
59
|
+
const testAccountsData = await getInitialTestAccountsData();
|
|
60
|
+
const accounts = await Promise.all(
|
|
61
|
+
testAccountsData.map(({ secret, salt, signingKey }) => wallet.createSchnorrAccount(secret, salt, signingKey)),
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// Register and deploy the 4th account.
|
|
65
|
+
const extraAccount = await wallet.createSchnorrAccount(extraAccountSecret, extraAccountSalt, extraAccountSigningKey);
|
|
66
|
+
const deployMethod = await extraAccount.getDeployMethod();
|
|
67
|
+
await deployMethod.send({ from: accounts[0].address });
|
|
68
|
+
|
|
69
|
+
logger.info('Embedded wallet created', {
|
|
70
|
+
accounts: [...accounts, extraAccount].map(a => a.address.toString()),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Contract artifacts are large, so allow generous body sizes for RPC requests.
|
|
74
|
+
const rpcOptions = { maxBodySizeBytes: '50mb' };
|
|
75
|
+
|
|
76
|
+
// Serve node RPC
|
|
77
|
+
const nodeRpcServer = createNamespacedSafeJsonRpcServer({ node: [node, AztecNodeApiSchema] }, rpcOptions);
|
|
78
|
+
const nodeHttpServer = await startHttpRpcServer(nodeRpcServer, { port: NODE_PORT });
|
|
79
|
+
logger.info(`Node JSON-RPC server listening on port ${nodeHttpServer.port}`);
|
|
80
|
+
|
|
81
|
+
// Serve wallet RPC
|
|
82
|
+
const walletRpcServer = createNamespacedSafeJsonRpcServer({ wallet: [wallet, WalletSchema] }, rpcOptions);
|
|
83
|
+
const walletHttpServer = await startHttpRpcServer(walletRpcServer, { port: WALLET_PORT });
|
|
84
|
+
logger.info(`Wallet JSON-RPC server listening on port ${walletHttpServer.port}`);
|
|
85
|
+
|
|
86
|
+
const shutdown = async () => {
|
|
87
|
+
logger.info('Shutting down...');
|
|
88
|
+
nodeHttpServer.close();
|
|
89
|
+
walletHttpServer.close();
|
|
90
|
+
await wallet.stop();
|
|
91
|
+
await stopNetwork();
|
|
92
|
+
process.exit(0);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
96
|
+
process.once('SIGINT', shutdown);
|
|
97
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
98
|
+
process.once('SIGTERM', shutdown);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
main().catch(err => {
|
|
102
|
+
logger.error('Wallet service failed to start', err);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
});
|
|
@@ -18,10 +18,8 @@ aztec-wallet() {
|
|
|
18
18
|
|
|
19
19
|
aztec-wallet import-test-accounts
|
|
20
20
|
|
|
21
|
-
# docs:start:declare-accounts
|
|
22
21
|
aztec-wallet create-account -a alice -f test0
|
|
23
22
|
aztec-wallet create-account -a bob -f test0
|
|
24
|
-
# docs:end:declare-accounts
|
|
25
23
|
|
|
26
24
|
aztec-wallet bridge-fee-juice 1000000000000000000000 accounts:alice --mint --no-wait
|
|
27
25
|
|
|
@@ -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
|
+
};
|
|
@@ -154,7 +154,6 @@ export const uniswapL1L2TestSuite = (
|
|
|
154
154
|
await cleanup();
|
|
155
155
|
});
|
|
156
156
|
|
|
157
|
-
// docs:start:uniswap_private
|
|
158
157
|
it('should uniswap trade on L1 from L2 funds privately (swaps WETH -> DAI)', async () => {
|
|
159
158
|
const wethL1BeforeBalance = await wethCrossChainHarness.getL1BalanceOf(ownerEthAddress);
|
|
160
159
|
|
|
@@ -345,10 +344,8 @@ export const uniswapL1L2TestSuite = (
|
|
|
345
344
|
logger.info('WETH balance after swap : ', wethL2BalanceAfterSwap.toString());
|
|
346
345
|
logger.info('DAI balance after swap : ', daiL2BalanceAfterSwap.toString());
|
|
347
346
|
});
|
|
348
|
-
// docs:end:uniswap_private
|
|
349
347
|
|
|
350
348
|
// TODO(#7463): reenable look into this failure https://github.com/AztecProtocol/aztec-packages/actions/runs/9912612912/job/27388320150?pr=7462
|
|
351
|
-
// // docs:start:uniswap_public
|
|
352
349
|
// it('should uniswap trade on L1 from L2 funds publicly (swaps WETH -> DAI)', async () => {
|
|
353
350
|
// const wethL1BeforeBalance = await wethCrossChainHarness.getL1BalanceOf(ownerEthAddress);
|
|
354
351
|
|
|
@@ -581,7 +578,6 @@ export const uniswapL1L2TestSuite = (
|
|
|
581
578
|
// logger.info('WETH balance after swap : ', wethL2BalanceAfterSwap.toString());
|
|
582
579
|
// logger.info('DAI balance after swap : ', daiL2BalanceAfterSwap.toString());
|
|
583
580
|
// });
|
|
584
|
-
// // docs:end:uniswap_public
|
|
585
581
|
|
|
586
582
|
// Edge cases for the private flow:
|
|
587
583
|
// note - tests for uniswapPortal.sol and minting asset on L2 are covered in other tests.
|