@aztec/node-keystore 2.1.9 → 2.1.11-rc.2
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/keystore_manager.d.ts +3 -3
- package/dest/keystore_manager.d.ts.map +1 -1
- package/dest/keystore_manager.js +19 -4
- package/dest/loader.d.ts.map +1 -1
- package/dest/loader.js +76 -20
- package/dest/schemas.d.ts +1948 -2
- package/dest/schemas.d.ts.map +1 -1
- package/dest/schemas.js +49 -5
- package/dest/signer.d.ts.map +1 -1
- package/dest/signer.js +5 -5
- package/dest/types.d.ts +12 -5
- package/dest/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/keystore_manager.ts +29 -4
- package/src/loader.ts +77 -13
- package/src/schemas.ts +54 -5
- package/src/signer.ts +5 -9
- package/src/types.ts +12 -5
|
@@ -54,7 +54,7 @@ export declare class KeystoreManager {
|
|
|
54
54
|
*/
|
|
55
55
|
createAttesterSigners(validatorIndex: number): EthSigner[];
|
|
56
56
|
/**
|
|
57
|
-
* Create signers for validator publisher accounts (falls back to attester if not specified)
|
|
57
|
+
* Create signers for validator publisher accounts (falls back to keystore-level publisher, then to attester if not specified)
|
|
58
58
|
*/
|
|
59
59
|
createPublisherSigners(validatorIndex: number): EthSigner[];
|
|
60
60
|
createAllValidatorPublisherSigners(): EthSigner[];
|
|
@@ -78,11 +78,11 @@ export declare class KeystoreManager {
|
|
|
78
78
|
*/
|
|
79
79
|
getValidatorCount(): number;
|
|
80
80
|
/**
|
|
81
|
-
* Get coinbase address for validator (falls back to the specific attester address)
|
|
81
|
+
* Get coinbase address for validator (falls back to keystore-level coinbase, then to the specific attester address)
|
|
82
82
|
*/
|
|
83
83
|
getCoinbaseAddress(validatorIndex: number, attesterAddress: EthAddress): EthAddress;
|
|
84
84
|
/**
|
|
85
|
-
* Get fee recipient for validator
|
|
85
|
+
* Get fee recipient for validator (falls back to keystore-level feeRecipient)
|
|
86
86
|
*/
|
|
87
87
|
getFeeRecipient(validatorIndex: number): AztecAddress;
|
|
88
88
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keystore_manager.d.ts","sourceRoot":"","sources":["../src/keystore_manager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAKhE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAKhD,OAAO,KAAK,EAIV,WAAW,EAEX,qBAAqB,EACrB,QAAQ,EAER,cAAc,EACd,iBAAiB,IAAI,uBAAuB,EAC7C,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;IAGpB,KAAK,CAAC,EAAE,KAAK;gBAD7B,OAAO,EAAE,MAAM,EACC,KAAK,CAAC,EAAE,KAAK,YAAA;CAKhC;AAED;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;IAEpC;;;;OAIG;gBACS,QAAQ,EAAE,QAAQ;IAK9B;;;OAGG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAwEtC;;;;;OAKG;IACH,OAAO,CAAC,+BAA+B;IAkBvC;;;OAGG;IACH,OAAO,CAAC,0CAA0C;IAKlD;;OAEG;IACH,OAAO,CAAC,2CAA2C;IA+CnD;;OAEG;IACH,qBAAqB,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,EAAE;IAM1D;;OAEG;IACH,sBAAsB,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,EAAE;
|
|
1
|
+
{"version":3,"file":"keystore_manager.d.ts","sourceRoot":"","sources":["../src/keystore_manager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAKhE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAKhD,OAAO,KAAK,EAIV,WAAW,EAEX,qBAAqB,EACrB,QAAQ,EAER,cAAc,EACd,iBAAiB,IAAI,uBAAuB,EAC7C,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,qBAAa,aAAc,SAAQ,KAAK;IAGpB,KAAK,CAAC,EAAE,KAAK;gBAD7B,OAAO,EAAE,MAAM,EACC,KAAK,CAAC,EAAE,KAAK,YAAA;CAKhC;AAED;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAW;IAEpC;;;;OAIG;gBACS,QAAQ,EAAE,QAAQ;IAK9B;;;OAGG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAwEtC;;;;;OAKG;IACH,OAAO,CAAC,+BAA+B;IAkBvC;;;OAGG;IACH,OAAO,CAAC,0CAA0C;IAKlD;;OAEG;IACH,OAAO,CAAC,2CAA2C;IA+CnD;;OAEG;IACH,qBAAqB,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,EAAE;IAM1D;;OAEG;IACH,sBAAsB,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,EAAE;IAsB3D,kCAAkC,IAAI,SAAS,EAAE;IAWjD;;OAEG;IACH,oBAAoB,IAAI,SAAS,EAAE;IAQnC;;OAEG;IACH,mBAAmB,IAAI;QAAE,EAAE,EAAE,UAAU,GAAG,SAAS,CAAC;QAAC,OAAO,EAAE,SAAS,EAAE,CAAA;KAAE,GAAG,SAAS;IAiCvF;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,uBAAuB;IAOpD;;OAEG;IACH,iBAAiB,IAAI,MAAM;IAI3B;;OAEG;IACH,kBAAkB,CAAC,cAAc,EAAE,MAAM,EAAE,eAAe,EAAE,UAAU,GAAG,UAAU;IAgBnF;;OAEG;IACH,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,YAAY;IAiBrD;;;OAGG;IACH,kBAAkB,IAAI,WAAW,GAAG,SAAS;IAI7C;;;OAGG;IACH,eAAe,IAAI,cAAc,GAAG,SAAS;IAI7C;;;OAGG;IACH,uCAAuC,IAAI,IAAI;IAqB/C;;OAEG;IACH,OAAO,CAAC,4BAA4B;IA+BpC;;OAEG;IACH,OAAO,CAAC,0BAA0B;IA2ClC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAkD9B;;OAEG;IACH,OAAO,CAAC,gCAAgC;IAwBxC;;OAEG;IACH,OAAO,CAAC,yBAAyB;IA8BjC;;OAEG;IACG,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;IAI3E;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,SAAS,CAAC;IAI1F;;;OAGG;IACH,8BAA8B,CAC5B,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,UAAU,GAC1B,qBAAqB,GAAG,SAAS;IA0GpC,iDAAiD;IACjD,OAAO,CAAC,8BAA8B;CAyBvC"}
|
package/dest/keystore_manager.js
CHANGED
|
@@ -170,12 +170,16 @@ import { LocalSigner, RemoteSigner } from './signer.js';
|
|
|
170
170
|
return this.createSignersFromEthAccounts(ethAccounts, validator.remoteSigner || this.keystore.remoteSigner);
|
|
171
171
|
}
|
|
172
172
|
/**
|
|
173
|
-
* Create signers for validator publisher accounts (falls back to attester if not specified)
|
|
173
|
+
* Create signers for validator publisher accounts (falls back to keystore-level publisher, then to attester if not specified)
|
|
174
174
|
*/ createPublisherSigners(validatorIndex) {
|
|
175
175
|
const validator = this.getValidator(validatorIndex);
|
|
176
176
|
if (validator.publisher) {
|
|
177
177
|
return this.createSignersFromEthAccounts(validator.publisher, validator.remoteSigner || this.keystore.remoteSigner);
|
|
178
178
|
}
|
|
179
|
+
// Fall back to keystore-level publisher
|
|
180
|
+
if (this.keystore.publisher) {
|
|
181
|
+
return this.createSignersFromEthAccounts(this.keystore.publisher, validator.remoteSigner || this.keystore.remoteSigner);
|
|
182
|
+
}
|
|
179
183
|
// Fall back to attester signers
|
|
180
184
|
return this.createAttesterSigners(validatorIndex);
|
|
181
185
|
}
|
|
@@ -239,20 +243,31 @@ import { LocalSigner, RemoteSigner } from './signer.js';
|
|
|
239
243
|
return this.keystore.validators?.length || 0;
|
|
240
244
|
}
|
|
241
245
|
/**
|
|
242
|
-
* Get coinbase address for validator (falls back to the specific attester address)
|
|
246
|
+
* Get coinbase address for validator (falls back to keystore-level coinbase, then to the specific attester address)
|
|
243
247
|
*/ getCoinbaseAddress(validatorIndex, attesterAddress) {
|
|
244
248
|
const validator = this.getValidator(validatorIndex);
|
|
245
249
|
if (validator.coinbase) {
|
|
246
250
|
return validator.coinbase;
|
|
247
251
|
}
|
|
252
|
+
// Fall back to keystore-level coinbase
|
|
253
|
+
if (this.keystore.coinbase) {
|
|
254
|
+
return this.keystore.coinbase;
|
|
255
|
+
}
|
|
248
256
|
// Fall back to the specific attester address
|
|
249
257
|
return attesterAddress;
|
|
250
258
|
}
|
|
251
259
|
/**
|
|
252
|
-
* Get fee recipient for validator
|
|
260
|
+
* Get fee recipient for validator (falls back to keystore-level feeRecipient)
|
|
253
261
|
*/ getFeeRecipient(validatorIndex) {
|
|
254
262
|
const validator = this.getValidator(validatorIndex);
|
|
255
|
-
|
|
263
|
+
if (validator.feeRecipient) {
|
|
264
|
+
return validator.feeRecipient;
|
|
265
|
+
}
|
|
266
|
+
// Fall back to keystore-level feeRecipient
|
|
267
|
+
if (this.keystore.feeRecipient) {
|
|
268
|
+
return this.keystore.feeRecipient;
|
|
269
|
+
}
|
|
270
|
+
throw new KeystoreError(`No feeRecipient configured for validator ${validatorIndex}. You can set it at validator or keystore level.`);
|
|
256
271
|
}
|
|
257
272
|
/**
|
|
258
273
|
* Get the raw slasher configuration as provided in the keystore file.
|
package/dest/loader.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAe,QAAQ,EAAE,MAAM,YAAY,CAAC;AAIxD;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAGjC,QAAQ,EAAE,MAAM;IACP,KAAK,CAAC,EAAE,KAAK;gBAF7B,OAAO,EAAE,MAAM,EACR,QAAQ,EAAE,MAAM,EACP,KAAK,CAAC,EAAE,KAAK,YAAA;CAKhC;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,CAuB3D;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,EAAE,CAmCjE;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,CAuBtD;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,QAAQ,EAAE,CA8B1E;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,QAAQ,CAuI9D"}
|
package/dest/loader.js
CHANGED
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
* Keystore File Loader
|
|
3
3
|
*
|
|
4
4
|
* Handles loading and parsing keystore configuration files.
|
|
5
|
-
*/ import {
|
|
5
|
+
*/ import { EthAddress } from '@aztec/foundation/eth-address';
|
|
6
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
6
7
|
import { readFileSync, readdirSync, statSync } from 'fs';
|
|
7
8
|
import { extname, join } from 'path';
|
|
9
|
+
import { privateKeyToAddress } from 'viem/accounts';
|
|
8
10
|
import { keystoreSchema } from './schemas.js';
|
|
9
11
|
const logger = createLogger('node-keystore:loader');
|
|
10
12
|
/**
|
|
@@ -166,12 +168,17 @@ const logger = createLogger('node-keystore:loader');
|
|
|
166
168
|
}
|
|
167
169
|
// Track attester addresses to prevent duplicates
|
|
168
170
|
const attesterAddresses = new Set();
|
|
171
|
+
// Determine schema version: use v2 if any input is v2
|
|
172
|
+
const schemaVersion = keystores.some((ks)=>ks.schemaVersion === 2) ? 2 : 1;
|
|
169
173
|
const merged = {
|
|
170
|
-
schemaVersion
|
|
174
|
+
schemaVersion,
|
|
171
175
|
validators: [],
|
|
172
176
|
slasher: undefined,
|
|
173
177
|
remoteSigner: undefined,
|
|
174
|
-
prover: undefined
|
|
178
|
+
prover: undefined,
|
|
179
|
+
publisher: undefined,
|
|
180
|
+
coinbase: undefined,
|
|
181
|
+
feeRecipient: undefined
|
|
175
182
|
};
|
|
176
183
|
for(let i = 0; i < keystores.length; i++){
|
|
177
184
|
const keystore = keystores[i];
|
|
@@ -179,15 +186,22 @@ const logger = createLogger('node-keystore:loader');
|
|
|
179
186
|
if (keystore.validators) {
|
|
180
187
|
for (const validator of keystore.validators){
|
|
181
188
|
// Check for duplicate attester addresses
|
|
182
|
-
const attesterKeys =
|
|
183
|
-
for (
|
|
189
|
+
const attesterKeys = extractAttesterAddresses(validator.attester);
|
|
190
|
+
for (let key of attesterKeys){
|
|
191
|
+
key = key.toLowerCase();
|
|
184
192
|
if (attesterAddresses.has(key)) {
|
|
185
193
|
throw new KeyStoreLoadError(`Duplicate attester address ${key} found across keystore files`, `keystores[${i}].validators`);
|
|
186
194
|
}
|
|
187
195
|
attesterAddresses.add(key);
|
|
188
196
|
}
|
|
197
|
+
// When merging v1 validators into a v2+ result, preserve original fallback behavior
|
|
198
|
+
// by explicitly setting publisher/coinbase/feeRecipient if they're missing
|
|
199
|
+
if (keystore.schemaVersion !== schemaVersion) {
|
|
200
|
+
throw new KeyStoreLoadError(`Cannot merge keystores with different schema versions: ${keystore.schemaVersion} and ${schemaVersion}`, `keystores[${i}].schemaVersion`);
|
|
201
|
+
} else {
|
|
202
|
+
merged.validators.push(validator);
|
|
203
|
+
}
|
|
189
204
|
}
|
|
190
|
-
merged.validators.push(...keystore.validators);
|
|
191
205
|
}
|
|
192
206
|
// Merge slasher (accumulate all)
|
|
193
207
|
if (keystore.slasher) {
|
|
@@ -219,6 +233,43 @@ const logger = createLogger('node-keystore:loader');
|
|
|
219
233
|
}
|
|
220
234
|
merged.prover = keystore.prover;
|
|
221
235
|
}
|
|
236
|
+
// Merge top-level publisher (accumulate all, unless conflicting MnemonicConfigs)
|
|
237
|
+
if (keystore.publisher) {
|
|
238
|
+
if (!merged.publisher) {
|
|
239
|
+
merged.publisher = keystore.publisher;
|
|
240
|
+
} else {
|
|
241
|
+
const isMnemonic = (accounts)=>typeof accounts === 'object' && accounts !== null && 'mnemonic' in accounts;
|
|
242
|
+
// If either is a mnemonic, warn and use last one (can't merge mnemonics)
|
|
243
|
+
if (isMnemonic(merged.publisher) || isMnemonic(keystore.publisher)) {
|
|
244
|
+
logger.warn('Multiple default publisher configurations found with mnemonic, using the last one (cannot merge mnemonics)');
|
|
245
|
+
merged.publisher = keystore.publisher;
|
|
246
|
+
} else {
|
|
247
|
+
// Both are non-mnemonic, accumulate them
|
|
248
|
+
const toArray = (accounts)=>Array.isArray(accounts) ? accounts : [
|
|
249
|
+
accounts
|
|
250
|
+
];
|
|
251
|
+
const combined = [
|
|
252
|
+
...toArray(merged.publisher),
|
|
253
|
+
...toArray(keystore.publisher)
|
|
254
|
+
];
|
|
255
|
+
merged.publisher = combined;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// Merge top-level coinbase (last one wins, but warn about conflicts)
|
|
260
|
+
if (keystore.coinbase) {
|
|
261
|
+
if (merged.coinbase) {
|
|
262
|
+
logger.warn('Multiple default coinbase addresses found, using the last one');
|
|
263
|
+
}
|
|
264
|
+
merged.coinbase = keystore.coinbase;
|
|
265
|
+
}
|
|
266
|
+
// Merge top-level feeRecipient (last one wins, but warn about conflicts)
|
|
267
|
+
if (keystore.feeRecipient) {
|
|
268
|
+
if (merged.feeRecipient) {
|
|
269
|
+
logger.warn('Multiple default feeRecipient addresses found, using the last one');
|
|
270
|
+
}
|
|
271
|
+
merged.feeRecipient = keystore.feeRecipient;
|
|
272
|
+
}
|
|
222
273
|
}
|
|
223
274
|
// Clean up empty arrays
|
|
224
275
|
if (merged.validators.length === 0) {
|
|
@@ -235,26 +286,37 @@ const logger = createLogger('node-keystore:loader');
|
|
|
235
286
|
*
|
|
236
287
|
* @param attester The attester configuration in any supported shape.
|
|
237
288
|
* @returns Array of string keys used to detect duplicates.
|
|
238
|
-
*/ function
|
|
289
|
+
*/ function extractAttesterAddresses(attester) {
|
|
239
290
|
// String forms (private key or other) - return as-is for coarse uniqueness
|
|
240
291
|
if (typeof attester === 'string') {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
292
|
+
if (attester.length === 66) {
|
|
293
|
+
return [
|
|
294
|
+
privateKeyToAddress(attester)
|
|
295
|
+
];
|
|
296
|
+
} else {
|
|
297
|
+
return [
|
|
298
|
+
attester
|
|
299
|
+
];
|
|
300
|
+
}
|
|
244
301
|
}
|
|
245
302
|
// Arrays of attester items
|
|
246
303
|
if (Array.isArray(attester)) {
|
|
247
304
|
const keys = [];
|
|
248
305
|
for (const item of attester){
|
|
249
|
-
keys.push(...
|
|
306
|
+
keys.push(...extractAttesterAddresses(item));
|
|
250
307
|
}
|
|
251
308
|
return keys;
|
|
252
309
|
}
|
|
253
310
|
if (attester && typeof attester === 'object') {
|
|
311
|
+
if (attester instanceof EthAddress) {
|
|
312
|
+
return [
|
|
313
|
+
attester.toString()
|
|
314
|
+
];
|
|
315
|
+
}
|
|
254
316
|
const obj = attester;
|
|
255
317
|
// New shape: { eth: EthAccount, bls?: BLSAccount }
|
|
256
318
|
if ('eth' in obj) {
|
|
257
|
-
return
|
|
319
|
+
return extractAttesterAddresses(obj.eth);
|
|
258
320
|
}
|
|
259
321
|
// Remote signer account object shape: { address, remoteSignerUrl?, ... }
|
|
260
322
|
if ('address' in obj) {
|
|
@@ -262,13 +324,7 @@ const logger = createLogger('node-keystore:loader');
|
|
|
262
324
|
String(obj.address)
|
|
263
325
|
];
|
|
264
326
|
}
|
|
265
|
-
// Mnemonic or other object shapes: stringify
|
|
266
|
-
return [
|
|
267
|
-
JSON.stringify(attester)
|
|
268
|
-
];
|
|
269
327
|
}
|
|
270
|
-
//
|
|
271
|
-
return [
|
|
272
|
-
JSON.stringify(attester)
|
|
273
|
-
];
|
|
328
|
+
// mnemonic, encrypted file just disable early duplicates checking
|
|
329
|
+
return [];
|
|
274
330
|
}
|