@aztec/cli 0.0.1-commit.b655e406 → 0.0.1-commit.b8a057fa
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 +1 -1
- package/dest/cmds/aztec_node/block_number.d.ts +1 -1
- package/dest/cmds/aztec_node/block_number.js +1 -1
- package/dest/cmds/aztec_node/get_block.d.ts +1 -1
- package/dest/cmds/aztec_node/get_block.d.ts.map +1 -1
- package/dest/cmds/aztec_node/get_block.js +2 -1
- package/dest/cmds/aztec_node/get_current_min_fee.d.ts +3 -0
- package/dest/cmds/aztec_node/get_current_min_fee.d.ts.map +1 -0
- package/dest/cmds/aztec_node/{get_current_base_fee.js → get_current_min_fee.js} +2 -2
- package/dest/cmds/aztec_node/get_l1_to_l2_message_witness.d.ts +1 -1
- package/dest/cmds/aztec_node/get_logs.d.ts +30 -3
- package/dest/cmds/aztec_node/get_logs.d.ts.map +1 -1
- package/dest/cmds/aztec_node/get_logs.js +39 -29
- package/dest/cmds/aztec_node/get_node_info.d.ts +1 -1
- package/dest/cmds/aztec_node/get_node_info.d.ts.map +1 -1
- package/dest/cmds/aztec_node/get_node_info.js +0 -2
- package/dest/cmds/aztec_node/index.d.ts +1 -1
- package/dest/cmds/aztec_node/index.d.ts.map +1 -1
- package/dest/cmds/aztec_node/index.js +16 -6
- package/dest/cmds/contracts/index.d.ts +1 -1
- package/dest/cmds/contracts/inspect_contract.d.ts +1 -1
- package/dest/cmds/contracts/inspect_contract.d.ts.map +1 -1
- package/dest/cmds/contracts/inspect_contract.js +4 -10
- package/dest/cmds/contracts/parse_parameter_struct.d.ts +1 -1
- package/dest/cmds/infrastructure/index.d.ts +1 -1
- package/dest/cmds/infrastructure/index.d.ts.map +1 -1
- package/dest/cmds/infrastructure/index.js +0 -1
- package/dest/cmds/infrastructure/sequencers.d.ts +1 -2
- package/dest/cmds/infrastructure/sequencers.d.ts.map +1 -1
- package/dest/cmds/infrastructure/sequencers.js +11 -4
- package/dest/cmds/infrastructure/setup_l2_contract.d.ts +1 -1
- package/dest/cmds/infrastructure/setup_l2_contract.d.ts.map +1 -1
- package/dest/cmds/infrastructure/setup_l2_contract.js +12 -7
- package/dest/cmds/l1/advance_epoch.d.ts +1 -1
- package/dest/cmds/l1/assume_proven_through.d.ts +3 -2
- package/dest/cmds/l1/assume_proven_through.d.ts.map +1 -1
- package/dest/cmds/l1/assume_proven_through.js +3 -4
- package/dest/cmds/l1/bridge_erc20.d.ts +1 -1
- package/dest/cmds/l1/bridge_erc20.d.ts.map +1 -1
- package/dest/cmds/l1/bridge_erc20.js +2 -1
- package/dest/cmds/l1/compute_genesis_values.d.ts +4 -0
- package/dest/cmds/l1/compute_genesis_values.d.ts.map +1 -0
- package/dest/cmds/l1/compute_genesis_values.js +17 -0
- package/dest/cmds/l1/create_l1_account.d.ts +1 -1
- package/dest/cmds/l1/deploy_l1_contracts_cmd.d.ts +4 -0
- package/dest/cmds/l1/deploy_l1_contracts_cmd.d.ts.map +1 -0
- package/dest/cmds/l1/{deploy_l1_contracts.js → deploy_l1_contracts_cmd.js} +39 -5
- package/dest/cmds/l1/deploy_new_rollup.d.ts +4 -4
- package/dest/cmds/l1/deploy_new_rollup.d.ts.map +1 -1
- package/dest/cmds/l1/deploy_new_rollup.js +4 -6
- package/dest/cmds/l1/get_l1_addresses.d.ts +1 -1
- package/dest/cmds/l1/get_l1_addresses.d.ts.map +1 -1
- package/dest/cmds/l1/get_l1_addresses.js +5 -2
- package/dest/cmds/l1/get_l1_balance.d.ts +1 -1
- package/dest/cmds/l1/get_l1_balance.js +4 -2
- package/dest/cmds/l1/governance_utils.d.ts +5 -5
- package/dest/cmds/l1/governance_utils.d.ts.map +1 -1
- package/dest/cmds/l1/governance_utils.js +3 -1
- package/dest/cmds/l1/index.d.ts +1 -2
- package/dest/cmds/l1/index.d.ts.map +1 -1
- package/dest/cmds/l1/index.js +17 -10
- package/dest/cmds/l1/prover_stats.d.ts +1 -1
- package/dest/cmds/l1/prover_stats.d.ts.map +1 -1
- package/dest/cmds/l1/prover_stats.js +32 -30
- package/dest/cmds/l1/trigger_seed_snapshot.d.ts +2 -2
- package/dest/cmds/l1/trigger_seed_snapshot.d.ts.map +1 -1
- package/dest/cmds/l1/trigger_seed_snapshot.js +2 -1
- package/dest/cmds/l1/update_l1_validators.d.ts +7 -7
- package/dest/cmds/l1/update_l1_validators.d.ts.map +1 -1
- package/dest/cmds/l1/update_l1_validators.js +58 -20
- package/dest/cmds/misc/compute_selector.d.ts +1 -1
- package/dest/cmds/misc/example_contracts.d.ts +1 -1
- package/dest/cmds/misc/generate_bootnode_enr.d.ts +1 -1
- package/dest/cmds/misc/generate_p2p_private_key.d.ts +1 -1
- package/dest/cmds/misc/generate_secret_and_hash.d.ts +1 -1
- package/dest/cmds/misc/generate_secret_and_hash.js +1 -1
- package/dest/cmds/misc/generate_secret_key.d.ts +1 -1
- package/dest/cmds/misc/get_canonical_sponsored_fpc_address.d.ts +1 -1
- package/dest/cmds/misc/index.d.ts +1 -1
- package/dest/cmds/misc/index.d.ts.map +1 -1
- package/dest/cmds/misc/index.js +1 -1
- package/dest/cmds/misc/update/common.d.ts +1 -1
- package/dest/cmds/misc/update/github.d.ts +1 -1
- package/dest/cmds/misc/update/noir.d.ts +1 -1
- package/dest/cmds/misc/update/npm.d.ts +1 -1
- package/dest/cmds/misc/update/npm.js +1 -1
- package/dest/cmds/misc/update/utils.d.ts +1 -1
- package/dest/cmds/misc/update.d.ts +1 -1
- package/dest/cmds/validator_keys/add.d.ts +1 -1
- package/dest/cmds/validator_keys/add.d.ts.map +1 -1
- package/dest/cmds/validator_keys/add.js +20 -7
- package/dest/cmds/validator_keys/eth_json_v3_worker.d.ts +2 -0
- package/dest/cmds/validator_keys/eth_json_v3_worker.d.ts.map +1 -0
- package/dest/cmds/validator_keys/eth_json_v3_worker.js +27 -0
- package/dest/cmds/validator_keys/generate_bls_keypair.d.ts +1 -1
- package/dest/cmds/validator_keys/generate_bls_keypair.d.ts.map +1 -1
- package/dest/cmds/validator_keys/generate_bls_keypair.js +3 -2
- package/dest/cmds/validator_keys/index.d.ts +1 -1
- package/dest/cmds/validator_keys/index.d.ts.map +1 -1
- package/dest/cmds/validator_keys/index.js +17 -4
- package/dest/cmds/validator_keys/new.d.ts +12 -4
- package/dest/cmds/validator_keys/new.d.ts.map +1 -1
- package/dest/cmds/validator_keys/new.js +163 -19
- package/dest/cmds/validator_keys/shared.d.ts +4 -4
- package/dest/cmds/validator_keys/shared.d.ts.map +1 -1
- package/dest/cmds/validator_keys/shared.js +97 -51
- package/dest/cmds/validator_keys/staker.d.ts +38 -0
- package/dest/cmds/validator_keys/staker.d.ts.map +1 -0
- package/dest/cmds/validator_keys/staker.js +210 -0
- 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/cached_fetch.d.ts +19 -10
- package/dest/config/cached_fetch.d.ts.map +1 -1
- package/dest/config/cached_fetch.js +110 -32
- package/dest/config/chain_l2_config.d.ts +18 -38
- package/dest/config/chain_l2_config.d.ts.map +1 -1
- package/dest/config/chain_l2_config.js +48 -463
- package/dest/config/enrich_env.d.ts +1 -1
- package/dest/config/generated/networks.d.ts +239 -0
- package/dest/config/generated/networks.d.ts.map +1 -0
- package/dest/config/generated/networks.js +240 -0
- package/dest/config/get_l1_config.d.ts +3 -2
- package/dest/config/get_l1_config.d.ts.map +1 -1
- package/dest/config/get_l1_config.js +3 -1
- package/dest/config/index.d.ts +1 -1
- package/dest/config/network_config.d.ts +7 -4
- package/dest/config/network_config.d.ts.map +1 -1
- package/dest/config/network_config.js +70 -30
- package/dest/utils/aztec.d.ts +7 -14
- package/dest/utils/aztec.d.ts.map +1 -1
- package/dest/utils/aztec.js +19 -41
- package/dest/utils/commands.d.ts +20 -11
- package/dest/utils/commands.d.ts.map +1 -1
- package/dest/utils/commands.js +26 -15
- package/dest/utils/encoding.d.ts +1 -1
- package/dest/utils/encoding.js +1 -1
- package/dest/utils/github.d.ts +1 -1
- package/dest/utils/index.d.ts +1 -1
- package/dest/utils/inspect.d.ts +3 -2
- package/dest/utils/inspect.d.ts.map +1 -1
- package/dest/utils/inspect.js +15 -12
- package/dest/utils/setup_contracts.d.ts +1 -1
- package/package.json +44 -31
- package/public_include_metric_prefixes.json +1 -0
- package/src/cmds/aztec_node/block_number.ts +1 -1
- package/src/cmds/aztec_node/get_block.ts +2 -1
- package/src/cmds/aztec_node/{get_current_base_fee.ts → get_current_min_fee.ts} +2 -2
- package/src/cmds/aztec_node/get_logs.ts +70 -37
- package/src/cmds/aztec_node/get_node_info.ts +0 -2
- package/src/cmds/aztec_node/index.ts +16 -11
- package/src/cmds/contracts/inspect_contract.ts +4 -11
- package/src/cmds/infrastructure/index.ts +0 -1
- package/src/cmds/infrastructure/sequencers.ts +7 -5
- package/src/cmds/infrastructure/setup_l2_contract.ts +12 -7
- package/src/cmds/l1/assume_proven_through.ts +4 -4
- package/src/cmds/l1/bridge_erc20.ts +2 -1
- package/src/cmds/l1/compute_genesis_values.ts +29 -0
- package/src/cmds/l1/{deploy_l1_contracts.ts → deploy_l1_contracts_cmd.ts} +39 -23
- package/src/cmds/l1/deploy_new_rollup.ts +5 -12
- package/src/cmds/l1/get_l1_addresses.ts +4 -2
- package/src/cmds/l1/get_l1_balance.ts +2 -2
- package/src/cmds/l1/governance_utils.ts +3 -8
- package/src/cmds/l1/index.ts +30 -21
- package/src/cmds/l1/prover_stats.ts +42 -31
- package/src/cmds/l1/trigger_seed_snapshot.ts +2 -1
- package/src/cmds/l1/update_l1_validators.ts +52 -32
- package/src/cmds/misc/generate_secret_and_hash.ts +1 -1
- package/src/cmds/misc/index.ts +1 -1
- package/src/cmds/misc/update/npm.ts +1 -1
- package/src/cmds/validator_keys/add.ts +20 -10
- package/src/cmds/validator_keys/eth_json_v3_worker.ts +30 -0
- package/src/cmds/validator_keys/generate_bls_keypair.ts +3 -2
- package/src/cmds/validator_keys/index.ts +85 -25
- package/src/cmds/validator_keys/new.ts +211 -25
- package/src/cmds/validator_keys/shared.ts +117 -60
- package/src/cmds/validator_keys/staker.ts +301 -0
- package/src/cmds/validator_keys/utils.ts +81 -0
- package/src/config/cached_fetch.ts +119 -31
- package/src/config/chain_l2_config.ts +47 -602
- package/src/config/generated/networks.ts +244 -0
- package/src/config/get_l1_config.ts +4 -1
- package/src/config/network_config.ts +80 -31
- package/src/utils/aztec.ts +30 -95
- package/src/utils/commands.ts +29 -15
- package/src/utils/encoding.ts +1 -1
- package/src/utils/inspect.ts +13 -10
- package/dest/cmds/aztec_node/get_current_base_fee.d.ts +0 -3
- package/dest/cmds/aztec_node/get_current_base_fee.d.ts.map +0 -1
- package/dest/cmds/l1/deploy_l1_contracts.d.ts +0 -4
- package/dest/cmds/l1/deploy_l1_contracts.d.ts.map +0 -1
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
import { prettyPrintJSON } from '@aztec/cli/utils';
|
|
2
|
+
import { createEthereumChain } from '@aztec/ethereum/chain';
|
|
3
|
+
import { GSEContract } from '@aztec/ethereum/contracts';
|
|
1
4
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
2
5
|
import type { LogFn } from '@aztec/foundation/log';
|
|
3
6
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
4
7
|
|
|
5
8
|
import { wordlist } from '@scure/bip39/wordlists/english.js';
|
|
6
|
-
import {
|
|
9
|
+
import { readFile, writeFile } from 'fs/promises';
|
|
10
|
+
import { basename, dirname, join } from 'path';
|
|
11
|
+
import { createPublicClient, fallback, http } from 'viem';
|
|
7
12
|
import { generateMnemonic, mnemonicToAccount } from 'viem/accounts';
|
|
8
13
|
|
|
9
14
|
import {
|
|
@@ -15,12 +20,20 @@ import {
|
|
|
15
20
|
writeEthJsonV3ToFile,
|
|
16
21
|
writeKeystoreFile,
|
|
17
22
|
} from './shared.js';
|
|
23
|
+
import { processAttesterAccounts } from './staker.js';
|
|
24
|
+
import {
|
|
25
|
+
validateBlsPathOptions,
|
|
26
|
+
validatePublisherOptions,
|
|
27
|
+
validateRemoteSignerOptions,
|
|
28
|
+
validateStakerOutputOptions,
|
|
29
|
+
} from './utils.js';
|
|
18
30
|
|
|
19
31
|
export type NewValidatorKeystoreOptions = {
|
|
20
32
|
dataDir?: string;
|
|
21
33
|
file?: string;
|
|
22
34
|
count?: number;
|
|
23
35
|
publisherCount?: number;
|
|
36
|
+
publishers?: string[];
|
|
24
37
|
mnemonic?: string;
|
|
25
38
|
passphrase?: string;
|
|
26
39
|
accountIndex?: number;
|
|
@@ -28,68 +41,184 @@ export type NewValidatorKeystoreOptions = {
|
|
|
28
41
|
separatePublisher?: boolean;
|
|
29
42
|
ikm?: string;
|
|
30
43
|
blsPath?: string;
|
|
31
|
-
blsOnly?: boolean;
|
|
32
44
|
password?: string;
|
|
33
|
-
|
|
45
|
+
passwordFile?: string;
|
|
46
|
+
ethPassword?: string;
|
|
47
|
+
ethPasswordFile?: string;
|
|
48
|
+
blsPassword?: string;
|
|
49
|
+
blsPasswordFile?: string;
|
|
50
|
+
encryptedKeystoreDir?: string;
|
|
34
51
|
json?: boolean;
|
|
35
52
|
feeRecipient: AztecAddress;
|
|
36
53
|
coinbase?: EthAddress;
|
|
37
54
|
remoteSigner?: string;
|
|
38
|
-
|
|
55
|
+
stakerOutput?: boolean;
|
|
56
|
+
gseAddress?: EthAddress;
|
|
57
|
+
l1RpcUrls?: string[];
|
|
58
|
+
l1ChainId?: number;
|
|
39
59
|
};
|
|
40
60
|
|
|
61
|
+
type PasswordSourceOptions = Pick<
|
|
62
|
+
NewValidatorKeystoreOptions,
|
|
63
|
+
'password' | 'passwordFile' | 'ethPassword' | 'ethPasswordFile' | 'blsPassword' | 'blsPasswordFile'
|
|
64
|
+
>;
|
|
65
|
+
|
|
66
|
+
type PasswordSource = {
|
|
67
|
+
password?: string;
|
|
68
|
+
passwordFile?: string;
|
|
69
|
+
passwordOption: string;
|
|
70
|
+
passwordFileOption: string;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
function validatePassword(password: string, source: string): string {
|
|
74
|
+
if (password.length === 0) {
|
|
75
|
+
throw new Error(`${source} cannot be empty`);
|
|
76
|
+
}
|
|
77
|
+
return password;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function stripOneTrailingNewline(password: string): string {
|
|
81
|
+
if (password.endsWith('\n')) {
|
|
82
|
+
password = password.slice(0, -1);
|
|
83
|
+
}
|
|
84
|
+
if (password.endsWith('\r')) {
|
|
85
|
+
password = password.slice(0, -1);
|
|
86
|
+
}
|
|
87
|
+
return password;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function resolvePasswordSource(source: PasswordSource): Promise<string | undefined> {
|
|
91
|
+
if (source.password !== undefined && source.passwordFile !== undefined) {
|
|
92
|
+
throw new Error(`${source.passwordOption} and ${source.passwordFileOption} cannot be used together`);
|
|
93
|
+
}
|
|
94
|
+
if (source.password !== undefined) {
|
|
95
|
+
return validatePassword(source.password, source.passwordOption);
|
|
96
|
+
}
|
|
97
|
+
if (source.passwordFile !== undefined) {
|
|
98
|
+
if (source.passwordFile.length === 0) {
|
|
99
|
+
throw new Error(`${source.passwordFileOption} cannot be empty`);
|
|
100
|
+
}
|
|
101
|
+
const password = stripOneTrailingNewline(await readFile(source.passwordFile, 'utf-8'));
|
|
102
|
+
return validatePassword(password, source.passwordFileOption);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function resolvePasswords(options: PasswordSourceOptions) {
|
|
109
|
+
const sharedPassword = await resolvePasswordSource({
|
|
110
|
+
password: options.password,
|
|
111
|
+
passwordFile: options.passwordFile,
|
|
112
|
+
passwordOption: '--password',
|
|
113
|
+
passwordFileOption: '--password-file',
|
|
114
|
+
});
|
|
115
|
+
const ethPassword =
|
|
116
|
+
(await resolvePasswordSource({
|
|
117
|
+
password: options.ethPassword,
|
|
118
|
+
passwordFile: options.ethPasswordFile,
|
|
119
|
+
passwordOption: '--eth-password',
|
|
120
|
+
passwordFileOption: '--eth-password-file',
|
|
121
|
+
})) ?? sharedPassword;
|
|
122
|
+
const blsPassword =
|
|
123
|
+
(await resolvePasswordSource({
|
|
124
|
+
password: options.blsPassword,
|
|
125
|
+
passwordFile: options.blsPasswordFile,
|
|
126
|
+
passwordOption: '--bls-password',
|
|
127
|
+
passwordFileOption: '--bls-password-file',
|
|
128
|
+
})) ?? sharedPassword;
|
|
129
|
+
|
|
130
|
+
if (ethPassword === undefined && blsPassword === undefined) {
|
|
131
|
+
return {};
|
|
132
|
+
}
|
|
133
|
+
if (ethPassword === undefined || blsPassword === undefined) {
|
|
134
|
+
throw new Error(
|
|
135
|
+
'Both ETH and BLS passwords are required when writing encrypted keystores. Provide --password to use one password for both, or provide both --eth-password and --bls-password.',
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
return { ethPassword, blsPassword };
|
|
139
|
+
}
|
|
140
|
+
|
|
41
141
|
export async function newValidatorKeystore(options: NewValidatorKeystoreOptions, log: LogFn) {
|
|
142
|
+
// validate bls-path inputs before proceeding with key generation
|
|
143
|
+
validateBlsPathOptions(options);
|
|
144
|
+
// validate staker output options before proceeding with key generation
|
|
145
|
+
validateStakerOutputOptions(options);
|
|
146
|
+
// validate publisher options
|
|
147
|
+
validatePublisherOptions(options);
|
|
148
|
+
// validate remote signer options
|
|
149
|
+
validateRemoteSignerOptions(options);
|
|
150
|
+
|
|
42
151
|
const {
|
|
43
152
|
dataDir,
|
|
44
153
|
file,
|
|
45
154
|
count,
|
|
46
155
|
publisherCount = 0,
|
|
156
|
+
publishers,
|
|
47
157
|
json,
|
|
48
158
|
coinbase,
|
|
49
159
|
accountIndex = 0,
|
|
50
160
|
addressIndex = 0,
|
|
51
161
|
feeRecipient,
|
|
52
162
|
remoteSigner,
|
|
53
|
-
fundingAccount,
|
|
54
|
-
blsOnly,
|
|
55
163
|
blsPath,
|
|
56
164
|
ikm,
|
|
57
165
|
mnemonic: _mnemonic,
|
|
58
|
-
password,
|
|
59
|
-
|
|
166
|
+
password: passwordOption,
|
|
167
|
+
passwordFile,
|
|
168
|
+
ethPassword: ethPasswordOption,
|
|
169
|
+
ethPasswordFile,
|
|
170
|
+
blsPassword: blsPasswordOption,
|
|
171
|
+
blsPasswordFile,
|
|
172
|
+
encryptedKeystoreDir,
|
|
173
|
+
stakerOutput,
|
|
174
|
+
gseAddress,
|
|
175
|
+
l1RpcUrls,
|
|
176
|
+
l1ChainId,
|
|
60
177
|
} = options;
|
|
61
178
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
179
|
+
const { ethPassword, blsPassword } = await resolvePasswords({
|
|
180
|
+
password: passwordOption,
|
|
181
|
+
passwordFile,
|
|
182
|
+
ethPassword: ethPasswordOption,
|
|
183
|
+
ethPasswordFile,
|
|
184
|
+
blsPassword: blsPasswordOption,
|
|
185
|
+
blsPasswordFile,
|
|
186
|
+
});
|
|
187
|
+
const shouldEncryptKeystores = ethPassword !== undefined && blsPassword !== undefined;
|
|
68
188
|
const mnemonic = _mnemonic ?? generateMnemonic(wordlist);
|
|
69
189
|
|
|
190
|
+
if (!_mnemonic && !json && !shouldEncryptKeystores) {
|
|
191
|
+
log('No mnemonic provided, generating new one...');
|
|
192
|
+
log(`Using new mnemonic:`);
|
|
193
|
+
log('');
|
|
194
|
+
log(mnemonic);
|
|
195
|
+
log('');
|
|
196
|
+
}
|
|
197
|
+
|
|
70
198
|
const validatorCount = typeof count === 'number' && Number.isFinite(count) && count > 0 ? Math.floor(count) : 1;
|
|
71
199
|
const { outputPath } = await resolveKeystoreOutputPath(dataDir, file);
|
|
200
|
+
const keystoreOutDir = dirname(outputPath);
|
|
72
201
|
|
|
73
202
|
const { validators, summaries } = await buildValidatorEntries({
|
|
74
203
|
validatorCount,
|
|
75
204
|
publisherCount,
|
|
205
|
+
publishers,
|
|
76
206
|
accountIndex,
|
|
77
207
|
baseAddressIndex: addressIndex,
|
|
78
208
|
mnemonic,
|
|
79
209
|
ikm,
|
|
80
210
|
blsPath,
|
|
81
|
-
blsOnly,
|
|
82
211
|
feeRecipient,
|
|
83
212
|
coinbase,
|
|
84
213
|
remoteSigner,
|
|
85
|
-
fundingAccount,
|
|
86
214
|
});
|
|
87
215
|
|
|
88
216
|
// If password provided, write ETH JSON V3 and BLS BN254 keystores and replace plaintext
|
|
89
|
-
if (
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
await
|
|
217
|
+
if (shouldEncryptKeystores) {
|
|
218
|
+
const encryptedKeystoreOutDir =
|
|
219
|
+
encryptedKeystoreDir && encryptedKeystoreDir.length > 0 ? encryptedKeystoreDir : keystoreOutDir;
|
|
220
|
+
await writeEthJsonV3ToFile(validators, { outDir: encryptedKeystoreOutDir, password: ethPassword });
|
|
221
|
+
await writeBlsBn254ToFile(validators, { outDir: encryptedKeystoreOutDir, password: blsPassword });
|
|
93
222
|
}
|
|
94
223
|
|
|
95
224
|
const keystore = {
|
|
@@ -99,15 +228,66 @@ export async function newValidatorKeystore(options: NewValidatorKeystoreOptions,
|
|
|
99
228
|
|
|
100
229
|
await writeKeystoreFile(outputPath, keystore);
|
|
101
230
|
|
|
102
|
-
|
|
103
|
-
|
|
231
|
+
// Generate staker outputs if requested
|
|
232
|
+
const allStakerOutputs: any[] = [];
|
|
233
|
+
if (stakerOutput && gseAddress && l1RpcUrls && l1ChainId !== undefined) {
|
|
234
|
+
const chain = createEthereumChain(l1RpcUrls, l1ChainId);
|
|
235
|
+
const publicClient = createPublicClient({
|
|
236
|
+
chain: chain.chainInfo,
|
|
237
|
+
transport: fallback(l1RpcUrls.map(url => http(url, { batch: false }))),
|
|
238
|
+
});
|
|
239
|
+
const gse = new GSEContract(publicClient, gseAddress);
|
|
240
|
+
|
|
241
|
+
// Extract keystore base name without extension for unique staker output filenames
|
|
242
|
+
const keystoreBaseName = basename(outputPath, '.json');
|
|
243
|
+
|
|
244
|
+
// Process each validator
|
|
245
|
+
for (let i = 0; i < validators.length; i++) {
|
|
246
|
+
const validator = validators[i];
|
|
247
|
+
const outputs = await processAttesterAccounts(validator.attester, gse);
|
|
248
|
+
|
|
249
|
+
// Collect all staker outputs
|
|
250
|
+
for (let j = 0; j < outputs.length; j++) {
|
|
251
|
+
allStakerOutputs.push(outputs[j]);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Write a single JSON file with all staker outputs
|
|
256
|
+
if (allStakerOutputs.length > 0) {
|
|
257
|
+
const stakerOutputPath = join(keystoreOutDir, `${keystoreBaseName}_staker_output.json`);
|
|
258
|
+
await writeFile(stakerOutputPath, prettyPrintJSON(allStakerOutputs), 'utf-8');
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const outputData = !_mnemonic && !shouldEncryptKeystores ? { ...keystore, generatedMnemonic: mnemonic } : keystore;
|
|
263
|
+
|
|
264
|
+
// Handle JSON output
|
|
265
|
+
if (json) {
|
|
266
|
+
if (stakerOutput && allStakerOutputs.length > 0) {
|
|
267
|
+
const combinedOutput = {
|
|
268
|
+
keystore: outputData,
|
|
269
|
+
staker: allStakerOutputs,
|
|
270
|
+
};
|
|
271
|
+
maybePrintJson(log, json, combinedOutput as unknown as Record<string, any>);
|
|
272
|
+
} else {
|
|
273
|
+
maybePrintJson(log, json, outputData as unknown as Record<string, any>);
|
|
274
|
+
}
|
|
275
|
+
} else {
|
|
104
276
|
log(`Wrote validator keystore to ${outputPath}`);
|
|
277
|
+
if (stakerOutput && allStakerOutputs.length > 0) {
|
|
278
|
+
const keystoreBaseName = basename(outputPath, '.json');
|
|
279
|
+
const stakerOutputPath = join(keystoreOutDir, `${keystoreBaseName}_staker_output.json`);
|
|
280
|
+
log(`Wrote staker output for ${allStakerOutputs.length} validator(s) to ${stakerOutputPath}`);
|
|
281
|
+
log('');
|
|
282
|
+
}
|
|
105
283
|
}
|
|
106
284
|
|
|
107
|
-
//
|
|
108
|
-
|
|
285
|
+
// print a concise summary of public keys (addresses and BLS pubkeys) if no --json options was selected
|
|
286
|
+
if (!json) {
|
|
287
|
+
logValidatorSummaries(log, summaries);
|
|
288
|
+
}
|
|
109
289
|
|
|
110
|
-
if (
|
|
290
|
+
if (mnemonic && remoteSigner && !json) {
|
|
111
291
|
for (let i = 0; i < validatorCount; i++) {
|
|
112
292
|
const addrIdx = addressIndex + i;
|
|
113
293
|
const acct = mnemonicToAccount(mnemonic, {
|
|
@@ -117,4 +297,10 @@ export async function newValidatorKeystore(options: NewValidatorKeystoreOptions,
|
|
|
117
297
|
log(`attester address: ${acct.address} remoteSignerUrl: ${remoteSigner}`);
|
|
118
298
|
}
|
|
119
299
|
}
|
|
300
|
+
|
|
301
|
+
// Log staker outputs if not in JSON mode
|
|
302
|
+
if (!json && stakerOutput && allStakerOutputs.length > 0) {
|
|
303
|
+
log('\nStaker outputs:');
|
|
304
|
+
log(prettyPrintJSON(allStakerOutputs));
|
|
305
|
+
}
|
|
120
306
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { prettyPrintJSON } from '@aztec/cli/utils';
|
|
2
|
-
import {
|
|
2
|
+
import { asyncPool } from '@aztec/foundation/async-pool';
|
|
3
|
+
import { deriveBlsPrivateKey } from '@aztec/foundation/crypto/bls';
|
|
3
4
|
import { createBn254Keystore } from '@aztec/foundation/crypto/bls/bn254_keystore';
|
|
5
|
+
import { computeBn254G1PublicKeyCompressed } from '@aztec/foundation/crypto/bn254';
|
|
4
6
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
5
7
|
import type { LogFn } from '@aztec/foundation/log';
|
|
6
8
|
import type { EthAccount, EthPrivateKey, ValidatorKeyStore } from '@aztec/node-keystore/types';
|
|
@@ -9,31 +11,94 @@ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
|
9
11
|
import { Wallet } from '@ethersproject/wallet';
|
|
10
12
|
import { constants as fsConstants, mkdirSync } from 'fs';
|
|
11
13
|
import { access, writeFile } from 'fs/promises';
|
|
12
|
-
import { homedir } from 'os';
|
|
14
|
+
import { availableParallelism, homedir } from 'os';
|
|
13
15
|
import { dirname, isAbsolute, join } from 'path';
|
|
14
16
|
import { mnemonicToAccount } from 'viem/accounts';
|
|
17
|
+
import { Worker } from 'worker_threads';
|
|
18
|
+
|
|
19
|
+
import { defaultBlsPath } from './utils.js';
|
|
20
|
+
|
|
21
|
+
type EthJsonV3WorkerResult = { json: string } | { error: { message: string; name?: string; stack?: string } };
|
|
22
|
+
|
|
23
|
+
// ethers' default scrypt parameters use substantial memory, so keep worker fan-out bounded.
|
|
24
|
+
const maxEthKeystoreWorkers = Math.max(1, Math.min(4, availableParallelism()));
|
|
25
|
+
|
|
26
|
+
function deserializeWorkerError(error: { message: string; name?: string; stack?: string }) {
|
|
27
|
+
const result = new Error(error.message);
|
|
28
|
+
result.name = error.name ?? result.name;
|
|
29
|
+
result.stack = error.stack;
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function encryptEthJsonV3InWorker(privateKeyHex: string, password: string): Promise<string> {
|
|
34
|
+
return new Promise<string>((resolve, reject) => {
|
|
35
|
+
const worker = new Worker(new URL('./eth_json_v3_worker.js', import.meta.url), {
|
|
36
|
+
workerData: { privateKeyHex, password },
|
|
37
|
+
});
|
|
38
|
+
let settled = false;
|
|
39
|
+
|
|
40
|
+
worker.once('message', (result: EthJsonV3WorkerResult) => {
|
|
41
|
+
settled = true;
|
|
42
|
+
|
|
43
|
+
if ('json' in result) {
|
|
44
|
+
resolve(result.json);
|
|
45
|
+
} else {
|
|
46
|
+
reject(deserializeWorkerError(result.error));
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
worker.once('error', error => {
|
|
50
|
+
settled = true;
|
|
51
|
+
reject(error);
|
|
52
|
+
});
|
|
53
|
+
worker.once('exit', code => {
|
|
54
|
+
if (!settled) {
|
|
55
|
+
reject(new Error(`ETH JSON V3 worker stopped with exit code ${code}`));
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function encryptEthJsonV3(privateKeyHex: string, password: string): Promise<string> {
|
|
62
|
+
if (process.env.JEST_WORKER_ID !== undefined) {
|
|
63
|
+
return await new Wallet(privateKeyHex).encrypt(password);
|
|
64
|
+
}
|
|
65
|
+
return await encryptEthJsonV3InWorker(privateKeyHex, password);
|
|
66
|
+
}
|
|
15
67
|
|
|
16
68
|
export type ValidatorSummary = { attesterEth?: string; attesterBls?: string; publisherEth?: string[] };
|
|
17
69
|
|
|
18
70
|
export type BuildValidatorsInput = {
|
|
19
71
|
validatorCount: number;
|
|
20
72
|
publisherCount?: number;
|
|
73
|
+
publishers?: string[];
|
|
21
74
|
accountIndex: number;
|
|
22
75
|
baseAddressIndex: number;
|
|
23
76
|
mnemonic: string;
|
|
24
77
|
ikm?: string;
|
|
25
78
|
blsPath?: string;
|
|
26
|
-
blsOnly?: boolean;
|
|
27
79
|
feeRecipient: AztecAddress;
|
|
28
80
|
coinbase?: EthAddress;
|
|
29
81
|
remoteSigner?: string;
|
|
30
|
-
fundingAccount?: EthAddress;
|
|
31
82
|
};
|
|
32
83
|
|
|
33
|
-
export function withValidatorIndex(path: string,
|
|
84
|
+
export function withValidatorIndex(path: string, accountIndex: number = 0, addressIndex: number = 0) {
|
|
85
|
+
// NOTE: The legacy BLS CLI is to allow users who generated keys in 2.1.4 to be able to use the same command
|
|
86
|
+
// 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.
|
|
87
|
+
const useLegacyBlsCli = ['true', '1', 'yes', 'y'].includes(process.env.LEGACY_BLS_CLI ?? '');
|
|
88
|
+
|
|
89
|
+
const defaultBlsPathParts = defaultBlsPath.split('/');
|
|
90
|
+
|
|
34
91
|
const parts = path.split('/');
|
|
35
|
-
if (parts.length
|
|
36
|
-
|
|
92
|
+
if (parts.length == defaultBlsPathParts.length && parts.every((part, index) => part === defaultBlsPathParts[index])) {
|
|
93
|
+
if (useLegacyBlsCli) {
|
|
94
|
+
// In 2.1.4, we were using address-index in parts[3] and did NOT use account-index, check lines 32 & 84
|
|
95
|
+
// https://github.com/AztecProtocol/aztec-packages/blob/v2.1.4/yarn-project/cli/src/cmds/validator_keys/shared.ts
|
|
96
|
+
|
|
97
|
+
parts[3] = String(addressIndex);
|
|
98
|
+
} else {
|
|
99
|
+
parts[3] = String(accountIndex);
|
|
100
|
+
parts[5] = String(addressIndex);
|
|
101
|
+
}
|
|
37
102
|
return parts.join('/');
|
|
38
103
|
}
|
|
39
104
|
return path;
|
|
@@ -64,42 +129,37 @@ export async function buildValidatorEntries(input: BuildValidatorsInput) {
|
|
|
64
129
|
const {
|
|
65
130
|
validatorCount,
|
|
66
131
|
publisherCount = 0,
|
|
132
|
+
publishers,
|
|
67
133
|
accountIndex,
|
|
68
134
|
baseAddressIndex,
|
|
69
135
|
mnemonic,
|
|
70
136
|
ikm,
|
|
71
137
|
blsPath,
|
|
72
|
-
blsOnly,
|
|
73
138
|
feeRecipient,
|
|
74
139
|
coinbase,
|
|
75
140
|
remoteSigner,
|
|
76
|
-
fundingAccount,
|
|
77
141
|
} = input;
|
|
78
142
|
|
|
79
|
-
const defaultBlsPath = 'm/12381/3600/0/0/0';
|
|
80
143
|
const summaries: ValidatorSummary[] = [];
|
|
81
144
|
|
|
82
145
|
const validators = await Promise.all(
|
|
83
146
|
Array.from({ length: validatorCount }, async (_unused, i) => {
|
|
84
147
|
const addressIndex = baseAddressIndex + i;
|
|
85
148
|
const basePath = blsPath ?? defaultBlsPath;
|
|
86
|
-
const perValidatorPath = withValidatorIndex(basePath, addressIndex);
|
|
149
|
+
const perValidatorPath = withValidatorIndex(basePath, accountIndex, addressIndex);
|
|
87
150
|
|
|
88
|
-
const blsPrivKey =
|
|
151
|
+
const blsPrivKey = ikm || mnemonic ? deriveBlsPrivateKey(mnemonic, ikm, perValidatorPath) : undefined;
|
|
89
152
|
const blsPubCompressed = blsPrivKey ? await computeBlsPublicKeyCompressed(blsPrivKey) : undefined;
|
|
90
153
|
|
|
91
|
-
if (blsOnly) {
|
|
92
|
-
const attester = { bls: blsPrivKey! };
|
|
93
|
-
summaries.push({ attesterBls: blsPubCompressed });
|
|
94
|
-
return { attester, feeRecipient } as ValidatorKeyStore;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
154
|
const ethAttester = deriveEthAttester(mnemonic, accountIndex, addressIndex, remoteSigner);
|
|
98
155
|
const attester = blsPrivKey ? { eth: ethAttester, bls: blsPrivKey } : ethAttester;
|
|
99
156
|
|
|
100
157
|
let publisherField: EthAccount | EthPrivateKey | (EthAccount | EthPrivateKey)[] | undefined;
|
|
101
158
|
const publisherAddresses: string[] = [];
|
|
102
|
-
if (
|
|
159
|
+
if (publishers && publishers.length > 0) {
|
|
160
|
+
publisherAddresses.push(...publishers);
|
|
161
|
+
publisherField = publishers.length === 1 ? (publishers[0] as EthPrivateKey) : (publishers as EthPrivateKey[]);
|
|
162
|
+
} else if (publisherCount > 0) {
|
|
103
163
|
const publishersBaseIndex = baseAddressIndex + validatorCount + i * publisherCount;
|
|
104
164
|
const publisherAccounts = Array.from({ length: publisherCount }, (_unused2, j) => {
|
|
105
165
|
const publisherAddressIndex = publishersBaseIndex + j;
|
|
@@ -130,8 +190,7 @@ export async function buildValidatorEntries(input: BuildValidatorsInput) {
|
|
|
130
190
|
attester,
|
|
131
191
|
...(publisherField !== undefined ? { publisher: publisherField } : {}),
|
|
132
192
|
feeRecipient,
|
|
133
|
-
coinbase,
|
|
134
|
-
fundingAccount,
|
|
193
|
+
coinbase: coinbase ?? attesterEthAddress,
|
|
135
194
|
} as ValidatorKeyStore;
|
|
136
195
|
}),
|
|
137
196
|
);
|
|
@@ -218,7 +277,7 @@ export async function writeBn254BlsKeystore(
|
|
|
218
277
|
): Promise<string> {
|
|
219
278
|
mkdirSync(outDir, { recursive: true });
|
|
220
279
|
|
|
221
|
-
const keystore = createBn254Keystore(password, privateKeyHex, pubkeyHex, derivationPath);
|
|
280
|
+
const keystore = await createBn254Keystore(password, privateKeyHex, pubkeyHex, derivationPath);
|
|
222
281
|
|
|
223
282
|
const safeBase = fileNameBase.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
224
283
|
const outPath = join(outDir, `keystore-${safeBase}.json`);
|
|
@@ -229,30 +288,31 @@ export async function writeBn254BlsKeystore(
|
|
|
229
288
|
/** Replace plaintext BLS keys in validators with { path, password } pointing to BN254 keystore files. */
|
|
230
289
|
export async function writeBlsBn254ToFile(
|
|
231
290
|
validators: ValidatorKeyStore[],
|
|
232
|
-
options: { outDir: string; password: string },
|
|
291
|
+
options: { outDir: string; password: string; blsPath?: string },
|
|
233
292
|
): Promise<void> {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
293
|
+
await Promise.all(
|
|
294
|
+
validators.map(async (v, i) => {
|
|
295
|
+
if (!v || typeof v !== 'object' || !('attester' in v)) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const att = (v as any).attester;
|
|
240
299
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
300
|
+
// Shapes: { bls: <hex> } or { eth: <ethAccount>, bls?: <hex> } or plain EthAccount
|
|
301
|
+
const blsKey: string | undefined = typeof att === 'object' && 'bls' in att ? (att as any).bls : undefined;
|
|
302
|
+
if (!blsKey || typeof blsKey !== 'string') {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
246
305
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
306
|
+
const pub = await computeBlsPublicKeyCompressed(blsKey);
|
|
307
|
+
const path = options.blsPath ?? defaultBlsPath;
|
|
308
|
+
const fileBase = `${String(i + 1)}_${pub.slice(2, 18)}`;
|
|
309
|
+
const keystorePath = await writeBn254BlsKeystore(options.outDir, fileBase, options.password, blsKey, pub, path);
|
|
251
310
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
311
|
+
if (typeof att === 'object') {
|
|
312
|
+
(att as any).bls = { path: keystorePath, password: options.password };
|
|
313
|
+
}
|
|
314
|
+
}),
|
|
315
|
+
);
|
|
256
316
|
}
|
|
257
317
|
|
|
258
318
|
/** Writes an Ethereum JSON V3 keystore using ethers, returns absolute path */
|
|
@@ -264,8 +324,7 @@ export async function writeEthJsonV3Keystore(
|
|
|
264
324
|
): Promise<string> {
|
|
265
325
|
const safeBase = fileNameBase.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
266
326
|
mkdirSync(outDir, { recursive: true });
|
|
267
|
-
const
|
|
268
|
-
const json = await wallet.encrypt(password);
|
|
327
|
+
const json = await encryptEthJsonV3(privateKeyHex, password);
|
|
269
328
|
const outPath = join(outDir, `keystore-eth-${safeBase}.json`);
|
|
270
329
|
await writeFile(outPath, json, { encoding: 'utf-8' });
|
|
271
330
|
return outPath;
|
|
@@ -276,13 +335,16 @@ export async function writeEthJsonV3ToFile(
|
|
|
276
335
|
validators: ValidatorKeyStore[],
|
|
277
336
|
options: { outDir: string; password: string },
|
|
278
337
|
): Promise<void> {
|
|
279
|
-
const
|
|
338
|
+
const tasks: (() => Promise<void>)[] = [];
|
|
339
|
+
|
|
340
|
+
const maybeQueueEncryptEth = (account: any, label: string, setEncryptedAccount: (account: any) => void) => {
|
|
280
341
|
if (typeof account === 'string' && account.startsWith('0x') && account.length === 66) {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
342
|
+
tasks.push(async () => {
|
|
343
|
+
const fileBase = `${label}_${account.slice(2, 10)}`;
|
|
344
|
+
const path = await writeEthJsonV3Keystore(options.outDir, fileBase, options.password, account);
|
|
345
|
+
setEncryptedAccount({ path, password: options.password });
|
|
346
|
+
});
|
|
284
347
|
}
|
|
285
|
-
return account;
|
|
286
348
|
};
|
|
287
349
|
|
|
288
350
|
for (let i = 0; i < validators.length; i++) {
|
|
@@ -294,28 +356,23 @@ export async function writeEthJsonV3ToFile(
|
|
|
294
356
|
// attester may be string (eth), object with eth, or remote signer
|
|
295
357
|
const att = (v as any).attester;
|
|
296
358
|
if (typeof att === 'string') {
|
|
297
|
-
(
|
|
359
|
+
maybeQueueEncryptEth(att, `attester_${i + 1}`, account => ((v as any).attester = account));
|
|
298
360
|
} else if (att && typeof att === 'object' && 'eth' in att) {
|
|
299
|
-
(att as any).eth
|
|
361
|
+
maybeQueueEncryptEth((att as any).eth, `attester_${i + 1}`, account => ((att as any).eth = account));
|
|
300
362
|
}
|
|
301
363
|
|
|
302
364
|
// publisher can be single or array
|
|
303
365
|
if ('publisher' in v) {
|
|
304
366
|
const pub = (v as any).publisher;
|
|
305
367
|
if (Array.isArray(pub)) {
|
|
306
|
-
const out: any[] = [];
|
|
307
368
|
for (let j = 0; j < pub.length; j++) {
|
|
308
|
-
|
|
369
|
+
maybeQueueEncryptEth(pub[j], `publisher_${i + 1}_${j + 1}`, account => (pub[j] = account));
|
|
309
370
|
}
|
|
310
|
-
(v as any).publisher = out;
|
|
311
371
|
} else if (pub !== undefined) {
|
|
312
|
-
(
|
|
372
|
+
maybeQueueEncryptEth(pub, `publisher_${i + 1}`, account => ((v as any).publisher = account));
|
|
313
373
|
}
|
|
314
374
|
}
|
|
315
|
-
|
|
316
|
-
// Optional fundingAccount within validator
|
|
317
|
-
if ('fundingAccount' in v) {
|
|
318
|
-
(v as any).fundingAccount = await maybeEncryptEth((v as any).fundingAccount, `funding_${i + 1}`);
|
|
319
|
-
}
|
|
320
375
|
}
|
|
376
|
+
|
|
377
|
+
await asyncPool(maxEthKeystoreWorkers, tasks, task => task());
|
|
321
378
|
}
|