Skip to content

Commit d0cce81

Browse files
authored
perf(keyring-eth-hd): store computed account address (#373)
Store the computed account address together with the HD node. This should prevent the need to recompute the address when listing accounts or finding an account by its address.
1 parent b3beadc commit d0cce81

1 file changed

Lines changed: 31 additions & 24 deletions

File tree

packages/keyring-eth-hd/src/hd-keyring.ts

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ export type HDKeyringAccountSelectionOptions = {
8181

8282
type SerializedBuffer = ReturnType<Buffer['toJSON']>;
8383

84+
/**
85+
* Wallet storage object that contains both the HDKey and pre-computed address.
86+
*/
87+
type WalletData = {
88+
hdKey: HDKey;
89+
address: Hex;
90+
};
91+
8492
/**
8593
* Checks if the given value is a valid serialized Buffer compatible with
8694
* the return type of `Buffer.toJSON`.
@@ -114,7 +122,7 @@ export class HdKeyring implements Keyring {
114122

115123
hdPath: string = hdPathString;
116124

117-
#wallets: HDKey[] = [];
125+
#wallets: WalletData[] = [];
118126

119127
readonly #cryptographicFunctions?: CryptographicFunctions;
120128

@@ -200,16 +208,21 @@ export class HdKeyring implements Keyring {
200208
}
201209

202210
const oldLen = this.#wallets.length;
203-
const newWallets: HDKey[] = [];
211+
const newWallets: WalletData[] = [];
204212
for (let i = oldLen; i < numberOfAccounts + oldLen; i++) {
205-
const wallet = this.root.deriveChild(i);
206-
newWallets.push(wallet);
207-
this.#wallets.push(wallet);
213+
const hdKey = this.root.deriveChild(i);
214+
assert(hdKey.publicKey, 'Expected public key to be set');
215+
216+
const address = this.#addressFromPublicKey(hdKey.publicKey);
217+
const walletData: WalletData = {
218+
hdKey,
219+
address,
220+
};
221+
222+
newWallets.push(walletData);
223+
this.#wallets.push(walletData);
208224
}
209-
const hexWallets = newWallets.map((wallet) => {
210-
assert(wallet.publicKey, 'Expected public key to be set');
211-
return this.#addressfromPublicKey(wallet.publicKey);
212-
});
225+
const hexWallets = newWallets.map((walletData) => walletData.address);
213226
return Promise.resolve(hexWallets);
214227
}
215228

@@ -219,10 +232,7 @@ export class HdKeyring implements Keyring {
219232
* @returns The addresses of all accounts in the keyring.
220233
*/
221234
async getAccounts(): Promise<Hex[]> {
222-
return this.#wallets.map((wallet) => {
223-
assert(wallet.publicKey, 'Expected public key to be set');
224-
return this.#addressfromPublicKey(wallet.publicKey);
225-
});
235+
return this.#wallets.map((walletData) => walletData.address);
226236
}
227237

228238
/**
@@ -416,17 +426,14 @@ export class HdKeyring implements Keyring {
416426
const address = this.#normalizeAddress(account);
417427
if (
418428
!this.#wallets
419-
.map(
420-
({ publicKey }) => publicKey && this.#addressfromPublicKey(publicKey),
421-
)
429+
.map(({ address: walletAddress }) => walletAddress)
422430
.includes(address)
423431
) {
424432
throw new Error(`Address ${address} not found in this keyring`);
425433
}
426434

427435
this.#wallets = this.#wallets.filter(
428-
({ publicKey }) =>
429-
publicKey && this.#addressfromPublicKey(publicKey) !== address,
436+
({ address: walletAddress }) => walletAddress !== address,
430437
);
431438
}
432439

@@ -572,15 +579,15 @@ export class HdKeyring implements Keyring {
572579
{ withAppKeyOrigin }: HDKeyringAccountSelectionOptions = {},
573580
): HDKey | { privateKey: Buffer; publicKey: Buffer } {
574581
const address = this.#normalizeAddress(account);
575-
const wallet = this.#wallets.find(({ publicKey }) => {
576-
return publicKey && this.#addressfromPublicKey(publicKey) === address;
582+
const walletData = this.#wallets.find(({ address: walletAddress }) => {
583+
return walletAddress === address;
577584
});
578-
if (!wallet) {
585+
if (!walletData) {
579586
throw new Error('HD Keyring - Unable to find matching address.');
580587
}
581588

582589
if (withAppKeyOrigin) {
583-
const { privateKey } = wallet;
590+
const { privateKey } = walletData.hdKey;
584591
assert(privateKey, 'Expected private key to be set');
585592
const appKeyOriginBuffer = Buffer.from(withAppKeyOrigin, 'utf8');
586593
const appKeyBuffer = Buffer.concat([privateKey, appKeyOriginBuffer]);
@@ -589,7 +596,7 @@ export class HdKeyring implements Keyring {
589596
return { privateKey: appKeyPrivateKey, publicKey: appKeyPublicKey };
590597
}
591598

592-
return wallet;
599+
return walletData.hdKey;
593600
}
594601

595602
/**
@@ -626,7 +633,7 @@ export class HdKeyring implements Keyring {
626633
* @param publicKey - The public key of the account.
627634
* @returns The address of the account.
628635
*/
629-
#addressfromPublicKey(publicKey: Uint8Array): Hex {
636+
#addressFromPublicKey(publicKey: Uint8Array): Hex {
630637
return add0x(
631638
bytesToHex(publicToAddress(Buffer.from(publicKey), true)).toLowerCase(),
632639
);

0 commit comments

Comments
 (0)