@aztec/cli 3.0.0-nightly.20251119 → 3.0.0-nightly.20251121
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/validator_keys/add.d.ts.map +1 -1
- package/dest/cmds/validator_keys/add.js +9 -5
- package/dest/cmds/validator_keys/generate_bls_keypair.d.ts.map +1 -1
- package/dest/cmds/validator_keys/generate_bls_keypair.js +2 -1
- package/dest/cmds/validator_keys/index.d.ts.map +1 -1
- package/dest/cmds/validator_keys/index.js +7 -3
- package/dest/cmds/validator_keys/new.d.ts +1 -1
- package/dest/cmds/validator_keys/new.d.ts.map +1 -1
- package/dest/cmds/validator_keys/new.js +11 -19
- package/dest/cmds/validator_keys/shared.d.ts +1 -10
- package/dest/cmds/validator_keys/shared.d.ts.map +1 -1
- package/dest/cmds/validator_keys/shared.js +7 -16
- package/dest/cmds/validator_keys/utils.d.ts +25 -0
- package/dest/cmds/validator_keys/utils.d.ts.map +1 -0
- package/dest/cmds/validator_keys/utils.js +52 -0
- package/dest/config/network_config.d.ts +1 -1
- package/dest/config/network_config.d.ts.map +1 -1
- package/dest/config/network_config.js +19 -5
- package/package.json +28 -28
- package/src/cmds/validator_keys/add.ts +7 -5
- package/src/cmds/validator_keys/generate_bls_keypair.ts +2 -1
- package/src/cmds/validator_keys/index.ts +23 -7
- package/src/cmds/validator_keys/new.ts +15 -23
- package/src/cmds/validator_keys/shared.ts +9 -32
- package/src/cmds/validator_keys/utils.ts +80 -0
- package/src/config/network_config.ts +26 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../src/cmds/validator_keys/add.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAQnD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAC;AAW5D,MAAM,MAAM,uBAAuB,GAAG,2BAA2B,CAAC;AAElE,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB,EAAE,GAAG,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../src/cmds/validator_keys/add.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAQnD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAC;AAW5D,MAAM,MAAM,uBAAuB,GAAG,2BAA2B,CAAC;AAElE,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB,EAAE,GAAG,EAAE,KAAK,iBAoGpG"}
|
|
@@ -2,11 +2,16 @@ import { loadKeystoreFile } from '@aztec/node-keystore/loader';
|
|
|
2
2
|
import { wordlist } from '@scure/bip39/wordlists/english.js';
|
|
3
3
|
import { dirname, isAbsolute, join } from 'path';
|
|
4
4
|
import { generateMnemonic } from 'viem/accounts';
|
|
5
|
-
import { buildValidatorEntries, logValidatorSummaries, maybePrintJson,
|
|
5
|
+
import { buildValidatorEntries, logValidatorSummaries, maybePrintJson, writeBlsBn254ToFile, writeEthJsonV3ToFile, writeKeystoreFile } from './shared.js';
|
|
6
|
+
import { validateBlsPathOptions, validatePublisherOptions, validateRemoteSignerOptions } from './utils.js';
|
|
6
7
|
export async function addValidatorKeys(existing, options, log) {
|
|
7
8
|
// validate bls-path inputs before proceeding with key generation
|
|
8
9
|
validateBlsPathOptions(options);
|
|
9
|
-
|
|
10
|
+
// validate publisher options
|
|
11
|
+
validatePublisherOptions(options);
|
|
12
|
+
// validate remote signer options
|
|
13
|
+
validateRemoteSignerOptions(options);
|
|
14
|
+
const { dataDir, file, count, publisherCount = 0, publishers, mnemonic, accountIndex = 0, addressIndex, ikm, blsPath, json, feeRecipient: feeRecipientOpt, coinbase: coinbaseOpt, remoteSigner: remoteSignerOpt, password, encryptedKeystoreDir } = options;
|
|
10
15
|
const validatorCount = typeof count === 'number' && Number.isFinite(count) && count > 0 ? Math.floor(count) : 1;
|
|
11
16
|
const baseAddressIndex = addressIndex ?? 0;
|
|
12
17
|
const keystore = loadKeystoreFile(existing);
|
|
@@ -19,7 +24,6 @@ export async function addValidatorKeys(existing, options, log) {
|
|
|
19
24
|
throw new Error('feeRecipient is required (either present in existing file or via --fee-recipient)');
|
|
20
25
|
}
|
|
21
26
|
const coinbase = coinbaseOpt ?? first.coinbase;
|
|
22
|
-
const fundingAccount = fundingAccountOpt ?? first.fundingAccount;
|
|
23
27
|
const derivedRemoteSigner = first.attester?.remoteSignerUrl || first.attester?.eth?.remoteSignerUrl;
|
|
24
28
|
const remoteSigner = remoteSignerOpt ?? derivedRemoteSigner;
|
|
25
29
|
// Ensure we always have a mnemonic for key derivation if none was provided
|
|
@@ -29,6 +33,7 @@ export async function addValidatorKeys(existing, options, log) {
|
|
|
29
33
|
const { validators, summaries } = await buildValidatorEntries({
|
|
30
34
|
validatorCount,
|
|
31
35
|
publisherCount,
|
|
36
|
+
publishers,
|
|
32
37
|
accountIndex,
|
|
33
38
|
baseAddressIndex: effectiveBaseAddressIndex,
|
|
34
39
|
mnemonic: mnemonicToUse,
|
|
@@ -36,8 +41,7 @@ export async function addValidatorKeys(existing, options, log) {
|
|
|
36
41
|
blsPath,
|
|
37
42
|
feeRecipient,
|
|
38
43
|
coinbase,
|
|
39
|
-
remoteSigner
|
|
40
|
-
fundingAccount
|
|
44
|
+
remoteSigner
|
|
41
45
|
});
|
|
42
46
|
keystore.validators.push(...validators);
|
|
43
47
|
// If password provided, write ETH JSON V3 and BLS BN254 keystores and replace plaintext
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate_bls_keypair.d.ts","sourceRoot":"","sources":["../../../src/cmds/validator_keys/generate_bls_keypair.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"generate_bls_keypair.d.ts","sourceRoot":"","sources":["../../../src/cmds/validator_keys/generate_bls_keypair.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAOnD,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,EAAE,GAAG,EAAE,KAAK,iBAetF"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { deriveBlsPrivateKey } from '@aztec/foundation/crypto';
|
|
2
2
|
import { writeFile } from 'fs/promises';
|
|
3
|
-
import { computeBlsPublicKeyCompressed,
|
|
3
|
+
import { computeBlsPublicKeyCompressed, withValidatorIndex } from './shared.js';
|
|
4
|
+
import { defaultBlsPath } from './utils.js';
|
|
4
5
|
export async function generateBlsKeypair(options, log) {
|
|
5
6
|
const { mnemonic, ikm, blsPath, compressed = true, json, out } = options;
|
|
6
7
|
const path = withValidatorIndex(blsPath ?? defaultBlsPath, 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cmds/validator_keys/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAEnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cmds/validator_keys/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAEnD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,WAsI1D"}
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { parseAztecAddress, parseEthereumAddress, parseHex, parseOptionalInteger } from '../../utils/commands.js';
|
|
2
|
-
import { defaultBlsPath } from './
|
|
2
|
+
import { defaultBlsPath } from './utils.js';
|
|
3
3
|
export function injectCommands(program, log) {
|
|
4
4
|
const group = program.command('validator-keys').aliases([
|
|
5
5
|
'valKeys',
|
|
6
6
|
'valkeys'
|
|
7
7
|
]).description('Manage validator keystores for node operators');
|
|
8
|
-
group.command('new').summary('Generate a new validator keystore JSON').description('Generates a new validator keystore with ETH secp256k1 accounts and optional BLS accounts').option('--data-dir <path>', 'Directory to store keystore(s). Defaults to ~/.aztec/keystore').option('--file <name>', 'Keystore file name. Defaults to key1.json (or keyN.json if key1.json exists)').option('--count <N>', 'Number of validators to generate', parseOptionalInteger).option('--publisher-count <N>', 'Number of publisher accounts per validator (default
|
|
8
|
+
group.command('new').summary('Generate a new validator keystore JSON').description('Generates a new validator keystore with ETH secp256k1 accounts and optional BLS accounts').option('--data-dir <path>', 'Directory to store keystore(s). Defaults to ~/.aztec/keystore').option('--file <name>', 'Keystore file name. Defaults to key1.json (or keyN.json if key1.json exists)').option('--count <N>', 'Number of validators to generate', parseOptionalInteger).option('--publisher-count <N>', 'Number of publisher accounts per validator (default 0)', (value)=>parseOptionalInteger(value, 0)).option('--publishers <privateKeys>', 'Comma-separated list of publisher private keys for all validators.', (value)=>value.split(',').map((key)=>key.trim())).option('--mnemonic <mnemonic>', 'Mnemonic for ETH/BLS derivation').option('--passphrase <str>', 'Optional passphrase for mnemonic').option('--account-index <N>', 'Base account index for ETH/BLS derivation', parseOptionalInteger).option('--address-index <N>', 'Base address index for ETH/BLS derivation', parseOptionalInteger).option('--coinbase <address>', 'Coinbase ETH address to use when proposing. Defaults to attester address.', parseEthereumAddress)// TODO: add funding account back in when implemented
|
|
9
|
+
// .option('--funding-account <privateKey|address>', 'ETH private key (or address for remote signer setup) to fund publishers')
|
|
10
|
+
.option('--remote-signer <url>', 'Default remote signer URL for accounts in this file').option('--ikm <hex>', 'Initial keying material for BLS (alternative to mnemonic)', (value)=>parseHex(value, 32)).option('--bls-path <path>', `EIP-2334 path (default ${defaultBlsPath})`).option('--password <str>', 'Password for writing keystore files (ETH JSON V3 and BLS EIP-2335). Empty string allowed').option('--encrypted-keystore-dir <dir>', 'Output directory for encrypted keystore file(s)').option('--json', 'Echo resulting JSON to stdout').option('--staker-output', 'Generate a single staker output JSON file with an array of validator entries').option('--gse-address <address>', 'GSE contract address (required with --staker-output)', parseEthereumAddress).option('--l1-rpc-urls <urls>', 'L1 RPC URLs (comma-separated, required with --staker-output)', (value)=>value.split(',')).option('-c, --l1-chain-id <number>', 'L1 chain ID (required with --staker-output)', (value)=>parseInt(value), 31337).requiredOption('--fee-recipient <address>', 'Aztec address that will receive fees', parseAztecAddress).action(async (options)=>{
|
|
9
11
|
const { newValidatorKeystore } = await import('./new.js');
|
|
10
12
|
await newValidatorKeystore(options, log);
|
|
11
13
|
});
|
|
12
|
-
group.command('add').summary('Augment an existing validator keystore JSON').description('Adds attester/publisher/BLS entries to an existing keystore using the same flags as new').argument('<existing>', 'Path to existing keystore JSON').option('--data-dir <path>', 'Directory where keystore(s) live. (default: ~/.aztec/keystore)').option('--file <name>', 'Override output file name. (default: key<N>.json)').option('--count <N>', 'Number of validators to add. (default: 1)', parseOptionalInteger).option('--publisher-count <N>', 'Number of publisher accounts per validator (default
|
|
14
|
+
group.command('add').summary('Augment an existing validator keystore JSON').description('Adds attester/publisher/BLS entries to an existing keystore using the same flags as new').argument('<existing>', 'Path to existing keystore JSON').option('--data-dir <path>', 'Directory where keystore(s) live. (default: ~/.aztec/keystore)').option('--file <name>', 'Override output file name. (default: key<N>.json)').option('--count <N>', 'Number of validators to add. (default: 1)', parseOptionalInteger).option('--publisher-count <N>', 'Number of publisher accounts per validator (default 0)', (value)=>parseOptionalInteger(value, 0)).option('--publishers <privateKeys>', 'Comma-separated list of publisher private keys for all validators.', (value)=>value.split(',').map((key)=>key.trim())).option('--mnemonic <mnemonic>', 'Mnemonic for ETH/BLS derivation').option('--passphrase <str>', 'Optional passphrase for mnemonic').option('--account-index <N>', 'Base account index for ETH/BLS derivation', parseOptionalInteger).option('--address-index <N>', 'Base address index for ETH/BLS derivation', parseOptionalInteger).option('--coinbase <address>', 'Coinbase ETH address to use when proposing. Defaults to attester address.', parseEthereumAddress)// TODO: add funding account back in when implemented
|
|
15
|
+
// .option('--funding-account <privateKey|address>', 'ETH private key (or address for remote signer setup) to fund publishers')
|
|
16
|
+
.option('--remote-signer <url>', 'Default remote signer URL for accounts in this file').option('--ikm <hex>', 'Initial keying material for BLS (alternative to mnemonic)', (value)=>parseHex(value, 32)).option('--bls-path <path>', `EIP-2334 path (default ${defaultBlsPath})`).option('--empty', 'Generate an empty skeleton without keys').option('--password <str>', 'Password for writing keystore files (ETH JSON V3 and BLS EIP-2335). Empty string allowed').option('--encrypted-keystore-dir <dir>', 'Output directory for encrypted keystore file(s)').option('--json', 'Echo resulting JSON to stdout').requiredOption('--fee-recipient <address>', 'Aztec address that will receive fees', parseAztecAddress).action(async (existing, options)=>{
|
|
13
17
|
const { addValidatorKeys } = await import('./add.js');
|
|
14
18
|
await addValidatorKeys(existing, options, log);
|
|
15
19
|
});
|
|
@@ -6,6 +6,7 @@ export type NewValidatorKeystoreOptions = {
|
|
|
6
6
|
file?: string;
|
|
7
7
|
count?: number;
|
|
8
8
|
publisherCount?: number;
|
|
9
|
+
publishers?: string[];
|
|
9
10
|
mnemonic?: string;
|
|
10
11
|
passphrase?: string;
|
|
11
12
|
accountIndex?: number;
|
|
@@ -19,7 +20,6 @@ export type NewValidatorKeystoreOptions = {
|
|
|
19
20
|
feeRecipient: AztecAddress;
|
|
20
21
|
coinbase?: EthAddress;
|
|
21
22
|
remoteSigner?: string;
|
|
22
|
-
fundingAccount?: EthAddress;
|
|
23
23
|
stakerOutput?: boolean;
|
|
24
24
|
gseAddress?: EthAddress;
|
|
25
25
|
l1RpcUrls?: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"new.d.ts","sourceRoot":"","sources":["../../../src/cmds/validator_keys/new.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"new.d.ts","sourceRoot":"","sources":["../../../src/cmds/validator_keys/new.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAyBhE,MAAM,MAAM,2BAA2B,GAAG;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,YAAY,CAAC;IAC3B,QAAQ,CAAC,EAAE,UAAU,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,EAAE,GAAG,EAAE,KAAK,iBAuJ1F"}
|
|
@@ -5,27 +5,19 @@ import { writeFile } from 'fs/promises';
|
|
|
5
5
|
import { basename, dirname, join } from 'path';
|
|
6
6
|
import { createPublicClient, fallback, http } from 'viem';
|
|
7
7
|
import { generateMnemonic, mnemonicToAccount } from 'viem/accounts';
|
|
8
|
-
import { buildValidatorEntries, logValidatorSummaries, maybePrintJson, resolveKeystoreOutputPath,
|
|
8
|
+
import { buildValidatorEntries, logValidatorSummaries, maybePrintJson, resolveKeystoreOutputPath, writeBlsBn254ToFile, writeEthJsonV3ToFile, writeKeystoreFile } from './shared.js';
|
|
9
9
|
import { processAttesterAccounts } from './staker.js';
|
|
10
|
+
import { validateBlsPathOptions, validatePublisherOptions, validateRemoteSignerOptions, validateStakerOutputOptions } from './utils.js';
|
|
10
11
|
export async function newValidatorKeystore(options, log) {
|
|
11
12
|
// validate bls-path inputs before proceeding with key generation
|
|
12
13
|
validateBlsPathOptions(options);
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
throw new Error('--l1-rpc-urls is required when using --staker-output');
|
|
21
|
-
}
|
|
22
|
-
if (l1ChainId === undefined) {
|
|
23
|
-
throw new Error('--l1-chain-id is required when using --staker-output');
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
if (remoteSigner && !_mnemonic) {
|
|
27
|
-
throw new Error('Using --remote-signer requires a deterministic key source. Provide --mnemonic to derive keys, or omit --remote-signer to write new private keys to keystore.');
|
|
28
|
-
}
|
|
14
|
+
// validate staker output options before proceeding with key generation
|
|
15
|
+
validateStakerOutputOptions(options);
|
|
16
|
+
// validate publisher options
|
|
17
|
+
validatePublisherOptions(options);
|
|
18
|
+
// validate remote signer options
|
|
19
|
+
validateRemoteSignerOptions(options);
|
|
20
|
+
const { dataDir, file, count, publisherCount = 0, publishers, json, coinbase, accountIndex = 0, addressIndex = 0, feeRecipient, remoteSigner, blsPath, ikm, mnemonic: _mnemonic, password, encryptedKeystoreDir, stakerOutput, gseAddress, l1RpcUrls, l1ChainId } = options;
|
|
29
21
|
const mnemonic = _mnemonic ?? generateMnemonic(wordlist);
|
|
30
22
|
if (!_mnemonic && !json) {
|
|
31
23
|
log('No mnemonic provided, generating new one...');
|
|
@@ -40,6 +32,7 @@ export async function newValidatorKeystore(options, log) {
|
|
|
40
32
|
const { validators, summaries } = await buildValidatorEntries({
|
|
41
33
|
validatorCount,
|
|
42
34
|
publisherCount,
|
|
35
|
+
publishers,
|
|
43
36
|
accountIndex,
|
|
44
37
|
baseAddressIndex: addressIndex,
|
|
45
38
|
mnemonic,
|
|
@@ -47,8 +40,7 @@ export async function newValidatorKeystore(options, log) {
|
|
|
47
40
|
blsPath,
|
|
48
41
|
feeRecipient,
|
|
49
42
|
coinbase,
|
|
50
|
-
remoteSigner
|
|
51
|
-
fundingAccount
|
|
43
|
+
remoteSigner
|
|
52
44
|
});
|
|
53
45
|
// If password provided, write ETH JSON V3 and BLS BN254 keystores and replace plaintext
|
|
54
46
|
if (password !== undefined) {
|
|
@@ -10,6 +10,7 @@ export type ValidatorSummary = {
|
|
|
10
10
|
export type BuildValidatorsInput = {
|
|
11
11
|
validatorCount: number;
|
|
12
12
|
publisherCount?: number;
|
|
13
|
+
publishers?: string[];
|
|
13
14
|
accountIndex: number;
|
|
14
15
|
baseAddressIndex: number;
|
|
15
16
|
mnemonic: string;
|
|
@@ -18,17 +19,7 @@ export type BuildValidatorsInput = {
|
|
|
18
19
|
feeRecipient: AztecAddress;
|
|
19
20
|
coinbase?: EthAddress;
|
|
20
21
|
remoteSigner?: string;
|
|
21
|
-
fundingAccount?: EthAddress;
|
|
22
22
|
};
|
|
23
|
-
export declare const defaultBlsPath = "m/12381/3600/0/0/0";
|
|
24
|
-
export declare function validateBlsPathOptions(options: {
|
|
25
|
-
count?: number;
|
|
26
|
-
publisherCount?: number;
|
|
27
|
-
accountIndex?: number;
|
|
28
|
-
addressIndex?: number;
|
|
29
|
-
blsPath?: string;
|
|
30
|
-
ikm?: string;
|
|
31
|
-
}): void;
|
|
32
23
|
export declare function withValidatorIndex(path: string, accountIndex?: number, addressIndex?: number): string;
|
|
33
24
|
/**
|
|
34
25
|
* Compute a compressed BN254 G1 public key from a private key.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/cmds/validator_keys/shared.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/cmds/validator_keys/shared.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAWhE,MAAM,MAAM,gBAAgB,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEvG,MAAM,MAAM,oBAAoB,GAAG;IACjC,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,YAAY,CAAC;IAC3B,QAAQ,CAAC,EAAE,UAAU,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,GAAE,MAAU,EAAE,YAAY,GAAE,MAAU,UAqBlG;AAED;;;;GAIG;AACH,wBAAsB,6BAA6B,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAE1F;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,gBAAgB,EAAE,MAAM,EACxB,YAAY,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,MAAM,GACpB,UAAU,GAAG,aAAa,CAK5B;AAED,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,oBAAoB;;;GAuEtE;AAED,wBAAsB,yBAAyB,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;;;GAoB9E;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,iBAGtE;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,QAsB9E;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,GAAG,SAAS,EAAE,GAAG,EAAE,OAAO,QAIrF;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,MAAM,CAAC,CASjB;AAED,yGAAyG;AACzG,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,iBAAiB,EAAE,EAC/B,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9D,OAAO,CAAC,IAAI,CAAC,CAuBf;AAED,8EAA8E;AAC9E,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,kGAAkG;AAClG,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,iBAAiB,EAAE,EAC/B,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC5C,OAAO,CAAC,IAAI,CAAC,CAsCf"}
|
|
@@ -7,14 +7,7 @@ import { access, writeFile } from 'fs/promises';
|
|
|
7
7
|
import { homedir } from 'os';
|
|
8
8
|
import { dirname, isAbsolute, join } from 'path';
|
|
9
9
|
import { mnemonicToAccount } from 'viem/accounts';
|
|
10
|
-
|
|
11
|
-
export function validateBlsPathOptions(options) {
|
|
12
|
-
if (options.blsPath && options.blsPath !== defaultBlsPath) {
|
|
13
|
-
if (options.count && options.count !== 1 || options.publisherCount && options.publisherCount > 0 || options.accountIndex && options.accountIndex !== 0 || options.addressIndex && options.addressIndex !== 0) {
|
|
14
|
-
throw new Error('--bls-path cannot be used with --count, --publisher-count, --account-index, or --address-index');
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|
|
10
|
+
import { defaultBlsPath } from './utils.js';
|
|
18
11
|
export function withValidatorIndex(path, accountIndex = 0, addressIndex = 0) {
|
|
19
12
|
// NOTE: The legacy BLS CLI is to allow users who generated keys in 2.1.4 to be able to use the same command
|
|
20
13
|
// to re-generate their keys. In 2.1.5 we switched how we append addresses to the path so this is to maintain backwards compatibility.
|
|
@@ -57,7 +50,7 @@ export function deriveEthAttester(mnemonic, baseAccountIndex, addressIndex, remo
|
|
|
57
50
|
} : '0x' + Buffer.from(acct.getHdKey().privateKey).toString('hex');
|
|
58
51
|
}
|
|
59
52
|
export async function buildValidatorEntries(input) {
|
|
60
|
-
const { validatorCount, publisherCount = 0, accountIndex, baseAddressIndex, mnemonic, ikm, blsPath, feeRecipient, coinbase, remoteSigner
|
|
53
|
+
const { validatorCount, publisherCount = 0, publishers, accountIndex, baseAddressIndex, mnemonic, ikm, blsPath, feeRecipient, coinbase, remoteSigner } = input;
|
|
61
54
|
const summaries = [];
|
|
62
55
|
const validators = await Promise.all(Array.from({
|
|
63
56
|
length: validatorCount
|
|
@@ -74,7 +67,10 @@ export async function buildValidatorEntries(input) {
|
|
|
74
67
|
} : ethAttester;
|
|
75
68
|
let publisherField;
|
|
76
69
|
const publisherAddresses = [];
|
|
77
|
-
if (
|
|
70
|
+
if (publishers && publishers.length > 0) {
|
|
71
|
+
publisherAddresses.push(...publishers);
|
|
72
|
+
publisherField = publishers.length === 1 ? publishers[0] : publishers;
|
|
73
|
+
} else if (publisherCount > 0) {
|
|
78
74
|
const publishersBaseIndex = baseAddressIndex + validatorCount + i * publisherCount;
|
|
79
75
|
const publisherAccounts = Array.from({
|
|
80
76
|
length: publisherCount
|
|
@@ -108,8 +104,7 @@ export async function buildValidatorEntries(input) {
|
|
|
108
104
|
publisher: publisherField
|
|
109
105
|
} : {},
|
|
110
106
|
feeRecipient,
|
|
111
|
-
coinbase
|
|
112
|
-
fundingAccount
|
|
107
|
+
coinbase: coinbase ?? attesterEthAddress
|
|
113
108
|
};
|
|
114
109
|
}));
|
|
115
110
|
return {
|
|
@@ -274,9 +269,5 @@ export function maybePrintJson(log, jsonFlag, obj) {
|
|
|
274
269
|
v.publisher = await maybeEncryptEth(pub, `publisher_${i + 1}`);
|
|
275
270
|
}
|
|
276
271
|
}
|
|
277
|
-
// Optional fundingAccount within validator
|
|
278
|
-
if ('fundingAccount' in v) {
|
|
279
|
-
v.fundingAccount = await maybeEncryptEth(v.fundingAccount, `funding_${i + 1}`);
|
|
280
|
-
}
|
|
281
272
|
}
|
|
282
273
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
2
|
+
export declare const defaultBlsPath = "m/12381/3600/0/0/0";
|
|
3
|
+
export declare function validateBlsPathOptions(options: {
|
|
4
|
+
count?: number;
|
|
5
|
+
publisherCount?: number;
|
|
6
|
+
accountIndex?: number;
|
|
7
|
+
addressIndex?: number;
|
|
8
|
+
blsPath?: string;
|
|
9
|
+
ikm?: string;
|
|
10
|
+
}): void;
|
|
11
|
+
export declare function validateStakerOutputOptions(options: {
|
|
12
|
+
stakerOutput?: boolean;
|
|
13
|
+
gseAddress?: EthAddress;
|
|
14
|
+
l1RpcUrls?: string[];
|
|
15
|
+
l1ChainId?: number;
|
|
16
|
+
}): void;
|
|
17
|
+
export declare function validateRemoteSignerOptions(options: {
|
|
18
|
+
remoteSigner?: string;
|
|
19
|
+
mnemonic?: string;
|
|
20
|
+
}): void;
|
|
21
|
+
export declare function validatePublisherOptions(options: {
|
|
22
|
+
publishers?: string[];
|
|
23
|
+
publisherCount?: number;
|
|
24
|
+
}): void;
|
|
25
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/cmds/validator_keys/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAGhE,eAAO,MAAM,cAAc,uBAAuB,CAAC;AAEnD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE;IAC9C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,QAWA;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE;IACnD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,QAeA;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,QAMhG;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,QAwBnG"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ethPrivateKeySchema } from '@aztec/node-keystore';
|
|
2
|
+
export const defaultBlsPath = 'm/12381/3600/0/0/0';
|
|
3
|
+
export function validateBlsPathOptions(options) {
|
|
4
|
+
if (options.blsPath && options.blsPath !== defaultBlsPath) {
|
|
5
|
+
if (options.count && options.count !== 1 || options.publisherCount && options.publisherCount > 0 || options.accountIndex && options.accountIndex !== 0 || options.addressIndex && options.addressIndex !== 0) {
|
|
6
|
+
throw new Error('--bls-path cannot be used with --count, --publisher-count, --account-index, or --address-index');
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export function validateStakerOutputOptions(options) {
|
|
11
|
+
if (!options.stakerOutput) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
// Required options for staker output
|
|
15
|
+
if (!options.gseAddress) {
|
|
16
|
+
throw new Error('--gse-address is required when using --staker-output');
|
|
17
|
+
}
|
|
18
|
+
if (!options.l1RpcUrls || options.l1RpcUrls.length === 0) {
|
|
19
|
+
throw new Error('--l1-rpc-urls is required when using --staker-output');
|
|
20
|
+
}
|
|
21
|
+
if (options.l1ChainId === undefined) {
|
|
22
|
+
throw new Error('--l1-chain-id is required when using --staker-output');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function validateRemoteSignerOptions(options) {
|
|
26
|
+
if (options.remoteSigner && !options.mnemonic) {
|
|
27
|
+
throw new Error('Using --remote-signer requires a deterministic key source. Provide --mnemonic to derive keys, or omit --remote-signer to write new private keys to keystore.');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function validatePublisherOptions(options) {
|
|
31
|
+
if (options.publisherCount && options.publisherCount > 0 && options.publishers && options.publishers.length > 0) {
|
|
32
|
+
throw new Error('--publishers and --publisher-count cannot be used together');
|
|
33
|
+
}
|
|
34
|
+
if (options.publishers && options.publishers.length > 0) {
|
|
35
|
+
// Normalize each private key by adding 0x prefix if missing
|
|
36
|
+
const normalizedKeys = [];
|
|
37
|
+
for (const key of options.publishers){
|
|
38
|
+
let privateKey = key.trim();
|
|
39
|
+
if (!privateKey.startsWith('0x')) {
|
|
40
|
+
privateKey = '0x' + privateKey;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
ethPrivateKeySchema.parse(privateKey);
|
|
44
|
+
normalizedKeys.push(privateKey);
|
|
45
|
+
} catch (error) {
|
|
46
|
+
throw new Error(`Invalid publisher private key: ${error instanceof Error ? error.message : String(error)}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Update the options with the normalized keys
|
|
50
|
+
options.publishers = normalizedKeys;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type NetworkConfig, type NetworkNames } from '@aztec/foundation/config';
|
|
2
2
|
/**
|
|
3
3
|
* Fetches remote network configuration from GitHub with caching support.
|
|
4
|
-
* Uses the reusable cachedFetch utility.
|
|
4
|
+
* Uses the reusable cachedFetch utility. Falls back to metadata.aztec.network if the default URL fails.
|
|
5
5
|
*
|
|
6
6
|
* @param networkName - The network name to fetch config for
|
|
7
7
|
* @param cacheDir - Optional cache directory for storing fetched config
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network_config.d.ts","sourceRoot":"","sources":["../../src/config/network_config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAA0B,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"network_config.d.ts","sourceRoot":"","sources":["../../src/config/network_config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAA0B,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAazG;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,YAAY,EACzB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAapC;AA0DD;;;;;;GAMG;AACH,wBAAsB,kCAAkC,CAAC,WAAW,EAAE,YAAY,iBAoBjF"}
|
|
@@ -4,20 +4,34 @@ import { join } from 'path';
|
|
|
4
4
|
import { cachedFetch } from './cached_fetch.js';
|
|
5
5
|
import { enrichEthAddressVar, enrichVar } from './enrich_env.js';
|
|
6
6
|
const DEFAULT_CONFIG_URL = 'https://raw.githubusercontent.com/AztecProtocol/networks/refs/heads/main/network_config.json';
|
|
7
|
+
const FALLBACK_CONFIG_URL = 'https://metadata.aztec.network/network_config.json';
|
|
7
8
|
const NETWORK_CONFIG_CACHE_DURATION_MS = 60 * 60 * 1000; // 1 hour
|
|
8
9
|
/**
|
|
9
10
|
* Fetches remote network configuration from GitHub with caching support.
|
|
10
|
-
* Uses the reusable cachedFetch utility.
|
|
11
|
+
* Uses the reusable cachedFetch utility. Falls back to metadata.aztec.network if the default URL fails.
|
|
11
12
|
*
|
|
12
13
|
* @param networkName - The network name to fetch config for
|
|
13
14
|
* @param cacheDir - Optional cache directory for storing fetched config
|
|
14
15
|
* @returns Remote configuration for the specified network, or undefined if not found/error
|
|
15
16
|
*/ export async function getNetworkConfig(networkName, cacheDir) {
|
|
16
|
-
|
|
17
|
+
// Try with the primary URL (env var or default)
|
|
17
18
|
const configLocation = process.env.NETWORK_CONFIG_LOCATION || DEFAULT_CONFIG_URL;
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
// First try the primary config location
|
|
20
|
+
let config = await fetchNetworkConfigFromUrl(configLocation, networkName, cacheDir);
|
|
21
|
+
// If primary fails and we were using the default URL, try the fallback
|
|
22
|
+
if (!config && configLocation === DEFAULT_CONFIG_URL) {
|
|
23
|
+
config = await fetchNetworkConfigFromUrl(FALLBACK_CONFIG_URL, networkName, cacheDir);
|
|
20
24
|
}
|
|
25
|
+
return config;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Helper function to fetch network config from a specific URL.
|
|
29
|
+
* @param configLocation - The URL or file path to fetch from
|
|
30
|
+
* @param networkName - The network name to fetch config for
|
|
31
|
+
* @param cacheDir - Optional cache directory for storing fetched config
|
|
32
|
+
* @returns Remote configuration for the specified network, or undefined if not found/error
|
|
33
|
+
*/ async function fetchNetworkConfigFromUrl(configLocation, networkName, cacheDir) {
|
|
34
|
+
let url;
|
|
21
35
|
try {
|
|
22
36
|
if (configLocation.includes('://')) {
|
|
23
37
|
url = new URL(configLocation);
|
|
@@ -67,7 +81,7 @@ const NETWORK_CONFIG_CACHE_DURATION_MS = 60 * 60 * 1000; // 1 hour
|
|
|
67
81
|
const cacheDir = process.env.DATA_DIRECTORY ? join(process.env.DATA_DIRECTORY, 'cache') : undefined;
|
|
68
82
|
const networkConfig = await getNetworkConfig(networkName, cacheDir);
|
|
69
83
|
if (!networkConfig) {
|
|
70
|
-
|
|
84
|
+
throw new Error(`Failed to fetch network config for network: ${networkName}`);
|
|
71
85
|
}
|
|
72
86
|
enrichVar('BOOTSTRAP_NODES', networkConfig.bootnodes.join(','));
|
|
73
87
|
enrichVar('L1_CHAIN_ID', String(networkConfig.l1ChainId));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/cli",
|
|
3
|
-
"version": "3.0.0-nightly.
|
|
3
|
+
"version": "3.0.0-nightly.20251121",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./contracts": "./dest/cmds/contracts/index.js",
|
|
@@ -71,21 +71,21 @@
|
|
|
71
71
|
]
|
|
72
72
|
},
|
|
73
73
|
"dependencies": {
|
|
74
|
-
"@aztec/accounts": "3.0.0-nightly.
|
|
75
|
-
"@aztec/archiver": "3.0.0-nightly.
|
|
76
|
-
"@aztec/aztec.js": "3.0.0-nightly.
|
|
77
|
-
"@aztec/constants": "3.0.0-nightly.
|
|
78
|
-
"@aztec/entrypoints": "3.0.0-nightly.
|
|
79
|
-
"@aztec/ethereum": "3.0.0-nightly.
|
|
80
|
-
"@aztec/foundation": "3.0.0-nightly.
|
|
81
|
-
"@aztec/l1-artifacts": "3.0.0-nightly.
|
|
82
|
-
"@aztec/node-keystore": "3.0.0-nightly.
|
|
83
|
-
"@aztec/node-lib": "3.0.0-nightly.
|
|
84
|
-
"@aztec/p2p": "3.0.0-nightly.
|
|
85
|
-
"@aztec/protocol-contracts": "3.0.0-nightly.
|
|
86
|
-
"@aztec/stdlib": "3.0.0-nightly.
|
|
87
|
-
"@aztec/test-wallet": "3.0.0-nightly.
|
|
88
|
-
"@aztec/world-state": "3.0.0-nightly.
|
|
74
|
+
"@aztec/accounts": "3.0.0-nightly.20251121",
|
|
75
|
+
"@aztec/archiver": "3.0.0-nightly.20251121",
|
|
76
|
+
"@aztec/aztec.js": "3.0.0-nightly.20251121",
|
|
77
|
+
"@aztec/constants": "3.0.0-nightly.20251121",
|
|
78
|
+
"@aztec/entrypoints": "3.0.0-nightly.20251121",
|
|
79
|
+
"@aztec/ethereum": "3.0.0-nightly.20251121",
|
|
80
|
+
"@aztec/foundation": "3.0.0-nightly.20251121",
|
|
81
|
+
"@aztec/l1-artifacts": "3.0.0-nightly.20251121",
|
|
82
|
+
"@aztec/node-keystore": "3.0.0-nightly.20251121",
|
|
83
|
+
"@aztec/node-lib": "3.0.0-nightly.20251121",
|
|
84
|
+
"@aztec/p2p": "3.0.0-nightly.20251121",
|
|
85
|
+
"@aztec/protocol-contracts": "3.0.0-nightly.20251121",
|
|
86
|
+
"@aztec/stdlib": "3.0.0-nightly.20251121",
|
|
87
|
+
"@aztec/test-wallet": "3.0.0-nightly.20251121",
|
|
88
|
+
"@aztec/world-state": "3.0.0-nightly.20251121",
|
|
89
89
|
"@ethersproject/wallet": "^5.8.0",
|
|
90
90
|
"@iarna/toml": "^2.2.5",
|
|
91
91
|
"@libp2p/peer-id-factory": "^3.0.4",
|
|
@@ -99,9 +99,9 @@
|
|
|
99
99
|
"viem": "npm:@spalladino/viem@2.38.2-eip7594.0"
|
|
100
100
|
},
|
|
101
101
|
"devDependencies": {
|
|
102
|
-
"@aztec/aztec-node": "3.0.0-nightly.
|
|
103
|
-
"@aztec/kv-store": "3.0.0-nightly.
|
|
104
|
-
"@aztec/telemetry-client": "3.0.0-nightly.
|
|
102
|
+
"@aztec/aztec-node": "3.0.0-nightly.20251121",
|
|
103
|
+
"@aztec/kv-store": "3.0.0-nightly.20251121",
|
|
104
|
+
"@aztec/telemetry-client": "3.0.0-nightly.20251121",
|
|
105
105
|
"@jest/globals": "^30.0.0",
|
|
106
106
|
"@types/jest": "^30.0.0",
|
|
107
107
|
"@types/lodash.chunk": "^4.2.9",
|
|
@@ -117,15 +117,15 @@
|
|
|
117
117
|
"typescript": "^5.3.3"
|
|
118
118
|
},
|
|
119
119
|
"peerDependencies": {
|
|
120
|
-
"@aztec/accounts": "3.0.0-nightly.
|
|
121
|
-
"@aztec/bb-prover": "3.0.0-nightly.
|
|
122
|
-
"@aztec/ethereum": "3.0.0-nightly.
|
|
123
|
-
"@aztec/l1-artifacts": "3.0.0-nightly.
|
|
124
|
-
"@aztec/noir-contracts.js": "3.0.0-nightly.
|
|
125
|
-
"@aztec/noir-protocol-circuits-types": "3.0.0-nightly.
|
|
126
|
-
"@aztec/noir-test-contracts.js": "3.0.0-nightly.
|
|
127
|
-
"@aztec/protocol-contracts": "3.0.0-nightly.
|
|
128
|
-
"@aztec/stdlib": "3.0.0-nightly.
|
|
120
|
+
"@aztec/accounts": "3.0.0-nightly.20251121",
|
|
121
|
+
"@aztec/bb-prover": "3.0.0-nightly.20251121",
|
|
122
|
+
"@aztec/ethereum": "3.0.0-nightly.20251121",
|
|
123
|
+
"@aztec/l1-artifacts": "3.0.0-nightly.20251121",
|
|
124
|
+
"@aztec/noir-contracts.js": "3.0.0-nightly.20251121",
|
|
125
|
+
"@aztec/noir-protocol-circuits-types": "3.0.0-nightly.20251121",
|
|
126
|
+
"@aztec/noir-test-contracts.js": "3.0.0-nightly.20251121",
|
|
127
|
+
"@aztec/protocol-contracts": "3.0.0-nightly.20251121",
|
|
128
|
+
"@aztec/stdlib": "3.0.0-nightly.20251121"
|
|
129
129
|
},
|
|
130
130
|
"files": [
|
|
131
131
|
"dest",
|
|
@@ -12,23 +12,28 @@ import {
|
|
|
12
12
|
buildValidatorEntries,
|
|
13
13
|
logValidatorSummaries,
|
|
14
14
|
maybePrintJson,
|
|
15
|
-
validateBlsPathOptions,
|
|
16
15
|
writeBlsBn254ToFile,
|
|
17
16
|
writeEthJsonV3ToFile,
|
|
18
17
|
writeKeystoreFile,
|
|
19
18
|
} from './shared.js';
|
|
19
|
+
import { validateBlsPathOptions, validatePublisherOptions, validateRemoteSignerOptions } from './utils.js';
|
|
20
20
|
|
|
21
21
|
export type AddValidatorKeysOptions = NewValidatorKeystoreOptions;
|
|
22
22
|
|
|
23
23
|
export async function addValidatorKeys(existing: string, options: AddValidatorKeysOptions, log: LogFn) {
|
|
24
24
|
// validate bls-path inputs before proceeding with key generation
|
|
25
25
|
validateBlsPathOptions(options);
|
|
26
|
+
// validate publisher options
|
|
27
|
+
validatePublisherOptions(options);
|
|
28
|
+
// validate remote signer options
|
|
29
|
+
validateRemoteSignerOptions(options);
|
|
26
30
|
|
|
27
31
|
const {
|
|
28
32
|
dataDir,
|
|
29
33
|
file,
|
|
30
34
|
count,
|
|
31
35
|
publisherCount = 0,
|
|
36
|
+
publishers,
|
|
32
37
|
mnemonic,
|
|
33
38
|
accountIndex = 0,
|
|
34
39
|
addressIndex,
|
|
@@ -37,7 +42,6 @@ export async function addValidatorKeys(existing: string, options: AddValidatorKe
|
|
|
37
42
|
json,
|
|
38
43
|
feeRecipient: feeRecipientOpt,
|
|
39
44
|
coinbase: coinbaseOpt,
|
|
40
|
-
fundingAccount: fundingAccountOpt,
|
|
41
45
|
remoteSigner: remoteSignerOpt,
|
|
42
46
|
password,
|
|
43
47
|
encryptedKeystoreDir,
|
|
@@ -58,8 +62,6 @@ export async function addValidatorKeys(existing: string, options: AddValidatorKe
|
|
|
58
62
|
throw new Error('feeRecipient is required (either present in existing file or via --fee-recipient)');
|
|
59
63
|
}
|
|
60
64
|
const coinbase = (coinbaseOpt as EthAddress | undefined) ?? (first.coinbase as EthAddress | undefined);
|
|
61
|
-
const fundingAccount =
|
|
62
|
-
(fundingAccountOpt as EthAddress | undefined) ?? (first.fundingAccount as EthAddress | undefined);
|
|
63
65
|
const derivedRemoteSigner = (first.attester as any)?.remoteSignerUrl || (first.attester as any)?.eth?.remoteSignerUrl;
|
|
64
66
|
const remoteSigner = remoteSignerOpt ?? derivedRemoteSigner;
|
|
65
67
|
|
|
@@ -73,6 +75,7 @@ export async function addValidatorKeys(existing: string, options: AddValidatorKe
|
|
|
73
75
|
const { validators, summaries } = await buildValidatorEntries({
|
|
74
76
|
validatorCount,
|
|
75
77
|
publisherCount,
|
|
78
|
+
publishers,
|
|
76
79
|
accountIndex,
|
|
77
80
|
baseAddressIndex: effectiveBaseAddressIndex,
|
|
78
81
|
mnemonic: mnemonicToUse,
|
|
@@ -81,7 +84,6 @@ export async function addValidatorKeys(existing: string, options: AddValidatorKe
|
|
|
81
84
|
feeRecipient,
|
|
82
85
|
coinbase,
|
|
83
86
|
remoteSigner,
|
|
84
|
-
fundingAccount,
|
|
85
87
|
});
|
|
86
88
|
|
|
87
89
|
keystore.validators.push(...validators);
|
|
@@ -3,7 +3,8 @@ import type { LogFn } from '@aztec/foundation/log';
|
|
|
3
3
|
|
|
4
4
|
import { writeFile } from 'fs/promises';
|
|
5
5
|
|
|
6
|
-
import { computeBlsPublicKeyCompressed,
|
|
6
|
+
import { computeBlsPublicKeyCompressed, withValidatorIndex } from './shared.js';
|
|
7
|
+
import { defaultBlsPath } from './utils.js';
|
|
7
8
|
|
|
8
9
|
export type GenerateBlsKeypairOptions = {
|
|
9
10
|
mnemonic?: string;
|
|
@@ -3,7 +3,7 @@ import type { LogFn } from '@aztec/foundation/log';
|
|
|
3
3
|
import { Command } from 'commander';
|
|
4
4
|
|
|
5
5
|
import { parseAztecAddress, parseEthereumAddress, parseHex, parseOptionalInteger } from '../../utils/commands.js';
|
|
6
|
-
import { defaultBlsPath } from './
|
|
6
|
+
import { defaultBlsPath } from './utils.js';
|
|
7
7
|
|
|
8
8
|
export function injectCommands(program: Command, log: LogFn) {
|
|
9
9
|
const group = program
|
|
@@ -18,15 +18,23 @@ export function injectCommands(program: Command, log: LogFn) {
|
|
|
18
18
|
.option('--data-dir <path>', 'Directory to store keystore(s). Defaults to ~/.aztec/keystore')
|
|
19
19
|
.option('--file <name>', 'Keystore file name. Defaults to key1.json (or keyN.json if key1.json exists)')
|
|
20
20
|
.option('--count <N>', 'Number of validators to generate', parseOptionalInteger)
|
|
21
|
-
.option('--publisher-count <N>', 'Number of publisher accounts per validator (default
|
|
21
|
+
.option('--publisher-count <N>', 'Number of publisher accounts per validator (default 0)', value =>
|
|
22
22
|
parseOptionalInteger(value, 0),
|
|
23
23
|
)
|
|
24
|
+
.option('--publishers <privateKeys>', 'Comma-separated list of publisher private keys for all validators.', value =>
|
|
25
|
+
value.split(',').map((key: string) => key.trim()),
|
|
26
|
+
)
|
|
24
27
|
.option('--mnemonic <mnemonic>', 'Mnemonic for ETH/BLS derivation')
|
|
25
28
|
.option('--passphrase <str>', 'Optional passphrase for mnemonic')
|
|
26
29
|
.option('--account-index <N>', 'Base account index for ETH/BLS derivation', parseOptionalInteger)
|
|
27
30
|
.option('--address-index <N>', 'Base address index for ETH/BLS derivation', parseOptionalInteger)
|
|
28
|
-
.option(
|
|
29
|
-
|
|
31
|
+
.option(
|
|
32
|
+
'--coinbase <address>',
|
|
33
|
+
'Coinbase ETH address to use when proposing. Defaults to attester address.',
|
|
34
|
+
parseEthereumAddress,
|
|
35
|
+
)
|
|
36
|
+
// TODO: add funding account back in when implemented
|
|
37
|
+
// .option('--funding-account <privateKey|address>', 'ETH private key (or address for remote signer setup) to fund publishers')
|
|
30
38
|
.option('--remote-signer <url>', 'Default remote signer URL for accounts in this file')
|
|
31
39
|
.option('--ikm <hex>', 'Initial keying material for BLS (alternative to mnemonic)', value => parseHex(value, 32))
|
|
32
40
|
.option('--bls-path <path>', `EIP-2334 path (default ${defaultBlsPath})`)
|
|
@@ -62,15 +70,23 @@ export function injectCommands(program: Command, log: LogFn) {
|
|
|
62
70
|
.option('--data-dir <path>', 'Directory where keystore(s) live. (default: ~/.aztec/keystore)')
|
|
63
71
|
.option('--file <name>', 'Override output file name. (default: key<N>.json)')
|
|
64
72
|
.option('--count <N>', 'Number of validators to add. (default: 1)', parseOptionalInteger)
|
|
65
|
-
.option('--publisher-count <N>', 'Number of publisher accounts per validator (default
|
|
73
|
+
.option('--publisher-count <N>', 'Number of publisher accounts per validator (default 0)', value =>
|
|
66
74
|
parseOptionalInteger(value, 0),
|
|
67
75
|
)
|
|
76
|
+
.option('--publishers <privateKeys>', 'Comma-separated list of publisher private keys for all validators.', value =>
|
|
77
|
+
value.split(',').map((key: string) => key.trim()),
|
|
78
|
+
)
|
|
68
79
|
.option('--mnemonic <mnemonic>', 'Mnemonic for ETH/BLS derivation')
|
|
69
80
|
.option('--passphrase <str>', 'Optional passphrase for mnemonic')
|
|
70
81
|
.option('--account-index <N>', 'Base account index for ETH/BLS derivation', parseOptionalInteger)
|
|
71
82
|
.option('--address-index <N>', 'Base address index for ETH/BLS derivation', parseOptionalInteger)
|
|
72
|
-
.option(
|
|
73
|
-
|
|
83
|
+
.option(
|
|
84
|
+
'--coinbase <address>',
|
|
85
|
+
'Coinbase ETH address to use when proposing. Defaults to attester address.',
|
|
86
|
+
parseEthereumAddress,
|
|
87
|
+
)
|
|
88
|
+
// TODO: add funding account back in when implemented
|
|
89
|
+
// .option('--funding-account <privateKey|address>', 'ETH private key (or address for remote signer setup) to fund publishers')
|
|
74
90
|
.option('--remote-signer <url>', 'Default remote signer URL for accounts in this file')
|
|
75
91
|
.option('--ikm <hex>', 'Initial keying material for BLS (alternative to mnemonic)', value => parseHex(value, 32))
|
|
76
92
|
.option('--bls-path <path>', `EIP-2334 path (default ${defaultBlsPath})`)
|
|
@@ -15,18 +15,24 @@ import {
|
|
|
15
15
|
logValidatorSummaries,
|
|
16
16
|
maybePrintJson,
|
|
17
17
|
resolveKeystoreOutputPath,
|
|
18
|
-
validateBlsPathOptions,
|
|
19
18
|
writeBlsBn254ToFile,
|
|
20
19
|
writeEthJsonV3ToFile,
|
|
21
20
|
writeKeystoreFile,
|
|
22
21
|
} from './shared.js';
|
|
23
22
|
import { processAttesterAccounts } from './staker.js';
|
|
23
|
+
import {
|
|
24
|
+
validateBlsPathOptions,
|
|
25
|
+
validatePublisherOptions,
|
|
26
|
+
validateRemoteSignerOptions,
|
|
27
|
+
validateStakerOutputOptions,
|
|
28
|
+
} from './utils.js';
|
|
24
29
|
|
|
25
30
|
export type NewValidatorKeystoreOptions = {
|
|
26
31
|
dataDir?: string;
|
|
27
32
|
file?: string;
|
|
28
33
|
count?: number;
|
|
29
34
|
publisherCount?: number;
|
|
35
|
+
publishers?: string[];
|
|
30
36
|
mnemonic?: string;
|
|
31
37
|
passphrase?: string;
|
|
32
38
|
accountIndex?: number;
|
|
@@ -40,7 +46,6 @@ export type NewValidatorKeystoreOptions = {
|
|
|
40
46
|
feeRecipient: AztecAddress;
|
|
41
47
|
coinbase?: EthAddress;
|
|
42
48
|
remoteSigner?: string;
|
|
43
|
-
fundingAccount?: EthAddress;
|
|
44
49
|
stakerOutput?: boolean;
|
|
45
50
|
gseAddress?: EthAddress;
|
|
46
51
|
l1RpcUrls?: string[];
|
|
@@ -50,19 +55,25 @@ export type NewValidatorKeystoreOptions = {
|
|
|
50
55
|
export async function newValidatorKeystore(options: NewValidatorKeystoreOptions, log: LogFn) {
|
|
51
56
|
// validate bls-path inputs before proceeding with key generation
|
|
52
57
|
validateBlsPathOptions(options);
|
|
58
|
+
// validate staker output options before proceeding with key generation
|
|
59
|
+
validateStakerOutputOptions(options);
|
|
60
|
+
// validate publisher options
|
|
61
|
+
validatePublisherOptions(options);
|
|
62
|
+
// validate remote signer options
|
|
63
|
+
validateRemoteSignerOptions(options);
|
|
53
64
|
|
|
54
65
|
const {
|
|
55
66
|
dataDir,
|
|
56
67
|
file,
|
|
57
68
|
count,
|
|
58
69
|
publisherCount = 0,
|
|
70
|
+
publishers,
|
|
59
71
|
json,
|
|
60
72
|
coinbase,
|
|
61
73
|
accountIndex = 0,
|
|
62
74
|
addressIndex = 0,
|
|
63
75
|
feeRecipient,
|
|
64
76
|
remoteSigner,
|
|
65
|
-
fundingAccount,
|
|
66
77
|
blsPath,
|
|
67
78
|
ikm,
|
|
68
79
|
mnemonic: _mnemonic,
|
|
@@ -74,25 +85,6 @@ export async function newValidatorKeystore(options: NewValidatorKeystoreOptions,
|
|
|
74
85
|
l1ChainId,
|
|
75
86
|
} = options;
|
|
76
87
|
|
|
77
|
-
// Validate staker output requirements
|
|
78
|
-
if (stakerOutput) {
|
|
79
|
-
if (!gseAddress) {
|
|
80
|
-
throw new Error('--gse-address is required when using --staker-output');
|
|
81
|
-
}
|
|
82
|
-
if (!l1RpcUrls || l1RpcUrls.length === 0) {
|
|
83
|
-
throw new Error('--l1-rpc-urls is required when using --staker-output');
|
|
84
|
-
}
|
|
85
|
-
if (l1ChainId === undefined) {
|
|
86
|
-
throw new Error('--l1-chain-id is required when using --staker-output');
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (remoteSigner && !_mnemonic) {
|
|
91
|
-
throw new Error(
|
|
92
|
-
'Using --remote-signer requires a deterministic key source. Provide --mnemonic to derive keys, or omit --remote-signer to write new private keys to keystore.',
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
88
|
const mnemonic = _mnemonic ?? generateMnemonic(wordlist);
|
|
97
89
|
|
|
98
90
|
if (!_mnemonic && !json) {
|
|
@@ -110,6 +102,7 @@ export async function newValidatorKeystore(options: NewValidatorKeystoreOptions,
|
|
|
110
102
|
const { validators, summaries } = await buildValidatorEntries({
|
|
111
103
|
validatorCount,
|
|
112
104
|
publisherCount,
|
|
105
|
+
publishers,
|
|
113
106
|
accountIndex,
|
|
114
107
|
baseAddressIndex: addressIndex,
|
|
115
108
|
mnemonic,
|
|
@@ -118,7 +111,6 @@ export async function newValidatorKeystore(options: NewValidatorKeystoreOptions,
|
|
|
118
111
|
feeRecipient,
|
|
119
112
|
coinbase,
|
|
120
113
|
remoteSigner,
|
|
121
|
-
fundingAccount,
|
|
122
114
|
});
|
|
123
115
|
|
|
124
116
|
// If password provided, write ETH JSON V3 and BLS BN254 keystores and replace plaintext
|
|
@@ -13,11 +13,14 @@ import { homedir } from 'os';
|
|
|
13
13
|
import { dirname, isAbsolute, join } from 'path';
|
|
14
14
|
import { mnemonicToAccount } from 'viem/accounts';
|
|
15
15
|
|
|
16
|
+
import { defaultBlsPath } from './utils.js';
|
|
17
|
+
|
|
16
18
|
export type ValidatorSummary = { attesterEth?: string; attesterBls?: string; publisherEth?: string[] };
|
|
17
19
|
|
|
18
20
|
export type BuildValidatorsInput = {
|
|
19
21
|
validatorCount: number;
|
|
20
22
|
publisherCount?: number;
|
|
23
|
+
publishers?: string[];
|
|
21
24
|
accountIndex: number;
|
|
22
25
|
baseAddressIndex: number;
|
|
23
26
|
mnemonic: string;
|
|
@@ -26,31 +29,8 @@ export type BuildValidatorsInput = {
|
|
|
26
29
|
feeRecipient: AztecAddress;
|
|
27
30
|
coinbase?: EthAddress;
|
|
28
31
|
remoteSigner?: string;
|
|
29
|
-
fundingAccount?: EthAddress;
|
|
30
32
|
};
|
|
31
33
|
|
|
32
|
-
export const defaultBlsPath = 'm/12381/3600/0/0/0';
|
|
33
|
-
|
|
34
|
-
export function validateBlsPathOptions(options: {
|
|
35
|
-
count?: number;
|
|
36
|
-
publisherCount?: number;
|
|
37
|
-
accountIndex?: number;
|
|
38
|
-
addressIndex?: number;
|
|
39
|
-
blsPath?: string;
|
|
40
|
-
ikm?: string;
|
|
41
|
-
}) {
|
|
42
|
-
if (options.blsPath && options.blsPath !== defaultBlsPath) {
|
|
43
|
-
if (
|
|
44
|
-
(options.count && options.count !== 1) ||
|
|
45
|
-
(options.publisherCount && options.publisherCount > 0) ||
|
|
46
|
-
(options.accountIndex && options.accountIndex !== 0) ||
|
|
47
|
-
(options.addressIndex && options.addressIndex !== 0)
|
|
48
|
-
) {
|
|
49
|
-
throw new Error('--bls-path cannot be used with --count, --publisher-count, --account-index, or --address-index');
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
34
|
export function withValidatorIndex(path: string, accountIndex: number = 0, addressIndex: number = 0) {
|
|
55
35
|
// NOTE: The legacy BLS CLI is to allow users who generated keys in 2.1.4 to be able to use the same command
|
|
56
36
|
// to re-generate their keys. In 2.1.5 we switched how we append addresses to the path so this is to maintain backwards compatibility.
|
|
@@ -99,6 +79,7 @@ export async function buildValidatorEntries(input: BuildValidatorsInput) {
|
|
|
99
79
|
const {
|
|
100
80
|
validatorCount,
|
|
101
81
|
publisherCount = 0,
|
|
82
|
+
publishers,
|
|
102
83
|
accountIndex,
|
|
103
84
|
baseAddressIndex,
|
|
104
85
|
mnemonic,
|
|
@@ -107,7 +88,6 @@ export async function buildValidatorEntries(input: BuildValidatorsInput) {
|
|
|
107
88
|
feeRecipient,
|
|
108
89
|
coinbase,
|
|
109
90
|
remoteSigner,
|
|
110
|
-
fundingAccount,
|
|
111
91
|
} = input;
|
|
112
92
|
|
|
113
93
|
const summaries: ValidatorSummary[] = [];
|
|
@@ -126,7 +106,10 @@ export async function buildValidatorEntries(input: BuildValidatorsInput) {
|
|
|
126
106
|
|
|
127
107
|
let publisherField: EthAccount | EthPrivateKey | (EthAccount | EthPrivateKey)[] | undefined;
|
|
128
108
|
const publisherAddresses: string[] = [];
|
|
129
|
-
if (
|
|
109
|
+
if (publishers && publishers.length > 0) {
|
|
110
|
+
publisherAddresses.push(...publishers);
|
|
111
|
+
publisherField = publishers.length === 1 ? (publishers[0] as EthPrivateKey) : (publishers as EthPrivateKey[]);
|
|
112
|
+
} else if (publisherCount > 0) {
|
|
130
113
|
const publishersBaseIndex = baseAddressIndex + validatorCount + i * publisherCount;
|
|
131
114
|
const publisherAccounts = Array.from({ length: publisherCount }, (_unused2, j) => {
|
|
132
115
|
const publisherAddressIndex = publishersBaseIndex + j;
|
|
@@ -157,8 +140,7 @@ export async function buildValidatorEntries(input: BuildValidatorsInput) {
|
|
|
157
140
|
attester,
|
|
158
141
|
...(publisherField !== undefined ? { publisher: publisherField } : {}),
|
|
159
142
|
feeRecipient,
|
|
160
|
-
coinbase,
|
|
161
|
-
fundingAccount,
|
|
143
|
+
coinbase: coinbase ?? attesterEthAddress,
|
|
162
144
|
} as ValidatorKeyStore;
|
|
163
145
|
}),
|
|
164
146
|
);
|
|
@@ -339,10 +321,5 @@ export async function writeEthJsonV3ToFile(
|
|
|
339
321
|
(v as any).publisher = await maybeEncryptEth(pub, `publisher_${i + 1}`);
|
|
340
322
|
}
|
|
341
323
|
}
|
|
342
|
-
|
|
343
|
-
// Optional fundingAccount within validator
|
|
344
|
-
if ('fundingAccount' in v) {
|
|
345
|
-
(v as any).fundingAccount = await maybeEncryptEth((v as any).fundingAccount, `funding_${i + 1}`);
|
|
346
|
-
}
|
|
347
324
|
}
|
|
348
325
|
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
2
|
+
import { type EthPrivateKey, ethPrivateKeySchema } from '@aztec/node-keystore';
|
|
3
|
+
|
|
4
|
+
export const defaultBlsPath = 'm/12381/3600/0/0/0';
|
|
5
|
+
|
|
6
|
+
export function validateBlsPathOptions(options: {
|
|
7
|
+
count?: number;
|
|
8
|
+
publisherCount?: number;
|
|
9
|
+
accountIndex?: number;
|
|
10
|
+
addressIndex?: number;
|
|
11
|
+
blsPath?: string;
|
|
12
|
+
ikm?: string;
|
|
13
|
+
}) {
|
|
14
|
+
if (options.blsPath && options.blsPath !== defaultBlsPath) {
|
|
15
|
+
if (
|
|
16
|
+
(options.count && options.count !== 1) ||
|
|
17
|
+
(options.publisherCount && options.publisherCount > 0) ||
|
|
18
|
+
(options.accountIndex && options.accountIndex !== 0) ||
|
|
19
|
+
(options.addressIndex && options.addressIndex !== 0)
|
|
20
|
+
) {
|
|
21
|
+
throw new Error('--bls-path cannot be used with --count, --publisher-count, --account-index, or --address-index');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function validateStakerOutputOptions(options: {
|
|
27
|
+
stakerOutput?: boolean;
|
|
28
|
+
gseAddress?: EthAddress;
|
|
29
|
+
l1RpcUrls?: string[];
|
|
30
|
+
l1ChainId?: number;
|
|
31
|
+
}) {
|
|
32
|
+
if (!options.stakerOutput) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
// Required options for staker output
|
|
36
|
+
if (!options.gseAddress) {
|
|
37
|
+
throw new Error('--gse-address is required when using --staker-output');
|
|
38
|
+
}
|
|
39
|
+
if (!options.l1RpcUrls || options.l1RpcUrls.length === 0) {
|
|
40
|
+
throw new Error('--l1-rpc-urls is required when using --staker-output');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (options.l1ChainId === undefined) {
|
|
44
|
+
throw new Error('--l1-chain-id is required when using --staker-output');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function validateRemoteSignerOptions(options: { remoteSigner?: string; mnemonic?: string }) {
|
|
49
|
+
if (options.remoteSigner && !options.mnemonic) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
'Using --remote-signer requires a deterministic key source. Provide --mnemonic to derive keys, or omit --remote-signer to write new private keys to keystore.',
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function validatePublisherOptions(options: { publishers?: string[]; publisherCount?: number }) {
|
|
57
|
+
if (options.publisherCount && options.publisherCount > 0 && options.publishers && options.publishers.length > 0) {
|
|
58
|
+
throw new Error('--publishers and --publisher-count cannot be used together');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (options.publishers && options.publishers.length > 0) {
|
|
62
|
+
// Normalize each private key by adding 0x prefix if missing
|
|
63
|
+
const normalizedKeys: string[] = [];
|
|
64
|
+
for (const key of options.publishers) {
|
|
65
|
+
let privateKey = key.trim();
|
|
66
|
+
if (!privateKey.startsWith('0x')) {
|
|
67
|
+
privateKey = '0x' + privateKey;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
ethPrivateKeySchema.parse(privateKey);
|
|
72
|
+
normalizedKeys.push(privateKey);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
throw new Error(`Invalid publisher private key: ${error instanceof Error ? error.message : String(error)}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Update the options with the normalized keys
|
|
78
|
+
options.publishers = normalizedKeys as EthPrivateKey[];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -8,11 +8,12 @@ import { enrichEthAddressVar, enrichVar } from './enrich_env.js';
|
|
|
8
8
|
|
|
9
9
|
const DEFAULT_CONFIG_URL =
|
|
10
10
|
'https://raw.githubusercontent.com/AztecProtocol/networks/refs/heads/main/network_config.json';
|
|
11
|
+
const FALLBACK_CONFIG_URL = 'https://metadata.aztec.network/network_config.json';
|
|
11
12
|
const NETWORK_CONFIG_CACHE_DURATION_MS = 60 * 60 * 1000; // 1 hour
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Fetches remote network configuration from GitHub with caching support.
|
|
15
|
-
* Uses the reusable cachedFetch utility.
|
|
16
|
+
* Uses the reusable cachedFetch utility. Falls back to metadata.aztec.network if the default URL fails.
|
|
16
17
|
*
|
|
17
18
|
* @param networkName - The network name to fetch config for
|
|
18
19
|
* @param cacheDir - Optional cache directory for storing fetched config
|
|
@@ -22,13 +23,33 @@ export async function getNetworkConfig(
|
|
|
22
23
|
networkName: NetworkNames,
|
|
23
24
|
cacheDir?: string,
|
|
24
25
|
): Promise<NetworkConfig | undefined> {
|
|
25
|
-
|
|
26
|
+
// Try with the primary URL (env var or default)
|
|
26
27
|
const configLocation = process.env.NETWORK_CONFIG_LOCATION || DEFAULT_CONFIG_URL;
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
// First try the primary config location
|
|
30
|
+
let config = await fetchNetworkConfigFromUrl(configLocation, networkName, cacheDir);
|
|
31
|
+
|
|
32
|
+
// If primary fails and we were using the default URL, try the fallback
|
|
33
|
+
if (!config && configLocation === DEFAULT_CONFIG_URL) {
|
|
34
|
+
config = await fetchNetworkConfigFromUrl(FALLBACK_CONFIG_URL, networkName, cacheDir);
|
|
30
35
|
}
|
|
31
36
|
|
|
37
|
+
return config;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Helper function to fetch network config from a specific URL.
|
|
42
|
+
* @param configLocation - The URL or file path to fetch from
|
|
43
|
+
* @param networkName - The network name to fetch config for
|
|
44
|
+
* @param cacheDir - Optional cache directory for storing fetched config
|
|
45
|
+
* @returns Remote configuration for the specified network, or undefined if not found/error
|
|
46
|
+
*/
|
|
47
|
+
async function fetchNetworkConfigFromUrl(
|
|
48
|
+
configLocation: string,
|
|
49
|
+
networkName: NetworkNames,
|
|
50
|
+
cacheDir?: string,
|
|
51
|
+
): Promise<NetworkConfig | undefined> {
|
|
52
|
+
let url: URL | undefined;
|
|
32
53
|
try {
|
|
33
54
|
if (configLocation.includes('://')) {
|
|
34
55
|
url = new URL(configLocation);
|
|
@@ -88,7 +109,7 @@ export async function enrichEnvironmentWithNetworkConfig(networkName: NetworkNam
|
|
|
88
109
|
const networkConfig = await getNetworkConfig(networkName, cacheDir);
|
|
89
110
|
|
|
90
111
|
if (!networkConfig) {
|
|
91
|
-
|
|
112
|
+
throw new Error(`Failed to fetch network config for network: ${networkName}`);
|
|
92
113
|
}
|
|
93
114
|
|
|
94
115
|
enrichVar('BOOTSTRAP_NODES', networkConfig.bootnodes.join(','));
|