@aztec-labs/cli 6.0.0-rc.3 → 6.0.0-rc.4
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/infrastructure/index.d.ts +1 -1
- package/dest/cmds/infrastructure/index.d.ts.map +1 -1
- package/dest/cmds/infrastructure/index.js +3 -2
- package/dest/cmds/infrastructure/sequencers.d.ts +4 -1
- package/dest/cmds/infrastructure/sequencers.d.ts.map +1 -1
- package/dest/cmds/infrastructure/sequencers.js +10 -3
- package/dest/cmds/l1/deploy_l1_contracts_cmd.d.ts +1 -1
- package/dest/cmds/l1/deploy_l1_contracts_cmd.d.ts.map +1 -1
- package/dest/cmds/l1/deploy_l1_contracts_cmd.js +1 -0
- package/dest/cmds/l1/index.d.ts +1 -1
- package/dest/cmds/l1/index.d.ts.map +1 -1
- package/dest/cmds/l1/index.js +2 -1
- package/dest/cmds/l1/l1_rpc_test_utils.d.ts +10 -2
- package/dest/cmds/l1/l1_rpc_test_utils.d.ts.map +1 -1
- package/dest/cmds/l1/l1_rpc_test_utils.js +35 -1
- 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 +3 -4
- package/dest/cmds/l1/update_l1_validators.d.ts +3 -2
- package/dest/cmds/l1/update_l1_validators.d.ts.map +1 -1
- package/dest/cmds/l1/update_l1_validators.js +6 -4
- package/dest/cmds/misc/generate_p2p_private_key.d.ts +1 -1
- package/dest/cmds/misc/generate_p2p_private_key.d.ts.map +1 -1
- package/dest/cmds/misc/generate_p2p_private_key.js +1 -0
- 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 +14 -4
- package/dest/cmds/validator_keys/bls_key_derivation.d.ts +89 -0
- package/dest/cmds/validator_keys/bls_key_derivation.d.ts.map +1 -0
- package/dest/cmds/validator_keys/bls_key_derivation.js +122 -0
- package/dest/cmds/validator_keys/generate_bls_keypair.d.ts +3 -2
- package/dest/cmds/validator_keys/generate_bls_keypair.d.ts.map +1 -1
- package/dest/cmds/validator_keys/generate_bls_keypair.js +16 -3
- 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 +14 -3
- package/dest/cmds/validator_keys/new.d.ts +3 -2
- package/dest/cmds/validator_keys/new.d.ts.map +1 -1
- package/dest/cmds/validator_keys/new.js +47 -33
- package/dest/cmds/validator_keys/shared.d.ts +28 -3
- package/dest/cmds/validator_keys/shared.d.ts.map +1 -1
- package/dest/cmds/validator_keys/shared.js +48 -7
- package/dest/cmds/validator_keys/staker.d.ts +6 -1
- package/dest/cmds/validator_keys/staker.d.ts.map +1 -1
- package/dest/cmds/validator_keys/staker.js +32 -0
- package/dest/config/chain_l2_config.d.ts +1 -1
- package/dest/config/chain_l2_config.d.ts.map +1 -1
- package/dest/config/chain_l2_config.js +1 -1
- package/dest/config/enrich_env.d.ts +1 -1
- package/dest/config/enrich_env.d.ts.map +1 -1
- package/dest/config/enrich_env.js +1 -1
- package/dest/config/get_l1_config.d.ts +1 -1
- package/dest/config/get_l1_config.d.ts.map +1 -1
- package/dest/config/get_l1_config.js +2 -1
- 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 +4 -2
- package/dest/utils/aztec.d.ts +1 -1
- package/dest/utils/aztec.d.ts.map +1 -1
- package/dest/utils/aztec.js +1 -0
- package/dest/utils/commands.d.ts +1 -1
- package/dest/utils/commands.d.ts.map +1 -1
- package/dest/utils/commands.js +3 -1
- package/dest/utils/encoding.d.ts +1 -1
- package/dest/utils/encoding.d.ts.map +1 -1
- package/dest/utils/encoding.js +1 -0
- package/package.json +25 -25
- package/src/cmds/infrastructure/index.ts +13 -1
- package/src/cmds/infrastructure/sequencers.ts +14 -4
- package/src/cmds/l1/deploy_l1_contracts_cmd.ts +1 -0
- package/src/cmds/l1/index.ts +6 -0
- package/src/cmds/l1/l1_rpc_test_utils.ts +25 -2
- package/src/cmds/l1/prover_stats.ts +3 -2
- package/src/cmds/l1/update_l1_validators.ts +10 -4
- package/src/cmds/misc/generate_p2p_private_key.ts +1 -0
- package/src/cmds/validator_keys/add.ts +15 -2
- package/src/cmds/validator_keys/bls_key_derivation.ts +209 -0
- package/src/cmds/validator_keys/generate_bls_keypair.ts +26 -5
- package/src/cmds/validator_keys/index.ts +32 -0
- package/src/cmds/validator_keys/new.ts +50 -32
- package/src/cmds/validator_keys/shared.ts +70 -8
- package/src/cmds/validator_keys/staker.ts +56 -0
- package/src/config/chain_l2_config.ts +1 -0
- package/src/config/enrich_env.ts +1 -0
- package/src/config/get_l1_config.ts +2 -1
- package/src/config/network_config.ts +4 -2
- package/src/utils/aztec.ts +1 -0
- package/src/utils/commands.ts +3 -1
- package/src/utils/encoding.ts +1 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { estimateBlsKeyProofOfPossessionGas, minimumProofOfPossessionGas } from '@aztec-labs/ethereum/bn254';
|
|
2
|
+
import { deriveBlsPrivateKey } from '@aztec-labs/foundation/crypto/bls';
|
|
3
|
+
/**
|
|
4
|
+
* BLS key derivation v6. The gas model is a frozen copy of `AMSTERDAM_PROOF_OF_POSSESSION_GAS_MODEL` from
|
|
5
|
+
* `@aztec-labs/ethereum/bn254`. The budget is the 300,000 gas `proofOfPossessionGasLimit` that the v6 upgrade
|
|
6
|
+
* payload sets on the GSE, minus a 10% margin.
|
|
7
|
+
*
|
|
8
|
+
* With per-attempt probabilities 0.189030554816 of reaching the square root and 0.094515277408 of succeeding, about
|
|
9
|
+
* 5.8243e-6 of keys (1 in 171,694) estimate over the budget, so they move to a later candidate under v6.
|
|
10
|
+
*
|
|
11
|
+
* Frozen once a CLI release ships it: changing any value changes which BLS key `--bls-key-derivation-v6` selects for
|
|
12
|
+
* the same mnemonic and indices, so operators could no longer regenerate their keys. Add a new version instead.
|
|
13
|
+
*/ export const BLS_KEY_DERIVATION_V6 = {
|
|
14
|
+
version: 6,
|
|
15
|
+
gasModel: {
|
|
16
|
+
fixed: 132_694,
|
|
17
|
+
perAttempt: 515,
|
|
18
|
+
perSqrtCall: 4_580,
|
|
19
|
+
memoryNumerator: 95_975,
|
|
20
|
+
memoryDenominator: 1_000_000
|
|
21
|
+
},
|
|
22
|
+
budget: 270_000
|
|
23
|
+
};
|
|
24
|
+
/** Version checked when no derivation flag is given. A future version gets its own flag next to `--bls-key-derivation-v6`. */ export const LATEST_BLS_KEY_DERIVATION = BLS_KEY_DERIVATION_V6;
|
|
25
|
+
/** Number of candidates tried per validator before key selection gives up. */ export const MAX_BLS_KEY_CANDIDATES = 256;
|
|
26
|
+
const GENERATED_MNEMONIC_HINTS = {
|
|
27
|
+
shown: ' This run generated its mnemonic, and re-running without --mnemonic generates a new one: to keep this ' + 'mnemonic, pass it back with --mnemonic.',
|
|
28
|
+
hidden: ' This run generated a mnemonic without showing it, so re-running derives new keys from a new mnemonic.'
|
|
29
|
+
};
|
|
30
|
+
/** Thrown when candidate 0 estimates over the budget and no flag says what to do about it. */ export class BlsKeyOverGasBudgetError extends Error {
|
|
31
|
+
path;
|
|
32
|
+
estimatedGas;
|
|
33
|
+
version;
|
|
34
|
+
maxGas;
|
|
35
|
+
constructor(path, estimatedGas, version, maxGas, generatedMnemonic){
|
|
36
|
+
const budget = maxGas === undefined ? `the ${version.budget} budget of BLS key derivation v${version.version}, so it could exceed the L1 gas cap` : `the ${maxGas} budget set by --bls-key-derivation-max-gas`;
|
|
37
|
+
const remedies = maxGas === undefined ? `Re-run with --bls-key-derivation-v${version.version} to select a cheaper key for this validator, or with ` + `--skip-bls-key-gas-check to keep this key regardless (for example, a key already registered).` : `Re-run with --bls-key-derivation-v${version.version} to select a cheaper key for this validator, or with a ` + `higher --bls-key-derivation-max-gas.`;
|
|
38
|
+
super(`The proof-of-possession check of the BLS key derived at ${path} is estimated at ${estimatedGas} gas, above ` + `${budget}. ${remedies}` + (generatedMnemonic ? GENERATED_MNEMONIC_HINTS[generatedMnemonic] : '')), this.path = path, this.estimatedGas = estimatedGas, this.version = version, this.maxGas = maxGas;
|
|
39
|
+
this.name = 'BlsKeyOverGasBudgetError';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Validates the BLS key derivation flags and turns them into a policy. */ export function resolveBlsKeyDerivationPolicy(options) {
|
|
43
|
+
const { blsKeyDerivationV6, blsKeyDerivationMaxGas: maxGas, skipBlsKeyGasCheck } = options;
|
|
44
|
+
const version = LATEST_BLS_KEY_DERIVATION;
|
|
45
|
+
if (skipBlsKeyGasCheck) {
|
|
46
|
+
if (blsKeyDerivationV6) {
|
|
47
|
+
throw new Error('--bls-key-derivation-v6 and --skip-bls-key-gas-check cannot be used together');
|
|
48
|
+
}
|
|
49
|
+
if (maxGas !== undefined) {
|
|
50
|
+
throw new Error('--bls-key-derivation-max-gas and --skip-bls-key-gas-check cannot be used together');
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
mode: 'none'
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (maxGas !== undefined) {
|
|
57
|
+
if (!Number.isSafeInteger(maxGas)) {
|
|
58
|
+
throw new Error(`--bls-key-derivation-max-gas must be an integer, got ${maxGas}`);
|
|
59
|
+
}
|
|
60
|
+
if (maxGas > version.budget) {
|
|
61
|
+
throw new Error(`--bls-key-derivation-max-gas can only lower the budget: ${maxGas} is above the ${version.budget} gas budget ` + `of BLS key derivation v${version.version}.`);
|
|
62
|
+
}
|
|
63
|
+
const minimum = minimumProofOfPossessionGas(version.gasModel);
|
|
64
|
+
if (maxGas < minimum) {
|
|
65
|
+
throw new Error(`--bls-key-derivation-max-gas ${maxGas} is below ${minimum}, the lowest proof-of-possession gas estimate any ` + `key can have, so no key could fit.`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
mode: blsKeyDerivationV6 ? 'retry' : 'check',
|
|
70
|
+
version,
|
|
71
|
+
...maxGas !== undefined ? {
|
|
72
|
+
maxGas
|
|
73
|
+
} : {}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/** Derivation path of a candidate: candidate 0 is the per-validator path itself, others append `/<candidate>`. */ export function blsCandidatePath(perValidatorPath, candidate) {
|
|
77
|
+
return candidate === 0 ? perValidatorPath : `${perValidatorPath}/${candidate}`;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Derives a validator's BLS key from `perValidatorPath` under the given policy. Only the mnemonic or IKM, the path
|
|
81
|
+
* and the policy decide the result, so re-running with the same inputs regenerates the same key.
|
|
82
|
+
*/ export function selectBlsKey(policy, input) {
|
|
83
|
+
const { mnemonic, ikm, perValidatorPath, generatedMnemonic, maxCandidates = MAX_BLS_KEY_CANDIDATES } = input;
|
|
84
|
+
const candidate0 = {
|
|
85
|
+
privateKey: deriveBlsPrivateKey(mnemonic, ikm, perValidatorPath),
|
|
86
|
+
path: perValidatorPath
|
|
87
|
+
};
|
|
88
|
+
if (policy.mode === 'none') {
|
|
89
|
+
return {
|
|
90
|
+
...candidate0,
|
|
91
|
+
candidate: 0
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const { gasModel } = policy.version;
|
|
95
|
+
const budget = policy.maxGas ?? policy.version.budget;
|
|
96
|
+
if (policy.mode === 'check') {
|
|
97
|
+
const estimatedGas = estimateBlsKeyProofOfPossessionGas(gasModel, candidate0.privateKey);
|
|
98
|
+
if (estimatedGas > budget) {
|
|
99
|
+
throw new BlsKeyOverGasBudgetError(perValidatorPath, estimatedGas, policy.version, policy.maxGas, // An IKM takes precedence over the mnemonic, so the mnemonic does not decide the BLS key.
|
|
100
|
+
ikm ? undefined : generatedMnemonic);
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
...candidate0,
|
|
104
|
+
candidate: 0
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
for(let candidate = 0; candidate < maxCandidates; candidate++){
|
|
108
|
+
const path = blsCandidatePath(perValidatorPath, candidate);
|
|
109
|
+
const privateKey = candidate === 0 ? candidate0.privateKey : deriveBlsPrivateKey(mnemonic, ikm, path);
|
|
110
|
+
if (estimateBlsKeyProofOfPossessionGas(gasModel, privateKey) <= budget) {
|
|
111
|
+
return {
|
|
112
|
+
privateKey,
|
|
113
|
+
path,
|
|
114
|
+
candidate,
|
|
115
|
+
...candidate > 0 && policy.maxGas !== undefined ? {
|
|
116
|
+
maxGas: budget
|
|
117
|
+
} : {}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
throw new Error(`No BLS key within the ${budget} gas budget found for ` + `${perValidatorPath} after ${maxCandidates} candidates.`);
|
|
122
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { LogFn } from '@aztec-labs/foundation/log';
|
|
2
|
+
import { type BlsKeyDerivationOptions } from './bls_key_derivation.js';
|
|
2
3
|
export type GenerateBlsKeypairOptions = {
|
|
3
4
|
mnemonic?: string;
|
|
4
5
|
ikm?: string;
|
|
@@ -7,6 +8,6 @@ export type GenerateBlsKeypairOptions = {
|
|
|
7
8
|
compressed?: boolean;
|
|
8
9
|
json?: boolean;
|
|
9
10
|
out?: string;
|
|
10
|
-
};
|
|
11
|
+
} & BlsKeyDerivationOptions;
|
|
11
12
|
export declare function generateBlsKeypair(options: GenerateBlsKeypairOptions, log: LogFn): Promise<void>;
|
|
12
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
13
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdGVfYmxzX2tleXBhaXIuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jbWRzL3ZhbGlkYXRvcl9rZXlzL2dlbmVyYXRlX2Jsc19rZXlwYWlyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLEtBQUssRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBR3hELE9BQU8sRUFBRSxLQUFLLHVCQUF1QixFQUErQyxNQUFNLHlCQUF5QixDQUFDO0FBSXBILE1BQU0sTUFBTSx5QkFBeUIsR0FBRztJQUN0QyxRQUFRLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDbEIsR0FBRyxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ2IsT0FBTyxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ2pCLEVBQUUsQ0FBQyxFQUFFLE9BQU8sQ0FBQztJQUNiLFVBQVUsQ0FBQyxFQUFFLE9BQU8sQ0FBQztJQUNyQixJQUFJLENBQUMsRUFBRSxPQUFPLENBQUM7SUFDZixHQUFHLENBQUMsRUFBRSxNQUFNLENBQUM7Q0FDZCxHQUFHLHVCQUF1QixDQUFDO0FBRTVCLHdCQUFzQixrQkFBa0IsQ0FBQyxPQUFPLEVBQUUseUJBQXlCLEVBQUUsR0FBRyxFQUFFLEtBQUssaUJBb0N0RiJ9
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate_bls_keypair.d.ts","sourceRoot":"","sources":["../../../src/cmds/validator_keys/generate_bls_keypair.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generate_bls_keypair.d.ts","sourceRoot":"","sources":["../../../src/cmds/validator_keys/generate_bls_keypair.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AAGxD,OAAO,EAAE,KAAK,uBAAuB,EAA+C,MAAM,yBAAyB,CAAC;AAIpH,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,GAAG,uBAAuB,CAAC;AAE5B,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,EAAE,GAAG,EAAE,KAAK,iBAoCtF"}
|
|
@@ -1,14 +1,24 @@
|
|
|
1
|
-
import { deriveBlsPrivateKey } from '@aztec-labs/foundation/crypto/bls';
|
|
2
1
|
import { writeFile } from 'fs/promises';
|
|
2
|
+
import { resolveBlsKeyDerivationPolicy, selectBlsKey } from './bls_key_derivation.js';
|
|
3
3
|
import { computeBlsPublicKeyCompressed, withValidatorIndex } from './shared.js';
|
|
4
4
|
import { defaultBlsPath } from './utils.js';
|
|
5
5
|
export async function generateBlsKeypair(options, log) {
|
|
6
6
|
const { mnemonic, ikm, blsPath, compressed = true, json, out } = options;
|
|
7
|
-
const
|
|
8
|
-
const priv =
|
|
7
|
+
const blsKeyDerivation = resolveBlsKeyDerivationPolicy(options);
|
|
8
|
+
const { path, privateKey: priv, candidate, maxGas } = selectBlsKey(blsKeyDerivation, {
|
|
9
|
+
mnemonic,
|
|
10
|
+
ikm,
|
|
11
|
+
perValidatorPath: withValidatorIndex(blsPath ?? defaultBlsPath, 0)
|
|
12
|
+
});
|
|
9
13
|
const pub = await computeBlsPublicKeyCompressed(priv);
|
|
10
14
|
const result = {
|
|
11
15
|
path,
|
|
16
|
+
...candidate > 0 ? {
|
|
17
|
+
candidate
|
|
18
|
+
} : {},
|
|
19
|
+
...maxGas !== undefined ? {
|
|
20
|
+
maxGas
|
|
21
|
+
} : {},
|
|
12
22
|
privateKey: priv,
|
|
13
23
|
publicKey: pub,
|
|
14
24
|
format: compressed ? 'compressed' : 'uncompressed'
|
|
@@ -19,6 +29,9 @@ export async function generateBlsKeypair(options, log) {
|
|
|
19
29
|
});
|
|
20
30
|
if (!json) {
|
|
21
31
|
log(`Wrote BLS keypair to ${out}`);
|
|
32
|
+
if (candidate > 0) {
|
|
33
|
+
log(`BLS key derived from candidate ${candidate} at ${path}${maxGas !== undefined ? ` (max gas ${maxGas})` : ''}`);
|
|
34
|
+
}
|
|
22
35
|
}
|
|
23
36
|
}
|
|
24
37
|
if (json || !out) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { LogFn } from '@aztec-labs/foundation/log';
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
export declare function injectCommands(program: Command, log: LogFn): Command;
|
|
4
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
4
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jbWRzL3ZhbGlkYXRvcl9rZXlzL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sS0FBSyxFQUFFLEtBQUssRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ3hELE9BQU8sRUFBRSxPQUFPLEVBQVUsTUFBTSxXQUFXLENBQUM7QUEyQjVDLHdCQUFnQixjQUFjLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxHQUFHLEVBQUUsS0FBSyxXQXVMMUQifQ==
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cmds/validator_keys/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cmds/validator_keys/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AA2B5C,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,WAuL1D"}
|
|
@@ -1,16 +1,27 @@
|
|
|
1
|
+
import { minimumProofOfPossessionGas } from '@aztec-labs/ethereum/bn254';
|
|
1
2
|
import { Option } from 'commander';
|
|
2
3
|
import { parseAztecAddress, parseEthereumAddress, parseHex, parseOptionalInteger } from '../../utils/commands.js';
|
|
4
|
+
import { BLS_KEY_DERIVATION_V6 } from './bls_key_derivation.js';
|
|
3
5
|
import { defaultBlsPath } from './utils.js';
|
|
6
|
+
function blsKeyDerivationV6Option() {
|
|
7
|
+
return new Option('--bls-key-derivation-v6', `Replace any BLS key whose estimated proof-of-possession gas exceeds the budget with the next deterministic candidate from the same mnemonic (BLS key derivation v6, budget ${BLS_KEY_DERIVATION_V6.budget} gas). ETH keys never change. Pass it again to regenerate the same keys.`);
|
|
8
|
+
}
|
|
9
|
+
function blsKeyDerivationMaxGasOption() {
|
|
10
|
+
return new Option('--bls-key-derivation-max-gas <gas>', `Stricter budget for the estimated proof-of-possession verification gas of each BLS key. The L1 limit (GSE proofOfPossessionGasLimit) is 300,000 gas from the v6 upgrade, and governance may change it; the default budget is ${BLS_KEY_DERIVATION_V6.budget}, that cap minus a 10% margin. Must be between ${minimumProofOfPossessionGas(BLS_KEY_DERIVATION_V6.gasModel)} and ${BLS_KEY_DERIVATION_V6.budget}. Without --bls-key-derivation-v6, an over-budget key is an error. Pass the same value again to regenerate the same keys.`).argParser((value)=>parseOptionalInteger(value));
|
|
11
|
+
}
|
|
12
|
+
function skipBlsKeyGasCheckOption() {
|
|
13
|
+
return new Option('--skip-bls-key-gas-check', 'Keep the first derived BLS key even if its proof-of-possession check could exceed the L1 gas cap (for example, a key already registered).');
|
|
14
|
+
}
|
|
4
15
|
export function injectCommands(program, log) {
|
|
5
16
|
const group = program.command('validator-keys').aliases([
|
|
6
17
|
'valKeys',
|
|
7
18
|
'valkeys'
|
|
8
19
|
]).description('Manage validator keystores for node operators');
|
|
9
|
-
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).option('--funding-account <privateKey|address>', 'ETH funding account used to top up publisher EOAs. Provide a private key, or an address together with --remote-signer.').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})`).addOption(new Option('--password <str>', 'Shared password for writing ETH JSON V3 and BLS EIP-2335 keystore files').env('AZTEC_KEYSTORE_PASSWORD')).option('--password-file <path>', 'File containing the shared password for writing keystore files').addOption(new Option('--eth-password <str>', 'Password for writing ETH JSON V3 keystore files').env('AZTEC_ETH_KEYSTORE_PASSWORD')).option('--eth-password-file <path>', 'File containing the password for writing ETH JSON V3 keystore files').addOption(new Option('--bls-password <str>', 'Password for writing BLS EIP-2335 keystore files').env('AZTEC_BLS_KEYSTORE_PASSWORD')).option('--bls-password-file <path>', 'File containing the password for writing BLS EIP-2335 keystore files').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)=>{
|
|
20
|
+
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).option('--funding-account <privateKey|address>', 'ETH funding account used to top up publisher EOAs. Provide a private key, or an address together with --remote-signer.').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})`).addOption(blsKeyDerivationV6Option()).addOption(blsKeyDerivationMaxGasOption()).addOption(skipBlsKeyGasCheckOption()).addOption(new Option('--password <str>', 'Shared password for writing ETH JSON V3 and BLS EIP-2335 keystore files').env('AZTEC_KEYSTORE_PASSWORD')).option('--password-file <path>', 'File containing the shared password for writing keystore files').addOption(new Option('--eth-password <str>', 'Password for writing ETH JSON V3 keystore files').env('AZTEC_ETH_KEYSTORE_PASSWORD')).option('--eth-password-file <path>', 'File containing the password for writing ETH JSON V3 keystore files').addOption(new Option('--bls-password <str>', 'Password for writing BLS EIP-2335 keystore files').env('AZTEC_BLS_KEYSTORE_PASSWORD')).option('--bls-password-file <path>', 'File containing the password for writing BLS EIP-2335 keystore files').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)=>{
|
|
10
21
|
const { newValidatorKeystore } = await import('./new.js');
|
|
11
22
|
await newValidatorKeystore(options, log);
|
|
12
23
|
});
|
|
13
|
-
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).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)=>{
|
|
24
|
+
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).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})`).addOption(blsKeyDerivationV6Option()).addOption(blsKeyDerivationMaxGasOption()).addOption(skipBlsKeyGasCheckOption()).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)=>{
|
|
14
25
|
const { addValidatorKeys } = await import('./add.js');
|
|
15
26
|
await addValidatorKeys(existing, options, log);
|
|
16
27
|
});
|
|
@@ -25,7 +36,7 @@ export function injectCommands(program, log) {
|
|
|
25
36
|
await generateStakerJson(options, log);
|
|
26
37
|
});
|
|
27
38
|
// top-level convenience: aztec generate-bls-keypair
|
|
28
|
-
program.command('generate-bls-keypair').description('Generate a BLS keypair with convenience flags').option('--mnemonic <mnemonic>', 'Mnemonic for BLS derivation').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('--g2', 'Derive on G2 subgroup').option('--compressed', 'Output compressed public key').option('--json', 'Print JSON output to stdout').option('--out <file>', 'Write output to file').action(async (options)=>{
|
|
39
|
+
program.command('generate-bls-keypair').description('Generate a BLS keypair with convenience flags').option('--mnemonic <mnemonic>', 'Mnemonic for BLS derivation').option('--ikm <hex>', 'Initial keying material for BLS (alternative to mnemonic)', (value)=>parseHex(value, 32)).option('--bls-path <path>', `EIP-2334 path (default ${defaultBlsPath})`).addOption(blsKeyDerivationV6Option()).addOption(blsKeyDerivationMaxGasOption()).addOption(skipBlsKeyGasCheckOption()).option('--g2', 'Derive on G2 subgroup').option('--compressed', 'Output compressed public key').option('--json', 'Print JSON output to stdout').option('--out <file>', 'Write output to file').action(async (options)=>{
|
|
29
40
|
const { generateBlsKeypair } = await import('./generate_bls_keypair.js');
|
|
30
41
|
await generateBlsKeypair(options, log);
|
|
31
42
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { EthAddress } from '@aztec-labs/foundation/eth-address';
|
|
2
2
|
import type { LogFn } from '@aztec-labs/foundation/log';
|
|
3
3
|
import type { AztecAddress } from '@aztec-labs/stdlib/aztec-address';
|
|
4
|
+
import { type BlsKeyDerivationOptions } from './bls_key_derivation.js';
|
|
4
5
|
export type NewValidatorKeystoreOptions = {
|
|
5
6
|
dataDir?: string;
|
|
6
7
|
file?: string;
|
|
@@ -30,6 +31,6 @@ export type NewValidatorKeystoreOptions = {
|
|
|
30
31
|
gseAddress?: EthAddress;
|
|
31
32
|
l1RpcUrls?: string[];
|
|
32
33
|
l1ChainId?: number;
|
|
33
|
-
};
|
|
34
|
+
} & BlsKeyDerivationOptions;
|
|
34
35
|
export declare function newValidatorKeystore(options: NewValidatorKeystoreOptions, log: LogFn): Promise<void>;
|
|
35
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
36
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV3LmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY21kcy92YWxpZGF0b3Jfa2V5cy9uZXcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBR0EsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0sb0NBQW9DLENBQUM7QUFDckUsT0FBTyxLQUFLLEVBQUUsS0FBSyxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDeEQsT0FBTyxLQUFLLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFPckUsT0FBTyxFQUFFLEtBQUssdUJBQXVCLEVBQWlDLE1BQU0seUJBQXlCLENBQUM7QUF1QnRHLE1BQU0sTUFBTSwyQkFBMkIsR0FBRztJQUN4QyxPQUFPLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDakIsSUFBSSxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ2QsS0FBSyxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ2YsY0FBYyxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ3hCLFVBQVUsQ0FBQyxFQUFFLE1BQU0sRUFBRSxDQUFDO0lBQ3RCLFFBQVEsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUNsQixVQUFVLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDcEIsWUFBWSxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ3RCLFlBQVksQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUN0QixpQkFBaUIsQ0FBQyxFQUFFLE9BQU8sQ0FBQztJQUM1QixHQUFHLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDYixPQUFPLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDakIsUUFBUSxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ2xCLFlBQVksQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUN0QixXQUFXLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDckIsZUFBZSxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ3pCLFdBQVcsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUNyQixlQUFlLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDekIsb0JBQW9CLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDOUIsSUFBSSxDQUFDLEVBQUUsT0FBTyxDQUFDO0lBQ2YsWUFBWSxFQUFFLFlBQVksQ0FBQztJQUMzQixRQUFRLENBQUMsRUFBRSxVQUFVLENBQUM7SUFDdEIsY0FBYyxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ3hCLFlBQVksQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUN0QixZQUFZLENBQUMsRUFBRSxPQUFPLENBQUM7SUFDdkIsVUFBVSxDQUFDLEVBQUUsVUFBVSxDQUFDO0lBQ3hCLFNBQVMsQ0FBQyxFQUFFLE1BQU0sRUFBRSxDQUFDO0lBQ3JCLFNBQVMsQ0FBQyxFQUFFLE1BQU0sQ0FBQztDQUNwQixHQUFHLHVCQUF1QixDQUFDO0FBa0Y1Qix3QkFBc0Isb0JBQW9CLENBQUMsT0FBTyxFQUFFLDJCQUEyQixFQUFFLEdBQUcsRUFBRSxLQUFLLGlCQXFNMUYifQ==
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"new.d.ts","sourceRoot":"","sources":["../../../src/cmds/validator_keys/new.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"new.d.ts","sourceRoot":"","sources":["../../../src/cmds/validator_keys/new.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAOrE,OAAO,EAAE,KAAK,uBAAuB,EAAiC,MAAM,yBAAyB,CAAC;AAuBtG,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,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,YAAY,CAAC;IAC3B,QAAQ,CAAC,EAAE,UAAU,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,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,GAAG,uBAAuB,CAAC;AAkF5B,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,EAAE,GAAG,EAAE,KAAK,iBAqM1F"}
|
|
@@ -6,8 +6,9 @@ import { readFile, writeFile } from 'fs/promises';
|
|
|
6
6
|
import { basename, dirname, join } from 'path';
|
|
7
7
|
import { createPublicClient, fallback, http } from 'viem';
|
|
8
8
|
import { generateMnemonic, mnemonicToAccount, privateKeyToAccount } from 'viem/accounts';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { resolveBlsKeyDerivationPolicy } from './bls_key_derivation.js';
|
|
10
|
+
import { buildValidatorEntries, encryptFundingAccountToFile, getBlsDerivationPaths, getBlsKeyCandidates, logValidatorSummaries, maybePrintJson, resolveFundingAccount, resolveKeystoreOutputPath, writeBlsBn254ToFile, writeEthJsonV3ToFile, writeKeystoreFile } from './shared.js';
|
|
11
|
+
import { assertWithinProofOfPossessionGasLimit, processAttesterAccounts } from './staker.js';
|
|
11
12
|
import { validateBlsPathOptions, validateFundingAccountOptions, validatePublisherOptions, validateRemoteSignerOptions, validateStakerOutputOptions } from './utils.js';
|
|
12
13
|
function validatePassword(password, source) {
|
|
13
14
|
if (password.length === 0) {
|
|
@@ -81,6 +82,7 @@ export async function newValidatorKeystore(options, log) {
|
|
|
81
82
|
validateRemoteSignerOptions(options);
|
|
82
83
|
// validate funding account option
|
|
83
84
|
validateFundingAccountOptions(options);
|
|
85
|
+
const blsKeyDerivation = resolveBlsKeyDerivationPolicy(options);
|
|
84
86
|
const { dataDir, file, count, publisherCount = 0, publishers, json, coinbase, fundingAccount, accountIndex = 0, addressIndex = 0, feeRecipient, remoteSigner, blsPath, ikm, mnemonic: _mnemonic, password: passwordOption, passwordFile, ethPassword: ethPasswordOption, ethPasswordFile, blsPassword: blsPasswordOption, blsPasswordFile, encryptedKeystoreDir, stakerOutput, gseAddress, l1RpcUrls, l1ChainId } = options;
|
|
85
87
|
const { ethPassword, blsPassword } = await resolvePasswords({
|
|
86
88
|
password: passwordOption,
|
|
@@ -92,7 +94,8 @@ export async function newValidatorKeystore(options, log) {
|
|
|
92
94
|
});
|
|
93
95
|
const shouldEncryptKeystores = ethPassword !== undefined && blsPassword !== undefined;
|
|
94
96
|
const mnemonic = _mnemonic ?? generateMnemonic(wordlist);
|
|
95
|
-
|
|
97
|
+
const showGeneratedMnemonic = !_mnemonic && !json && !shouldEncryptKeystores;
|
|
98
|
+
if (showGeneratedMnemonic) {
|
|
96
99
|
log('No mnemonic provided, generating new one...');
|
|
97
100
|
log(`Using new mnemonic:`);
|
|
98
101
|
log('');
|
|
@@ -113,8 +116,33 @@ export async function newValidatorKeystore(options, log) {
|
|
|
113
116
|
blsPath,
|
|
114
117
|
feeRecipient,
|
|
115
118
|
coinbase,
|
|
116
|
-
remoteSigner
|
|
119
|
+
remoteSigner,
|
|
120
|
+
blsKeyDerivation,
|
|
121
|
+
generatedMnemonic: _mnemonic ? undefined : showGeneratedMnemonic ? 'shown' : 'hidden'
|
|
117
122
|
});
|
|
123
|
+
// Generate staker outputs if requested, from the plaintext keys and before writing anything, so that keys the GSE
|
|
124
|
+
// would reject leave no files behind.
|
|
125
|
+
const allStakerOutputs = [];
|
|
126
|
+
if (stakerOutput && gseAddress && l1RpcUrls && l1ChainId !== undefined) {
|
|
127
|
+
const chain = createEthereumChain(l1RpcUrls, l1ChainId);
|
|
128
|
+
const publicClient = createPublicClient({
|
|
129
|
+
chain: chain.chainInfo,
|
|
130
|
+
transport: fallback(l1RpcUrls.map((url)=>http(url, {
|
|
131
|
+
batch: false
|
|
132
|
+
})))
|
|
133
|
+
});
|
|
134
|
+
const gse = new GSEContract(publicClient, gseAddress);
|
|
135
|
+
// Process each validator
|
|
136
|
+
for(let i = 0; i < validators.length; i++){
|
|
137
|
+
const validator = validators[i];
|
|
138
|
+
const outputs = await processAttesterAccounts(validator.attester, gse);
|
|
139
|
+
// Collect all staker outputs
|
|
140
|
+
for(let j = 0; j < outputs.length; j++){
|
|
141
|
+
allStakerOutputs.push(outputs[j]);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
await assertWithinProofOfPossessionGasLimit(gse, allStakerOutputs);
|
|
145
|
+
}
|
|
118
146
|
let resolvedFundingAccount = fundingAccount ? resolveFundingAccount(fundingAccount, remoteSigner) : undefined;
|
|
119
147
|
// If password provided, write ETH JSON V3 and BLS BN254 keystores and replace plaintext
|
|
120
148
|
if (shouldEncryptKeystores) {
|
|
@@ -125,7 +153,8 @@ export async function newValidatorKeystore(options, log) {
|
|
|
125
153
|
});
|
|
126
154
|
await writeBlsBn254ToFile(validators, {
|
|
127
155
|
outDir: encryptedKeystoreOutDir,
|
|
128
|
-
password: blsPassword
|
|
156
|
+
password: blsPassword,
|
|
157
|
+
derivationPaths: getBlsDerivationPaths(summaries)
|
|
129
158
|
});
|
|
130
159
|
if (resolvedFundingAccount) {
|
|
131
160
|
resolvedFundingAccount = await encryptFundingAccountToFile(resolvedFundingAccount, {
|
|
@@ -142,38 +171,23 @@ export async function newValidatorKeystore(options, log) {
|
|
|
142
171
|
} : {}
|
|
143
172
|
};
|
|
144
173
|
await writeKeystoreFile(outputPath, keystore);
|
|
145
|
-
//
|
|
146
|
-
|
|
147
|
-
if (stakerOutput && gseAddress && l1RpcUrls && l1ChainId !== undefined) {
|
|
148
|
-
const chain = createEthereumChain(l1RpcUrls, l1ChainId);
|
|
149
|
-
const publicClient = createPublicClient({
|
|
150
|
-
chain: chain.chainInfo,
|
|
151
|
-
transport: fallback(l1RpcUrls.map((url)=>http(url, {
|
|
152
|
-
batch: false
|
|
153
|
-
})))
|
|
154
|
-
});
|
|
155
|
-
const gse = new GSEContract(publicClient, gseAddress);
|
|
174
|
+
// Write a single JSON file with all staker outputs
|
|
175
|
+
if (allStakerOutputs.length > 0) {
|
|
156
176
|
// Extract keystore base name without extension for unique staker output filenames
|
|
157
177
|
const keystoreBaseName = basename(outputPath, '.json');
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
const validator = validators[i];
|
|
161
|
-
const outputs = await processAttesterAccounts(validator.attester, gse);
|
|
162
|
-
// Collect all staker outputs
|
|
163
|
-
for(let j = 0; j < outputs.length; j++){
|
|
164
|
-
allStakerOutputs.push(outputs[j]);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
// Write a single JSON file with all staker outputs
|
|
168
|
-
if (allStakerOutputs.length > 0) {
|
|
169
|
-
const stakerOutputPath = join(keystoreOutDir, `${keystoreBaseName}_staker_output.json`);
|
|
170
|
-
await writeFile(stakerOutputPath, prettyPrintJSON(allStakerOutputs), 'utf-8');
|
|
171
|
-
}
|
|
178
|
+
const stakerOutputPath = join(keystoreOutDir, `${keystoreBaseName}_staker_output.json`);
|
|
179
|
+
await writeFile(stakerOutputPath, prettyPrintJSON(allStakerOutputs), 'utf-8');
|
|
172
180
|
}
|
|
173
|
-
const
|
|
181
|
+
const blsKeyCandidates = getBlsKeyCandidates(summaries);
|
|
182
|
+
const outputData = {
|
|
174
183
|
...keystore,
|
|
175
|
-
|
|
176
|
-
|
|
184
|
+
...!_mnemonic && !shouldEncryptKeystores ? {
|
|
185
|
+
generatedMnemonic: mnemonic
|
|
186
|
+
} : {},
|
|
187
|
+
...blsKeyCandidates.length > 0 ? {
|
|
188
|
+
blsKeyCandidates
|
|
189
|
+
} : {}
|
|
190
|
+
};
|
|
177
191
|
// Handle JSON output
|
|
178
192
|
if (json) {
|
|
179
193
|
if (stakerOutput && allStakerOutputs.length > 0) {
|
|
@@ -2,9 +2,16 @@ import { EthAddress } from '@aztec-labs/foundation/eth-address';
|
|
|
2
2
|
import type { LogFn } from '@aztec-labs/foundation/log';
|
|
3
3
|
import type { EthAccount, EthPrivateKey, ValidatorKeyStore } from '@aztec-labs/node-keystore/types';
|
|
4
4
|
import type { AztecAddress } from '@aztec-labs/stdlib/aztec-address';
|
|
5
|
+
import { type BlsKeyDerivationPolicy, type GeneratedMnemonic } from './bls_key_derivation.js';
|
|
5
6
|
export type ValidatorSummary = {
|
|
6
7
|
attesterEth?: string;
|
|
7
8
|
attesterBls?: string;
|
|
9
|
+
/** Derivation path of the BLS key, including the candidate component when the candidate is not 0. */
|
|
10
|
+
blsPath?: string;
|
|
11
|
+
/** Candidate selected by the BLS key derivation policy; 0 unless a retry picked another one. */
|
|
12
|
+
blsCandidate?: number;
|
|
13
|
+
/** The `--bls-key-derivation-max-gas` budget, when it took part in selecting a candidate other than 0. */
|
|
14
|
+
blsMaxGas?: number;
|
|
8
15
|
publisherEth?: string[];
|
|
9
16
|
};
|
|
10
17
|
export type BuildValidatorsInput = {
|
|
@@ -19,6 +26,10 @@ export type BuildValidatorsInput = {
|
|
|
19
26
|
feeRecipient: AztecAddress;
|
|
20
27
|
coinbase?: EthAddress;
|
|
21
28
|
remoteSigner?: string;
|
|
29
|
+
/** Defaults to the policy used when no BLS key derivation flag is given. */
|
|
30
|
+
blsKeyDerivation?: BlsKeyDerivationPolicy;
|
|
31
|
+
/** Set when the CLI generated `mnemonic` in this run. */
|
|
32
|
+
generatedMnemonic?: GeneratedMnemonic;
|
|
22
33
|
};
|
|
23
34
|
export declare function withValidatorIndex(path: string, accountIndex?: number, addressIndex?: number): string;
|
|
24
35
|
/**
|
|
@@ -46,6 +57,16 @@ export declare function resolveKeystoreOutputPath(dataDir?: string, file?: strin
|
|
|
46
57
|
}>;
|
|
47
58
|
export declare function writeKeystoreFile(path: string, keystore: unknown): Promise<void>;
|
|
48
59
|
export declare function logValidatorSummaries(log: LogFn, summaries: ValidatorSummary[]): void;
|
|
60
|
+
/** BLS keys in `summaries` that came from a retry candidate, for reporting alongside JSON output. */
|
|
61
|
+
export declare function getBlsKeyCandidates(summaries: ValidatorSummary[]): {
|
|
62
|
+
attesterEth: string | undefined;
|
|
63
|
+
bls: string | undefined;
|
|
64
|
+
path: string | undefined;
|
|
65
|
+
candidate: number | undefined;
|
|
66
|
+
maxGas?: number | undefined;
|
|
67
|
+
}[];
|
|
68
|
+
/** Derivation path of each BLS key in `summaries`, keyed by its compressed public key. */
|
|
69
|
+
export declare function getBlsDerivationPaths(summaries: ValidatorSummary[]): Map<string, string>;
|
|
49
70
|
export declare function maybePrintJson(log: LogFn, jsonFlag: boolean | undefined, obj: unknown): void;
|
|
50
71
|
/**
|
|
51
72
|
* Writes a BN254 keystore file for a BN254 BLS private key.
|
|
@@ -60,11 +81,15 @@ export declare function maybePrintJson(log: LogFn, jsonFlag: boolean | undefined
|
|
|
60
81
|
* @returns Absolute path to the written keystore file
|
|
61
82
|
*/
|
|
62
83
|
export declare function writeBn254BlsKeystore(outDir: string, fileNameBase: string, password: string, privateKeyHex: string, pubkeyHex: string, derivationPath: string): Promise<string>;
|
|
63
|
-
/**
|
|
84
|
+
/**
|
|
85
|
+
* Replace plaintext BLS keys in validators with { path, password } pointing to BN254 keystore files. Each file records
|
|
86
|
+
* the key's derivation path from `derivationPaths` (keyed by compressed public key), or an empty path for keys missing
|
|
87
|
+
* from it, such as keys that were already in a keystore file, whose origin is unknown.
|
|
88
|
+
*/
|
|
64
89
|
export declare function writeBlsBn254ToFile(validators: ValidatorKeyStore[], options: {
|
|
65
90
|
outDir: string;
|
|
66
91
|
password: string;
|
|
67
|
-
|
|
92
|
+
derivationPaths?: Map<string, string>;
|
|
68
93
|
}): Promise<void>;
|
|
69
94
|
/** Writes an Ethereum JSON V3 keystore using ethers, returns absolute path */
|
|
70
95
|
export declare function writeEthJsonV3Keystore(outDir: string, fileNameBase: string, password: string, privateKeyHex: string): Promise<string>;
|
|
@@ -78,4 +103,4 @@ export declare function writeEthJsonV3ToFile(validators: ValidatorKeyStore[], op
|
|
|
78
103
|
outDir: string;
|
|
79
104
|
password: string;
|
|
80
105
|
}): Promise<void>;
|
|
81
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
106
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2hhcmVkLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY21kcy92YWxpZGF0b3Jfa2V5cy9zaGFyZWQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBS0EsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQ2hFLE9BQU8sS0FBSyxFQUFFLEtBQUssRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ3hELE9BQU8sS0FBSyxFQUFFLFVBQVUsRUFBRSxhQUFhLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNwRyxPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQVVyRSxPQUFPLEVBQ0wsS0FBSyxzQkFBc0IsRUFDM0IsS0FBSyxpQkFBaUIsRUFHdkIsTUFBTSx5QkFBeUIsQ0FBQztBQW1EakMsTUFBTSxNQUFNLGdCQUFnQixHQUFHO0lBQzdCLFdBQVcsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUNyQixXQUFXLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDckIscUdBQXFHO0lBQ3JHLE9BQU8sQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUNqQixnR0FBZ0c7SUFDaEcsWUFBWSxDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ3RCLDBHQUEwRztJQUMxRyxTQUFTLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDbkIsWUFBWSxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUM7Q0FDekIsQ0FBQztBQUVGLE1BQU0sTUFBTSxvQkFBb0IsR0FBRztJQUNqQyxjQUFjLEVBQUUsTUFBTSxDQUFDO0lBQ3ZCLGNBQWMsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUN4QixVQUFVLENBQUMsRUFBRSxNQUFNLEVBQUUsQ0FBQztJQUN0QixZQUFZLEVBQUUsTUFBTSxDQUFDO0lBQ3JCLGdCQUFnQixFQUFFLE1BQU0sQ0FBQztJQUN6QixRQUFRLEVBQUUsTUFBTSxDQUFDO0lBQ2pCLEdBQUcsQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUNiLE9BQU8sQ0FBQyxFQUFFLE1BQU0sQ0FBQztJQUNqQixZQUFZLEVBQUUsWUFBWSxDQUFDO0lBQzNCLFFBQVEsQ0FBQyxFQUFFLFVBQVUsQ0FBQztJQUN0QixZQUFZLENBQUMsRUFBRSxNQUFNLENBQUM7SUFDdEIsNEVBQTRFO0lBQzVFLGdCQUFnQixDQUFDLEVBQUUsc0JBQXNCLENBQUM7SUFDMUMseURBQXlEO0lBQ3pELGlCQUFpQixDQUFDLEVBQUUsaUJBQWlCLENBQUM7Q0FDdkMsQ0FBQztBQUVGLHdCQUFnQixrQkFBa0IsQ0FBQyxJQUFJLEVBQUUsTUFBTSxFQUFFLFlBQVksR0FBRSxNQUFVLEVBQUUsWUFBWSxHQUFFLE1BQVUsVUFxQmxHO0FBRUQ7Ozs7R0FJRztBQUNILHdCQUFzQiw2QkFBNkIsQ0FBQyxhQUFhLEVBQUUsTUFBTSxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FFMUY7QUFFRCx3QkFBZ0IsaUJBQWlCLENBQy9CLFFBQVEsRUFBRSxNQUFNLEVBQ2hCLGdCQUFnQixFQUFFLE1BQU0sRUFDeEIsWUFBWSxFQUFFLE1BQU0sRUFDcEIsWUFBWSxDQUFDLEVBQUUsTUFBTSxHQUNwQixVQUFVLEdBQUcsYUFBYSxDQUs1QjtBQUVEOzs7Ozs7R0FNRztBQUNILHdCQUFnQixxQkFBcUIsQ0FBQyxjQUFjLEVBQUUsTUFBTSxFQUFFLFlBQVksQ0FBQyxFQUFFLE1BQU0sR0FBRyxVQUFVLENBTS9GO0FBRUQsd0JBQXNCLHFCQUFxQixDQUFDLEtBQUssRUFBRSxvQkFBb0I7OztHQWdGdEU7QUFFRCx3QkFBc0IseUJBQXlCLENBQUMsT0FBTyxDQUFDLEVBQUUsTUFBTSxFQUFFLElBQUksQ0FBQyxFQUFFLE1BQU07OztHQW9COUU7QUFFRCx3QkFBc0IsaUJBQWlCLENBQUMsSUFBSSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsT0FBTyxpQkFHdEU7QUFFRCx3QkFBZ0IscUJBQXFCLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsZ0JBQWdCLEVBQUUsUUFnQzlFO0FBRUQscUdBQXFHO0FBQ3JHLHdCQUFnQixtQkFBbUIsQ0FBQyxTQUFTLEVBQUUsZ0JBQWdCLEVBQUU7Ozs7OztJQVVoRTtBQUVELDBGQUEwRjtBQUMxRix3QkFBZ0IscUJBQXFCLENBQUMsU0FBUyxFQUFFLGdCQUFnQixFQUFFLEdBQUcsR0FBRyxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FFeEY7QUFFRCx3QkFBZ0IsY0FBYyxDQUFDLEdBQUcsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLE9BQU8sR0FBRyxTQUFTLEVBQUUsR0FBRyxFQUFFLE9BQU8sUUFJckY7QUFFRDs7Ozs7Ozs7Ozs7R0FXRztBQUNILHdCQUFzQixxQkFBcUIsQ0FDekMsTUFBTSxFQUFFLE1BQU0sRUFDZCxZQUFZLEVBQUUsTUFBTSxFQUNwQixRQUFRLEVBQUUsTUFBTSxFQUNoQixhQUFhLEVBQUUsTUFBTSxFQUNyQixTQUFTLEVBQUUsTUFBTSxFQUNqQixjQUFjLEVBQUUsTUFBTSxHQUNyQixPQUFPLENBQUMsTUFBTSxDQUFDLENBU2pCO0FBRUQ7Ozs7R0FJRztBQUNILHdCQUFzQixtQkFBbUIsQ0FDdkMsVUFBVSxFQUFFLGlCQUFpQixFQUFFLEVBQy9CLE9BQU8sRUFBRTtJQUFFLE1BQU0sRUFBRSxNQUFNLENBQUM7SUFBQyxRQUFRLEVBQUUsTUFBTSxDQUFDO0lBQUMsZUFBZSxDQUFDLEVBQUUsR0FBRyxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQTtDQUFFLEdBQ25GLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0F3QmY7QUFFRCw4RUFBOEU7QUFDOUUsd0JBQXNCLHNCQUFzQixDQUMxQyxNQUFNLEVBQUUsTUFBTSxFQUNkLFlBQVksRUFBRSxNQUFNLEVBQ3BCLFFBQVEsRUFBRSxNQUFNLEVBQ2hCLGFBQWEsRUFBRSxNQUFNLEdBQ3BCLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FPakI7QUFlRCxtSEFBbUg7QUFDbkgsd0JBQXNCLDJCQUEyQixDQUMvQyxPQUFPLEVBQUUsVUFBVSxFQUNuQixPQUFPLEVBQUU7SUFBRSxNQUFNLEVBQUUsTUFBTSxDQUFDO0lBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBQTtDQUFFLEdBQzVDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FFckI7QUFFRCxrR0FBa0c7QUFDbEcsd0JBQXNCLG9CQUFvQixDQUN4QyxVQUFVLEVBQUUsaUJBQWlCLEVBQUUsRUFDL0IsT0FBTyxFQUFFO0lBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQztJQUFDLFFBQVEsRUFBRSxNQUFNLENBQUE7Q0FBRSxHQUM1QyxPQUFPLENBQUMsSUFBSSxDQUFDLENBeUNmIn0=
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/cmds/validator_keys/shared.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAChE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/cmds/validator_keys/shared.ts"],"names":[],"mappings":"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"}
|