@aztec/node-keystore 2.1.9 → 2.1.11

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.
@@ -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;IAc3D,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;IAWnF;;OAEG;IACH,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,YAAY;IAKrD;;;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"}
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"}
@@ -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
- return validator.feeRecipient;
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.
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAWA,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,CA+E9D"}
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 { createLogger } from '@aztec/foundation/log';
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: 1,
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 = extractAttesterKeys(validator.attester);
183
- for (const key of attesterKeys){
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 extractAttesterKeys(attester) {
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
- return [
242
- attester
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(...extractAttesterKeys(item));
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 extractAttesterKeys(obj.eth);
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
- // Fallback stringify for anything else (null/undefined)
271
- return [
272
- JSON.stringify(attester)
273
- ];
328
+ // mnemonic, encrypted file just disable early duplicates checking
329
+ return [];
274
330
  }