@aztec/node-keystore 0.0.1-commit.9b94fc1 → 0.0.1-commit.9ee6fcc6
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 +8 -6
- package/dest/keystore_manager.d.ts.map +1 -1
- package/dest/keystore_manager.js +36 -11
- package/dest/loader.d.ts +1 -1
- package/dest/loader.d.ts.map +1 -1
- package/dest/loader.js +76 -20
- package/dest/schemas.d.ts +2070 -124
- package/dest/schemas.d.ts.map +1 -1
- package/dest/schemas.js +49 -5
- package/dest/signer.d.ts +2 -2
- package/dest/signer.d.ts.map +1 -1
- package/dest/signer.js +7 -6
- package/dest/types.d.ts +13 -6
- package/dest/types.d.ts.map +1 -1
- package/package.json +9 -7
- package/src/keystore_manager.ts +53 -12
- package/src/loader.ts +77 -13
- package/src/schemas.ts +54 -5
- package/src/signer.ts +8 -11
- package/src/types.ts +12 -5
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Manages keystore configuration and delegates signing operations to appropriate signers.
|
|
5
5
|
*/
|
|
6
|
-
import type { EthSigner } from '@aztec/ethereum';
|
|
6
|
+
import type { EthSigner } from '@aztec/ethereum/eth-signer';
|
|
7
7
|
import { Buffer32 } from '@aztec/foundation/buffer';
|
|
8
8
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
9
9
|
import type { Signature } from '@aztec/foundation/eth-signature';
|
|
@@ -30,7 +30,7 @@ export declare class KeystoreManager {
|
|
|
30
30
|
constructor(keystore: KeyStore);
|
|
31
31
|
/**
|
|
32
32
|
* Validates all remote signers in the keystore are accessible and have the required addresses.
|
|
33
|
-
*
|
|
33
|
+
* Retries each web3signer URL with backoff to tolerate transient unavailability at boot time.
|
|
34
34
|
*/
|
|
35
35
|
validateSigners(): Promise<void>;
|
|
36
36
|
/**
|
|
@@ -54,10 +54,12 @@ 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[];
|
|
61
|
+
/** Create a signer for the top-level funding account, if configured. */
|
|
62
|
+
createFundingSigner(): EthSigner | undefined;
|
|
61
63
|
/**
|
|
62
64
|
* Create signers for slasher accounts
|
|
63
65
|
*/
|
|
@@ -78,11 +80,11 @@ export declare class KeystoreManager {
|
|
|
78
80
|
*/
|
|
79
81
|
getValidatorCount(): number;
|
|
80
82
|
/**
|
|
81
|
-
* Get coinbase address for validator (falls back to the specific attester address)
|
|
83
|
+
* Get coinbase address for validator (falls back to keystore-level coinbase, then to the specific attester address)
|
|
82
84
|
*/
|
|
83
85
|
getCoinbaseAddress(validatorIndex: number, attesterAddress: EthAddress): EthAddress;
|
|
84
86
|
/**
|
|
85
|
-
* Get fee recipient for validator
|
|
87
|
+
* Get fee recipient for validator (falls back to keystore-level feeRecipient)
|
|
86
88
|
*/
|
|
87
89
|
getFeeRecipient(validatorIndex: number): AztecAddress;
|
|
88
90
|
/**
|
|
@@ -136,4 +138,4 @@ export declare class KeystoreManager {
|
|
|
136
138
|
/** Extract ETH accounts from AttesterAccounts */
|
|
137
139
|
private extractEthAccountsFromAttester;
|
|
138
140
|
}
|
|
139
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
141
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia2V5c3RvcmVfbWFuYWdlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2tleXN0b3JlX21hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7R0FJRztBQUNILE9BQU8sS0FBSyxFQUFFLFNBQVMsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQzVELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDM0QsT0FBTyxLQUFLLEVBQUUsU0FBUyxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFakUsT0FBTyxLQUFLLEVBQUUsWUFBWSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFLaEUsT0FBTyxLQUFLLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFLaEQsT0FBTyxLQUFLLEVBSVYsV0FBVyxFQUVYLHFCQUFxQixFQUNyQixRQUFRLEVBRVIsY0FBYyxFQUNkLGlCQUFpQixJQUFJLHVCQUF1QixFQUM3QyxNQUFNLFlBQVksQ0FBQztBQUVwQjs7R0FFRztBQUNILHFCQUFhLGFBQWMsU0FBUSxLQUFLO0lBR3BCLEtBQUssQ0FBQztJQUZ4QixZQUNFLE9BQU8sRUFBRSxNQUFNLEVBQ0MsS0FBSyxDQUFDLG1CQUFPLEVBSTlCO0NBQ0Y7QUFFRDs7R0FFRztBQUNILHFCQUFhLGVBQWU7SUFDMUIsT0FBTyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQVc7SUFFcEM7Ozs7T0FJRztJQUNILFlBQVksUUFBUSxFQUFFLFFBQVEsRUFHN0I7SUFFRDs7O09BR0c7SUFDRyxlQUFlLElBQUksT0FBTyxDQUFDLElBQUksQ0FBQyxDQTRFckM7SUFFRDs7Ozs7T0FLRztJQUNILE9BQU8sQ0FBQywrQkFBK0I7SUFrQnZDOzs7T0FHRztJQUNILE9BQU8sQ0FBQywwQ0FBMEM7SUFLbEQ7O09BRUc7SUFDSCxPQUFPLENBQUMsMkNBQTJDO0lBK0NuRDs7T0FFRztJQUNILHFCQUFxQixDQUFDLGNBQWMsRUFBRSxNQUFNLEdBQUcsU0FBUyxFQUFFLENBSXpEO0lBRUQ7O09BRUc7SUFDSCxzQkFBc0IsQ0FBQyxjQUFjLEVBQUUsTUFBTSxHQUFHLFNBQVMsRUFBRSxDQW9CMUQ7SUFFRCxrQ0FBa0MsSUFBSSxTQUFTLEVBQUUsQ0FTaEQ7SUFFRCx3RUFBd0U7SUFDeEUsbUJBQW1CLElBQUksU0FBUyxHQUFHLFNBQVMsQ0FNM0M7SUFFRDs7T0FFRztJQUNILG9CQUFvQixJQUFJLFNBQVMsRUFBRSxDQU1sQztJQUVEOztPQUVHO0lBQ0gsbUJBQW1CLElBQUk7UUFBRSxFQUFFLEVBQUUsVUFBVSxHQUFHLFNBQVMsQ0FBQztRQUFDLE9BQU8sRUFBRSxTQUFTLEVBQUUsQ0FBQTtLQUFFLEdBQUcsU0FBUyxDQStCdEY7SUFFRDs7T0FFRztJQUNILFlBQVksQ0FBQyxLQUFLLEVBQUUsTUFBTSxHQUFHLHVCQUF1QixDQUtuRDtJQUVEOztPQUVHO0lBQ0gsaUJBQWlCLElBQUksTUFBTSxDQUUxQjtJQUVEOztPQUVHO0lBQ0gsa0JBQWtCLENBQUMsY0FBYyxFQUFFLE1BQU0sRUFBRSxlQUFlLEVBQUUsVUFBVSxHQUFHLFVBQVUsQ0FjbEY7SUFFRDs7T0FFRztJQUNILGVBQWUsQ0FBQyxjQUFjLEVBQUUsTUFBTSxHQUFHLFlBQVksQ0FlcEQ7SUFFRDs7O09BR0c7SUFDSCxrQkFBa0IsSUFBSSxXQUFXLEdBQUcsU0FBUyxDQUU1QztJQUVEOzs7T0FHRztJQUNILGVBQWUsSUFBSSxjQUFjLEdBQUcsU0FBUyxDQUU1QztJQUVEOzs7T0FHRztJQUNILHVDQUF1QyxJQUFJLElBQUksQ0FtQjlDO0lBRUQ7O09BRUc7SUFDSCxPQUFPLENBQUMsNEJBQTRCO0lBK0JwQzs7T0FFRztJQUNILE9BQU8sQ0FBQywwQkFBMEI7SUEyQ2xDOztPQUVHO0lBQ0gsT0FBTyxDQUFDLHNCQUFzQjtJQWtEOUI7O09BRUc7SUFDSCxPQUFPLENBQUMsZ0NBQWdDO0lBd0J4Qzs7T0FFRztJQUNILE9BQU8sQ0FBQyx5QkFBeUI7SUE4QmpDOztPQUVHO0lBQ0csV0FBVyxDQUFDLE1BQU0sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLFFBQVEsR0FBRyxPQUFPLENBQUMsU0FBUyxDQUFDLENBRTFFO0lBRUQ7O09BRUc7SUFDRyxhQUFhLENBQUMsTUFBTSxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsbUJBQW1CLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUV6RjtJQUVEOzs7T0FHRztJQUNILDhCQUE4QixDQUM1QixjQUFjLEVBQUUsTUFBTSxFQUN0QixlQUFlLEVBQUUsVUFBVSxHQUMxQixxQkFBcUIsR0FBRyxTQUFTLENBd0duQztJQUVELGlEQUFpRDtJQUNqRCxPQUFPLENBQUMsOEJBQThCO0NBeUJ2QyJ9
|
|
@@ -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,
|
|
1
|
+
{"version":3,"file":"keystore_manager.d.ts","sourceRoot":"","sources":["../src/keystore_manager.ts"],"names":[],"mappings":"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"}
|
package/dest/keystore_manager.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Manages keystore configuration and delegates signing operations to appropriate signers.
|
|
5
5
|
*/ import { Buffer32 } from '@aztec/foundation/buffer';
|
|
6
|
+
import { makeBackoff, retry } from '@aztec/foundation/retry';
|
|
6
7
|
import { Wallet } from '@ethersproject/wallet';
|
|
7
8
|
import { readFileSync, readdirSync, statSync } from 'fs';
|
|
8
9
|
import { extname, join } from 'path';
|
|
@@ -32,7 +33,7 @@ import { LocalSigner, RemoteSigner } from './signer.js';
|
|
|
32
33
|
}
|
|
33
34
|
/**
|
|
34
35
|
* Validates all remote signers in the keystore are accessible and have the required addresses.
|
|
35
|
-
*
|
|
36
|
+
* Retries each web3signer URL with backoff to tolerate transient unavailability at boot time.
|
|
36
37
|
*/ async validateSigners() {
|
|
37
38
|
// Collect all remote signers with their addresses grouped by URL
|
|
38
39
|
const remoteSignersByUrl = new Map();
|
|
@@ -87,12 +88,14 @@ import { LocalSigner, RemoteSigner } from './signer.js';
|
|
|
87
88
|
if (this.keystore.prover && typeof this.keystore.prover === 'object' && 'publisher' in this.keystore.prover) {
|
|
88
89
|
collectRemoteSigners(this.keystore.prover.publisher, this.keystore.remoteSigner);
|
|
89
90
|
}
|
|
90
|
-
// Validate each remote signer URL with all its addresses
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
// Validate each remote signer URL with all its addresses, retrying on transient failures
|
|
92
|
+
await Promise.all(Array.from(remoteSignersByUrl.entries()).filter(([, addresses])=>addresses.size > 0).map(([url, addresses])=>retry(()=>RemoteSigner.validateAccess(url, Array.from(addresses)), `Validating web3signer at ${url}`, makeBackoff([
|
|
93
|
+
1,
|
|
94
|
+
2,
|
|
95
|
+
4,
|
|
96
|
+
8,
|
|
97
|
+
16
|
|
98
|
+
]))));
|
|
96
99
|
}
|
|
97
100
|
/**
|
|
98
101
|
* Validates that attester addresses are unique across all validators
|
|
@@ -170,12 +173,16 @@ import { LocalSigner, RemoteSigner } from './signer.js';
|
|
|
170
173
|
return this.createSignersFromEthAccounts(ethAccounts, validator.remoteSigner || this.keystore.remoteSigner);
|
|
171
174
|
}
|
|
172
175
|
/**
|
|
173
|
-
* Create signers for validator publisher accounts (falls back to attester if not specified)
|
|
176
|
+
* Create signers for validator publisher accounts (falls back to keystore-level publisher, then to attester if not specified)
|
|
174
177
|
*/ createPublisherSigners(validatorIndex) {
|
|
175
178
|
const validator = this.getValidator(validatorIndex);
|
|
176
179
|
if (validator.publisher) {
|
|
177
180
|
return this.createSignersFromEthAccounts(validator.publisher, validator.remoteSigner || this.keystore.remoteSigner);
|
|
178
181
|
}
|
|
182
|
+
// Fall back to keystore-level publisher
|
|
183
|
+
if (this.keystore.publisher) {
|
|
184
|
+
return this.createSignersFromEthAccounts(this.keystore.publisher, validator.remoteSigner || this.keystore.remoteSigner);
|
|
185
|
+
}
|
|
179
186
|
// Fall back to attester signers
|
|
180
187
|
return this.createAttesterSigners(validatorIndex);
|
|
181
188
|
}
|
|
@@ -187,6 +194,13 @@ import { LocalSigner, RemoteSigner } from './signer.js';
|
|
|
187
194
|
}
|
|
188
195
|
return allPublishers;
|
|
189
196
|
}
|
|
197
|
+
/** Create a signer for the top-level funding account, if configured. */ createFundingSigner() {
|
|
198
|
+
const fundingAccount = this.keystore.fundingAccount;
|
|
199
|
+
if (!fundingAccount) {
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
return this.createSignerFromEthAccount(fundingAccount, this.keystore.remoteSigner);
|
|
203
|
+
}
|
|
190
204
|
/**
|
|
191
205
|
* Create signers for slasher accounts
|
|
192
206
|
*/ createSlasherSigners() {
|
|
@@ -239,20 +253,31 @@ import { LocalSigner, RemoteSigner } from './signer.js';
|
|
|
239
253
|
return this.keystore.validators?.length || 0;
|
|
240
254
|
}
|
|
241
255
|
/**
|
|
242
|
-
* Get coinbase address for validator (falls back to the specific attester address)
|
|
256
|
+
* Get coinbase address for validator (falls back to keystore-level coinbase, then to the specific attester address)
|
|
243
257
|
*/ getCoinbaseAddress(validatorIndex, attesterAddress) {
|
|
244
258
|
const validator = this.getValidator(validatorIndex);
|
|
245
259
|
if (validator.coinbase) {
|
|
246
260
|
return validator.coinbase;
|
|
247
261
|
}
|
|
262
|
+
// Fall back to keystore-level coinbase
|
|
263
|
+
if (this.keystore.coinbase) {
|
|
264
|
+
return this.keystore.coinbase;
|
|
265
|
+
}
|
|
248
266
|
// Fall back to the specific attester address
|
|
249
267
|
return attesterAddress;
|
|
250
268
|
}
|
|
251
269
|
/**
|
|
252
|
-
* Get fee recipient for validator
|
|
270
|
+
* Get fee recipient for validator (falls back to keystore-level feeRecipient)
|
|
253
271
|
*/ getFeeRecipient(validatorIndex) {
|
|
254
272
|
const validator = this.getValidator(validatorIndex);
|
|
255
|
-
|
|
273
|
+
if (validator.feeRecipient) {
|
|
274
|
+
return validator.feeRecipient;
|
|
275
|
+
}
|
|
276
|
+
// Fall back to keystore-level feeRecipient
|
|
277
|
+
if (this.keystore.feeRecipient) {
|
|
278
|
+
return this.keystore.feeRecipient;
|
|
279
|
+
}
|
|
280
|
+
throw new KeystoreError(`No feeRecipient configured for validator ${validatorIndex}. You can set it at validator or keystore level.`);
|
|
256
281
|
}
|
|
257
282
|
/**
|
|
258
283
|
* Get the raw slasher configuration as provided in the keystore file.
|
package/dest/loader.d.ts
CHANGED
|
@@ -59,4 +59,4 @@ export declare function loadMultipleKeystores(paths: string | string[]): KeyStor
|
|
|
59
59
|
* @throws KeyStoreLoadError When duplicate attester keys are found or multiple prover configs exist.
|
|
60
60
|
*/
|
|
61
61
|
export declare function mergeKeystores(keystores: KeyStore[]): KeyStore;
|
|
62
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
62
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9hZGVyLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvbG9hZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQWNBLE9BQU8sS0FBSyxFQUFlLFFBQVEsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUl4RDs7R0FFRztBQUNILHFCQUFhLGlCQUFrQixTQUFRLEtBQUs7SUFHakMsUUFBUSxFQUFFLE1BQU07SUFDUCxLQUFLLENBQUM7SUFIeEIsWUFDRSxPQUFPLEVBQUUsTUFBTSxFQUNSLFFBQVEsRUFBRSxNQUFNLEVBQ1AsS0FBSyxDQUFDLG1CQUFPLEVBSTlCO0NBQ0Y7QUFFRDs7Ozs7O0dBTUc7QUFDSCx3QkFBZ0IsZ0JBQWdCLENBQUMsUUFBUSxFQUFFLE1BQU0sR0FBRyxRQUFRLENBdUIzRDtBQUVEOzs7Ozs7R0FNRztBQUNILHdCQUFnQixxQkFBcUIsQ0FBQyxPQUFPLEVBQUUsTUFBTSxHQUFHLFFBQVEsRUFBRSxDQW1DakU7QUFFRDs7Ozs7Ozs7O0dBU0c7QUFDSCx3QkFBZ0IsYUFBYSxDQUFDLElBQUksRUFBRSxNQUFNLEdBQUcsUUFBUSxFQUFFLENBdUJ0RDtBQUVEOzs7Ozs7R0FNRztBQUNILHdCQUFnQixxQkFBcUIsQ0FBQyxLQUFLLEVBQUUsTUFBTSxHQUFHLE1BQU0sRUFBRSxHQUFHLFFBQVEsRUFBRSxDQThCMUU7QUFFRDs7Ozs7Ozs7Ozs7Ozs7O0dBZUc7QUFDSCx3QkFBZ0IsY0FBYyxDQUFDLFNBQVMsRUFBRSxRQUFRLEVBQUUsR0FBRyxRQUFRLENBdUk5RCJ9
|
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;IAHxB,YACE,OAAO,EAAE,MAAM,EACR,QAAQ,EAAE,MAAM,EACP,KAAK,CAAC,mBAAO,EAI9B;CACF;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
|
}
|