@aztec-labs/cli 6.0.0-rc.1 → 6.0.0-rc.3
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/cmds/l1/index.d.ts +1 -1
- package/dest/cmds/l1/index.d.ts.map +1 -1
- package/dest/cmds/l1/index.js +57 -4
- package/dest/cmds/l1/l1_rpc_test_utils.d.ts +14 -0
- package/dest/cmds/l1/l1_rpc_test_utils.d.ts.map +1 -0
- package/dest/cmds/l1/l1_rpc_test_utils.js +58 -0
- package/dest/cmds/l1/update_l1_validators.d.ts +47 -4
- package/dest/cmds/l1/update_l1_validators.d.ts.map +1 -1
- package/dest/cmds/l1/update_l1_validators.js +216 -22
- package/dest/config/generated/networks.d.ts +9 -5
- package/dest/config/generated/networks.d.ts.map +1 -1
- package/dest/config/generated/networks.js +8 -4
- package/dest/config/index.d.ts +2 -1
- package/dest/config/index.d.ts.map +1 -1
- package/dest/config/index.js +1 -0
- package/package.json +23 -23
- package/src/cmds/l1/index.ts +136 -10
- package/src/cmds/l1/l1_rpc_test_utils.ts +43 -0
- package/src/cmds/l1/update_l1_validators.ts +294 -27
- package/src/config/generated/networks.ts +8 -4
- package/src/config/index.ts +1 -0
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
import { RollupAbi, StakingAssetHandlerAbi, TestERC20Abi } from '@aztec-foundation/l1-artifacts';
|
|
2
2
|
|
|
3
3
|
import { createEthereumChain, isAnvilTestChain } from '@aztec-labs/ethereum/chain';
|
|
4
|
-
import { createExtendedL1Client, getPublicClient } from '@aztec-labs/ethereum/client';
|
|
4
|
+
import { createExtendedL1Client, getPublicClient, makeL1HttpTransport } from '@aztec-labs/ethereum/client';
|
|
5
5
|
import { getL1ContractsConfigEnvVars } from '@aztec-labs/ethereum/config';
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
type AttesterExitAuthorization,
|
|
8
|
+
GSEContract,
|
|
9
|
+
RegistryContract,
|
|
10
|
+
RollupContract,
|
|
11
|
+
} from '@aztec-labs/ethereum/contracts';
|
|
7
12
|
import { createL1TxUtils } from '@aztec-labs/ethereum/l1-tx-utils';
|
|
8
13
|
import { EthCheatCodes } from '@aztec-labs/ethereum/test';
|
|
14
|
+
import { getActiveNetworkName } from '@aztec-labs/foundation/config';
|
|
9
15
|
import { EthAddress } from '@aztec-labs/foundation/eth-address';
|
|
10
16
|
import { Signature } from '@aztec-labs/foundation/eth-signature';
|
|
11
17
|
import type { LogFn, Logger } from '@aztec-labs/foundation/log';
|
|
12
18
|
import { DateProvider } from '@aztec-labs/foundation/timer';
|
|
13
19
|
import { ZkPassportProofParams } from '@aztec-labs/stdlib/zkpassport';
|
|
14
|
-
import { readFile } from 'node:fs/promises';
|
|
15
|
-
import {
|
|
20
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
21
|
+
import { join } from 'node:path';
|
|
22
|
+
import { createPublicClient, encodeFunctionData, formatEther, getContract, isHex, maxUint256 } from 'viem';
|
|
16
23
|
import { generatePrivateKey, mnemonicToAccount, privateKeyToAccount } from 'viem/accounts';
|
|
17
24
|
|
|
25
|
+
import { getNetworkConfig } from '../../config/network_config.js';
|
|
26
|
+
import { atomicUpdateFile } from '../../utils/commands.js';
|
|
27
|
+
import { deriveEthAttester } from '../validator_keys/shared.js';
|
|
28
|
+
|
|
18
29
|
export interface RollupCommandArgs {
|
|
19
30
|
rpcUrls: string[];
|
|
20
31
|
chainId: number;
|
|
@@ -24,6 +35,14 @@ export interface RollupCommandArgs {
|
|
|
24
35
|
withdrawerAddress?: EthAddress;
|
|
25
36
|
}
|
|
26
37
|
|
|
38
|
+
/** Credentials and derivation indices for a local Ethereum signer. */
|
|
39
|
+
export type SignerAccountArgs = {
|
|
40
|
+
privateKey?: string;
|
|
41
|
+
mnemonic?: string;
|
|
42
|
+
accountIndex?: number;
|
|
43
|
+
addressIndex?: number;
|
|
44
|
+
};
|
|
45
|
+
|
|
27
46
|
export interface StakingAssetHandlerCommandArgs {
|
|
28
47
|
rpcUrls: string[];
|
|
29
48
|
chainId: number;
|
|
@@ -256,16 +275,172 @@ export async function removeL1Validator({
|
|
|
256
275
|
dualLog(`Transaction hash: ${receipt.transactionHash}`);
|
|
257
276
|
}
|
|
258
277
|
|
|
278
|
+
/** Chain ID and registry published for a network; both are undefined when it publishes none, as for `local`. */
|
|
279
|
+
export type AttesterExitNetwork = {
|
|
280
|
+
name: string;
|
|
281
|
+
l1ChainId?: number;
|
|
282
|
+
registryAddress?: EthAddress;
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
/** Loads the published config of the network selected with --network, which takes precedence over the environment. */
|
|
286
|
+
export async function getAttesterExitNetwork(name: string): Promise<AttesterExitNetwork> {
|
|
287
|
+
const networkName = getActiveNetworkName(name);
|
|
288
|
+
const cacheDir = process.env.DATA_DIRECTORY ? join(process.env.DATA_DIRECTORY, 'cache') : undefined;
|
|
289
|
+
const config = networkName === 'local' ? undefined : await getNetworkConfig(networkName, cacheDir);
|
|
290
|
+
if (networkName !== 'local' && !config) {
|
|
291
|
+
throw new Error(`Network ${networkName} has no published config`);
|
|
292
|
+
}
|
|
293
|
+
return {
|
|
294
|
+
name: networkName,
|
|
295
|
+
l1ChainId: config?.l1ChainId,
|
|
296
|
+
registryAddress: config ? EthAddress.fromString(config.registryAddress) : undefined,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/** Inputs that select the chain and rollup an attester exit is signed for; each is undefined when not supplied. */
|
|
301
|
+
export type AttesterExitTargetArgs = {
|
|
302
|
+
chainId?: number;
|
|
303
|
+
/** Whether `chainId` came from the L1_CHAIN_ID environment variable rather than a flag. */
|
|
304
|
+
chainIdFromEnv?: boolean;
|
|
305
|
+
rpcUrls?: string[];
|
|
306
|
+
network?: AttesterExitNetwork;
|
|
307
|
+
rollupAddress?: EthAddress;
|
|
308
|
+
log: LogFn;
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Resolves the chain ID and rollup an attester exit is signed for, without falling back to the Anvil chain ID.
|
|
313
|
+
* Whenever an RPC is given, its chain ID must match. Without one, signing is offline and needs the chain ID from a flag
|
|
314
|
+
* or --network; an L1_CHAIN_ID left in the environment alone is rejected because nothing confirms it.
|
|
315
|
+
*/
|
|
316
|
+
export async function resolveAttesterExitTarget({
|
|
317
|
+
chainId,
|
|
318
|
+
chainIdFromEnv = false,
|
|
319
|
+
rpcUrls,
|
|
320
|
+
network,
|
|
321
|
+
rollupAddress,
|
|
322
|
+
log,
|
|
323
|
+
}: AttesterExitTargetArgs): Promise<{ chainId: number; rollupAddress: EthAddress }> {
|
|
324
|
+
if (!rollupAddress && !network) {
|
|
325
|
+
throw new Error('Provide --rollup, or --network to use the canonical rollup from the network registry');
|
|
326
|
+
}
|
|
327
|
+
if (!rollupAddress && !network?.registryAddress) {
|
|
328
|
+
throw new Error(`Network ${network?.name} publishes no registry address; provide --rollup`);
|
|
329
|
+
}
|
|
330
|
+
if (chainId !== undefined) {
|
|
331
|
+
assertValidChainId(chainId);
|
|
332
|
+
if (network?.l1ChainId !== undefined && chainId !== network.l1ChainId) {
|
|
333
|
+
throw new Error(`Chain ID ${chainId} does not match ${network.name}, which uses chain ID ${network.l1ChainId}`);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
const expectedChainId = chainId ?? network?.l1ChainId;
|
|
337
|
+
if (!rpcUrls) {
|
|
338
|
+
if (expectedChainId === undefined) {
|
|
339
|
+
throw new Error('Provide --l1-chain-id, --network, or --l1-rpc-urls to select the chain to sign for');
|
|
340
|
+
}
|
|
341
|
+
if (!rollupAddress) {
|
|
342
|
+
throw new Error('Looking up the rollup in the network registry requires --l1-rpc-urls');
|
|
343
|
+
}
|
|
344
|
+
if (chainIdFromEnv && network?.l1ChainId === undefined) {
|
|
345
|
+
throw new Error(
|
|
346
|
+
`Chain ID ${expectedChainId} comes only from L1_CHAIN_ID; confirm it with --l1-chain-id, --network, or --l1-rpc-urls`,
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
return { chainId: expectedChainId, rollupAddress };
|
|
350
|
+
}
|
|
351
|
+
const rpcChainId = await getL1RpcChainId(rpcUrls, expectedChainId);
|
|
352
|
+
if (rollupAddress) {
|
|
353
|
+
return { chainId: rpcChainId, rollupAddress };
|
|
354
|
+
}
|
|
355
|
+
const registryAddress = network!.registryAddress!;
|
|
356
|
+
const client = getPublicClient({ l1RpcUrls: rpcUrls, l1ChainId: rpcChainId });
|
|
357
|
+
const canonicalRollup = await new RegistryContract(client, registryAddress).getCanonicalAddress();
|
|
358
|
+
log(`Using canonical rollup ${canonicalRollup} from the ${network!.name} registry ${registryAddress}`);
|
|
359
|
+
return { chainId: rpcChainId, rollupAddress: canonicalRollup };
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/** Returns the chain ID the L1 RPC reports, failing if it differs from `expectedChainId`. */
|
|
363
|
+
async function getL1RpcChainId(rpcUrls: string[], expectedChainId?: number): Promise<number> {
|
|
364
|
+
const rpcChainId = await createPublicClient({ transport: makeL1HttpTransport(rpcUrls) }).getChainId();
|
|
365
|
+
if (expectedChainId !== undefined && rpcChainId !== expectedChainId) {
|
|
366
|
+
throw new Error(`The L1 RPC reports chain ID ${rpcChainId}, but chain ID ${expectedChainId} was requested`);
|
|
367
|
+
}
|
|
368
|
+
return rpcChainId;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/** Signs an exit authorization locally and writes a JSON array accepted by the batch command. */
|
|
372
|
+
export async function signAttesterExit({
|
|
373
|
+
rpcUrls,
|
|
374
|
+
chainId,
|
|
375
|
+
privateKey,
|
|
376
|
+
mnemonic,
|
|
377
|
+
accountIndex,
|
|
378
|
+
addressIndex,
|
|
379
|
+
rollupAddress,
|
|
380
|
+
attesterAddress,
|
|
381
|
+
deadline,
|
|
382
|
+
output,
|
|
383
|
+
append = false,
|
|
384
|
+
log,
|
|
385
|
+
}: Omit<RollupCommandArgs, 'withdrawerAddress' | 'mnemonic' | 'privateKey'> &
|
|
386
|
+
SignerAccountArgs & {
|
|
387
|
+
attesterAddress: EthAddress;
|
|
388
|
+
deadline: bigint;
|
|
389
|
+
output: string;
|
|
390
|
+
append?: boolean;
|
|
391
|
+
log: LogFn;
|
|
392
|
+
}) {
|
|
393
|
+
assertValidChainId(chainId);
|
|
394
|
+
const account = getSignerAccount({ privateKey, mnemonic, accountIndex, addressIndex });
|
|
395
|
+
if (account.address.toLowerCase() !== attesterAddress.toString().toLowerCase()) {
|
|
396
|
+
throw new Error('The signing account must match the attester address');
|
|
397
|
+
}
|
|
398
|
+
const chain = createEthereumChain(rpcUrls, chainId);
|
|
399
|
+
const client = createExtendedL1Client(rpcUrls, account, chain.chainInfo);
|
|
400
|
+
const rollup = new RollupContract(client, rollupAddress);
|
|
401
|
+
const authorization = await rollup.createAttesterExitAuthorization(attesterAddress, deadline, typedData =>
|
|
402
|
+
account.signTypedData(typedData),
|
|
403
|
+
);
|
|
404
|
+
const existingAuthorizations = append
|
|
405
|
+
? await readAttesterExitAuthorizationJson(output).catch((error: unknown) => {
|
|
406
|
+
if (!isRecord(error) || error.code !== 'ENOENT') {
|
|
407
|
+
throw error;
|
|
408
|
+
}
|
|
409
|
+
return undefined;
|
|
410
|
+
})
|
|
411
|
+
: undefined;
|
|
412
|
+
const authorizations = existingAuthorizations ?? [];
|
|
413
|
+
authorizations.push({
|
|
414
|
+
attester: authorization.attester.toString(),
|
|
415
|
+
deadline: authorization.deadline.toString(),
|
|
416
|
+
signature: Signature.fromViemSignature(authorization.signature).toString(),
|
|
417
|
+
});
|
|
418
|
+
const json = JSON.stringify(authorizations, null, 2);
|
|
419
|
+
if (existingAuthorizations) {
|
|
420
|
+
await atomicUpdateFile(output, `${json}\n`);
|
|
421
|
+
} else {
|
|
422
|
+
await writeFile(output, `${json}\n`, { flag: 'wx' });
|
|
423
|
+
}
|
|
424
|
+
log(`Wrote attester exit authorization to ${output}`);
|
|
425
|
+
}
|
|
426
|
+
|
|
259
427
|
/** Reads relayed attester exit authorizations from a JSON array. */
|
|
260
428
|
export async function readAttesterExitAuthorizations(path: string): Promise<AttesterExitAuthorization[]> {
|
|
261
|
-
const parsed
|
|
262
|
-
if (
|
|
429
|
+
const parsed = await readAttesterExitAuthorizationJson(path);
|
|
430
|
+
if (parsed.length === 0) {
|
|
263
431
|
throw new Error('Attester exit authorization file must contain a non-empty JSON array');
|
|
264
432
|
}
|
|
265
|
-
|
|
266
433
|
return parsed.map((value, index) => parseAttesterExitAuthorization(value, index));
|
|
267
434
|
}
|
|
268
435
|
|
|
436
|
+
async function readAttesterExitAuthorizationJson(path: string): Promise<unknown[]> {
|
|
437
|
+
const parsed: unknown = JSON.parse(await readFile(path, 'utf-8'));
|
|
438
|
+
if (!Array.isArray(parsed)) {
|
|
439
|
+
throw new Error('Attester exit authorization file must contain a JSON array');
|
|
440
|
+
}
|
|
441
|
+
return parsed;
|
|
442
|
+
}
|
|
443
|
+
|
|
269
444
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
270
445
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
271
446
|
}
|
|
@@ -282,7 +457,11 @@ function parseAttesterExitAuthorization(value: unknown, index: number): Attester
|
|
|
282
457
|
if (typeof authorization.deadline !== 'string' || !/^\d+$/.test(authorization.deadline)) {
|
|
283
458
|
throw new Error(`Attester exit authorization ${index} deadline must be a decimal string`);
|
|
284
459
|
}
|
|
285
|
-
if (
|
|
460
|
+
if (
|
|
461
|
+
typeof authorization.signature !== 'string' ||
|
|
462
|
+
!isHex(authorization.signature) ||
|
|
463
|
+
!Signature.isValidString(authorization.signature)
|
|
464
|
+
) {
|
|
286
465
|
throw new Error(`Attester exit authorization ${index} has an invalid signature`);
|
|
287
466
|
}
|
|
288
467
|
|
|
@@ -293,41 +472,80 @@ function parseAttesterExitAuthorization(value: unknown, index: number): Attester
|
|
|
293
472
|
};
|
|
294
473
|
}
|
|
295
474
|
|
|
475
|
+
/**
|
|
476
|
+
* Confirms the RPC is on the requested chain, then checks each imported signature so a bad entry is named rather than
|
|
477
|
+
* reverting the whole batch. Duplicates and deadlines are left to the chain, which with --up-to-limit never looks past
|
|
478
|
+
* the processed prefix.
|
|
479
|
+
*/
|
|
480
|
+
async function checkAttesterExitBatch(
|
|
481
|
+
rollup: RollupContract,
|
|
482
|
+
authorizations: AttesterExitAuthorization[],
|
|
483
|
+
rpcUrls: string[],
|
|
484
|
+
chainId: number,
|
|
485
|
+
) {
|
|
486
|
+
await getL1RpcChainId(rpcUrls, chainId);
|
|
487
|
+
for (const [index, authorization] of authorizations.entries()) {
|
|
488
|
+
await rollup.validateAttesterExitSignature(authorization, index);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
296
492
|
/** Relays a batch of attester-signed exits. */
|
|
297
493
|
export async function initiateWithdrawByAttesterBatch({
|
|
298
494
|
rpcUrls,
|
|
299
495
|
chainId,
|
|
300
496
|
privateKey,
|
|
301
497
|
mnemonic,
|
|
498
|
+
accountIndex,
|
|
499
|
+
addressIndex,
|
|
302
500
|
authorizations,
|
|
303
501
|
upToLimit,
|
|
502
|
+
dryRun = false,
|
|
304
503
|
rollupAddress,
|
|
305
504
|
log,
|
|
306
505
|
debugLogger,
|
|
307
|
-
}: Omit<RollupCommandArgs, 'withdrawerAddress'> &
|
|
506
|
+
}: Omit<RollupCommandArgs, 'withdrawerAddress' | 'mnemonic' | 'privateKey'> &
|
|
507
|
+
SignerAccountArgs &
|
|
308
508
|
LoggerArgs & {
|
|
309
509
|
authorizations: AttesterExitAuthorization[];
|
|
310
510
|
upToLimit: boolean;
|
|
511
|
+
dryRun?: boolean;
|
|
311
512
|
}) {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
513
|
+
if (dryRun) {
|
|
514
|
+
assertValidChainId(chainId);
|
|
515
|
+
// A dry run needs no key, but check any signer options given so the same command can later run without --dry-run.
|
|
516
|
+
if (privateKey || mnemonic || accountIndex !== undefined || addressIndex !== undefined) {
|
|
517
|
+
getSignerAccount({ privateKey, mnemonic, accountIndex, addressIndex });
|
|
518
|
+
}
|
|
519
|
+
const client = getPublicClient({ l1RpcUrls: rpcUrls, l1ChainId: chainId });
|
|
520
|
+
const rollup = new RollupContract(client, rollupAddress);
|
|
521
|
+
await checkAttesterExitBatch(rollup, authorizations, rpcUrls, chainId);
|
|
522
|
+
const processedCount = await rollup.simulateAttesterExitBatch(authorizations, upToLimit);
|
|
523
|
+
log(
|
|
524
|
+
`Dry run: would process ${processedCount} of ${authorizations.length} attester exit authorizations at current chain state.`,
|
|
525
|
+
);
|
|
526
|
+
logRemainingAttesterExits(log, processedCount, authorizations.length);
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
const account = getSignerAccount({ privateKey, mnemonic, accountIndex, addressIndex });
|
|
530
|
+
const client = createExtendedL1Client(rpcUrls, account, createEthereumChain(rpcUrls, chainId).chainInfo);
|
|
315
531
|
const rollup = new RollupContract(client, rollupAddress);
|
|
532
|
+
await checkAttesterExitBatch(rollup, authorizations, rpcUrls, chainId);
|
|
316
533
|
const l1TxUtils = createL1TxUtils(client, { logger: debugLogger });
|
|
317
|
-
const { receipt } =
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
log
|
|
326
|
-
|
|
327
|
-
log('The rollup processed the largest permitted prefix of the authorization list.');
|
|
328
|
-
}
|
|
329
|
-
debugLogger.info('Attester exit batch submitted', {
|
|
534
|
+
const { receipt, processedCount, remainingCount } = await rollup.submitAttesterExitBatch(
|
|
535
|
+
l1TxUtils,
|
|
536
|
+
authorizations,
|
|
537
|
+
upToLimit,
|
|
538
|
+
);
|
|
539
|
+
log(
|
|
540
|
+
`Processed ${processedCount} of ${authorizations.length} attester exit authorizations. Transaction hash: ${receipt.transactionHash}`,
|
|
541
|
+
);
|
|
542
|
+
logRemainingAttesterExits(log, processedCount, authorizations.length);
|
|
543
|
+
debugLogger.info('Attester exit batch processed', {
|
|
330
544
|
authorizationCount: authorizations.length,
|
|
545
|
+
processedCount,
|
|
546
|
+
remainingCount,
|
|
547
|
+
remainingStartIndex: remainingCount > 0 ? processedCount : undefined,
|
|
548
|
+
remainingEndIndexExclusive: remainingCount > 0 ? authorizations.length : undefined,
|
|
331
549
|
upToLimit,
|
|
332
550
|
rollup: rollupAddress.toString(),
|
|
333
551
|
transactionHash: receipt.transactionHash,
|
|
@@ -341,12 +559,18 @@ export async function initiateWithdrawByAttester({
|
|
|
341
559
|
chainId,
|
|
342
560
|
privateKey,
|
|
343
561
|
mnemonic,
|
|
562
|
+
accountIndex,
|
|
563
|
+
addressIndex,
|
|
344
564
|
attesterAddress,
|
|
345
565
|
rollupAddress,
|
|
346
566
|
log,
|
|
347
567
|
debugLogger,
|
|
348
|
-
}: Omit<RollupCommandArgs, 'withdrawerAddress'
|
|
349
|
-
|
|
568
|
+
}: Omit<RollupCommandArgs, 'withdrawerAddress' | 'mnemonic' | 'privateKey'> &
|
|
569
|
+
SignerAccountArgs &
|
|
570
|
+
LoggerArgs & {
|
|
571
|
+
attesterAddress: EthAddress;
|
|
572
|
+
}) {
|
|
573
|
+
const account = getSignerAccount({ privateKey, mnemonic, accountIndex, addressIndex });
|
|
350
574
|
if (account.address.toLowerCase() !== attesterAddress.toString().toLowerCase()) {
|
|
351
575
|
throw new Error('The transaction signer must match the attester address');
|
|
352
576
|
}
|
|
@@ -454,6 +678,15 @@ export async function debugRollup({ rpcUrls, chainId, rollupAddress, log }: Roll
|
|
|
454
678
|
log(`Proposer NOW: ${proposer.toString()}`);
|
|
455
679
|
}
|
|
456
680
|
|
|
681
|
+
function logRemainingAttesterExits(log: LogFn, processedCount: number, authorizationCount: number) {
|
|
682
|
+
const remainingCount = authorizationCount - processedCount;
|
|
683
|
+
log(
|
|
684
|
+
remainingCount > 0
|
|
685
|
+
? `Remaining authorizations: ${remainingCount}. Zero-based JSON array indices ${processedCount} through ${authorizationCount - 1} (inclusive).`
|
|
686
|
+
: 'Remaining authorizations: 0 (none).',
|
|
687
|
+
);
|
|
688
|
+
}
|
|
689
|
+
|
|
457
690
|
function makeDualLog(log: LogFn, debugLogger: Logger) {
|
|
458
691
|
return (msg: string) => {
|
|
459
692
|
log(msg);
|
|
@@ -461,6 +694,40 @@ function makeDualLog(log: LogFn, debugLogger: Logger) {
|
|
|
461
694
|
};
|
|
462
695
|
}
|
|
463
696
|
|
|
697
|
+
/** `createEthereumChain` maps a falsy chain ID to Anvil, so reject it before a chain is built from it. */
|
|
698
|
+
function assertValidChainId(chainId: number) {
|
|
699
|
+
if (!Number.isSafeInteger(chainId) || chainId <= 0) {
|
|
700
|
+
throw new Error('Chain ID must be a positive safe integer');
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
function getSignerAccount({ privateKey, mnemonic, accountIndex, addressIndex }: SignerAccountArgs) {
|
|
705
|
+
if (Boolean(privateKey) === Boolean(mnemonic)) {
|
|
706
|
+
throw new Error('Provide either a private key or a mnemonic for the signer');
|
|
707
|
+
}
|
|
708
|
+
if (privateKey) {
|
|
709
|
+
if (accountIndex !== undefined || addressIndex !== undefined) {
|
|
710
|
+
throw new Error('Account and address indices require a mnemonic');
|
|
711
|
+
}
|
|
712
|
+
return getAccount(privateKey, undefined);
|
|
713
|
+
}
|
|
714
|
+
const selectedAccountIndex = accountIndex ?? 0;
|
|
715
|
+
const selectedAddressIndex = addressIndex ?? 0;
|
|
716
|
+
if (
|
|
717
|
+
!Number.isSafeInteger(selectedAccountIndex) ||
|
|
718
|
+
selectedAccountIndex < 0 ||
|
|
719
|
+
!Number.isSafeInteger(selectedAddressIndex) ||
|
|
720
|
+
selectedAddressIndex < 0
|
|
721
|
+
) {
|
|
722
|
+
throw new Error('Account and address indices must be non-negative safe integers');
|
|
723
|
+
}
|
|
724
|
+
const derivedKey = deriveEthAttester(mnemonic!, selectedAccountIndex, selectedAddressIndex);
|
|
725
|
+
if (typeof derivedKey !== 'string') {
|
|
726
|
+
throw new Error('Expected a local signer private key');
|
|
727
|
+
}
|
|
728
|
+
return privateKeyToAccount(derivedKey);
|
|
729
|
+
}
|
|
730
|
+
|
|
464
731
|
function getAccount(privateKey: string | undefined, mnemonic: string | undefined) {
|
|
465
732
|
if (!privateKey && !mnemonic) {
|
|
466
733
|
throw new Error('Either privateKey or mnemonic must be provided to create a wallet client');
|
|
@@ -58,6 +58,8 @@ export const devnetConfig = {
|
|
|
58
58
|
SPONSORED_FPC: true,
|
|
59
59
|
TRANSACTIONS_DISABLED: false,
|
|
60
60
|
SEQ_MAX_TX_PER_BLOCK: 18,
|
|
61
|
+
SEQ_MAX_TX_PER_CHECKPOINT: 36,
|
|
62
|
+
VALIDATOR_MAX_TX_PER_CHECKPOINT: 72,
|
|
61
63
|
PROVER_REAL_PROOFS: false,
|
|
62
64
|
PXE_PROVER_ENABLED: false,
|
|
63
65
|
SYNC_SNAPSHOTS_URLS: '',
|
|
@@ -89,7 +91,7 @@ export const testnetConfig = {
|
|
|
89
91
|
AZTEC_EPOCH_DURATION: 32,
|
|
90
92
|
AZTEC_TARGET_COMMITTEE_SIZE: 48,
|
|
91
93
|
AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET: 2,
|
|
92
|
-
AZTEC_LAG_IN_EPOCHS_FOR_RANDAO:
|
|
94
|
+
AZTEC_LAG_IN_EPOCHS_FOR_RANDAO: 1,
|
|
93
95
|
AZTEC_EXIT_DELAY_SECONDS: 172800,
|
|
94
96
|
AZTEC_PROOF_SUBMISSION_EPOCHS: 1,
|
|
95
97
|
AZTEC_INITIAL_ETH_PER_FEE_ASSET: 10000000,
|
|
@@ -114,6 +116,8 @@ export const testnetConfig = {
|
|
|
114
116
|
SEQ_BLOCK_DURATION_MS: 6000,
|
|
115
117
|
MAX_BLOCKS_PER_CHECKPOINT: 10,
|
|
116
118
|
CHECKPOINT_PROPOSAL_SYNC_GRACE_SECONDS: 12,
|
|
119
|
+
SEQ_MAX_TX_PER_CHECKPOINT: 72,
|
|
120
|
+
VALIDATOR_MAX_TX_PER_CHECKPOINT: 144,
|
|
117
121
|
DATA_STORE_MAP_SIZE_KB: 134217728,
|
|
118
122
|
ARCHIVER_STORE_MAP_SIZE_KB: 1073741824,
|
|
119
123
|
NOTE_HASH_TREE_MAP_SIZE_KB: 1073741824,
|
|
@@ -140,7 +144,6 @@ export const testnetConfig = {
|
|
|
140
144
|
TEST_ACCOUNTS: false,
|
|
141
145
|
SPONSORED_FPC: false,
|
|
142
146
|
TRANSACTIONS_DISABLED: false,
|
|
143
|
-
SEQ_MAX_TX_PER_CHECKPOINT: 72,
|
|
144
147
|
PROVER_REAL_PROOFS: true,
|
|
145
148
|
P2P_MAX_PENDING_TX_COUNT: 1000,
|
|
146
149
|
P2P_TX_POOL_DELETE_TXS_AFTER_REORG: true,
|
|
@@ -165,7 +168,7 @@ export const mainnetConfig = {
|
|
|
165
168
|
AZTEC_EPOCH_DURATION: 32,
|
|
166
169
|
AZTEC_TARGET_COMMITTEE_SIZE: 48,
|
|
167
170
|
AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET: 2,
|
|
168
|
-
AZTEC_LAG_IN_EPOCHS_FOR_RANDAO:
|
|
171
|
+
AZTEC_LAG_IN_EPOCHS_FOR_RANDAO: 1,
|
|
169
172
|
AZTEC_PROOF_SUBMISSION_EPOCHS: 1,
|
|
170
173
|
AZTEC_INITIAL_ETH_PER_FEE_ASSET: 10000000,
|
|
171
174
|
AZTEC_SLASHER_ENABLED: true,
|
|
@@ -182,6 +185,8 @@ export const mainnetConfig = {
|
|
|
182
185
|
SEQ_BLOCK_DURATION_MS: 6000,
|
|
183
186
|
MAX_BLOCKS_PER_CHECKPOINT: 10,
|
|
184
187
|
CHECKPOINT_PROPOSAL_SYNC_GRACE_SECONDS: 12,
|
|
188
|
+
SEQ_MAX_TX_PER_CHECKPOINT: 72,
|
|
189
|
+
VALIDATOR_MAX_TX_PER_CHECKPOINT: 144,
|
|
185
190
|
DATA_STORE_MAP_SIZE_KB: 134217728,
|
|
186
191
|
ARCHIVER_STORE_MAP_SIZE_KB: 1073741824,
|
|
187
192
|
NOTE_HASH_TREE_MAP_SIZE_KB: 1073741824,
|
|
@@ -216,7 +221,6 @@ export const mainnetConfig = {
|
|
|
216
221
|
TEST_ACCOUNTS: false,
|
|
217
222
|
SPONSORED_FPC: false,
|
|
218
223
|
TRANSACTIONS_DISABLED: false,
|
|
219
|
-
SEQ_MAX_TX_PER_CHECKPOINT: 72,
|
|
220
224
|
PROVER_REAL_PROOFS: true,
|
|
221
225
|
BLOB_ALLOW_EMPTY_SOURCES: true,
|
|
222
226
|
P2P_MAX_PENDING_TX_COUNT: 1000,
|