From 2358784d433fcdbd1cbd00a7fac0d8eadc8a4918 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Wed, 2 Nov 2016 03:15:48 -0700 Subject: [PATCH] wallet: optimize depth syncing. --- lib/wallet/account.js | 171 +++++++++++++++++++++++++++--------------- lib/wallet/wallet.js | 11 ++- 2 files changed, 119 insertions(+), 63 deletions(-) diff --git a/lib/wallet/account.js b/lib/wallet/account.js index 6816151e..e90bbd9f 100644 --- a/lib/wallet/account.js +++ b/lib/wallet/account.js @@ -234,7 +234,8 @@ Account.prototype.init = co(function* init() { assert(this.nestedDepth === 0); this.initialized = true; - yield this.setDepth(1, 1, 1); + + yield this.initDepth(); }); /** @@ -433,32 +434,29 @@ Account.prototype.createNested = function createNested() { */ Account.prototype.createKey = co(function* createKey(branch) { - var ring, lookahead; + var key, lookahead; switch (branch) { case 0: - ring = this.deriveReceive(this.receiveDepth); + key = this.deriveReceive(this.receiveDepth); lookahead = this.deriveReceive(this.receiveDepth + this.lookahead); - yield this.saveKey(ring); yield this.saveKey(lookahead); this.receiveDepth++; - this.receive = ring; + this.receive = key; break; case 1: - ring = this.deriveChange(this.changeDepth); + key = this.deriveChange(this.changeDepth); lookahead = this.deriveChange(this.changeDepth + this.lookahead); - yield this.saveKey(ring); yield this.saveKey(lookahead); this.changeDepth++; - this.change = ring; + this.change = key; break; case 2: - ring = this.deriveNested(this.nestedDepth); + key = this.deriveNested(this.nestedDepth); lookahead = this.deriveNested(this.nestedDepth + this.lookahead); - yield this.saveKey(ring); yield this.saveKey(lookahead); this.nestedDepth++; - this.nested = ring; + this.nested = key; break; default: throw new Error('Bad branch: ' + branch); @@ -466,7 +464,7 @@ Account.prototype.createKey = co(function* createKey(branch) { this.save(); - return ring; + return key; }); /** @@ -608,68 +606,121 @@ Account.prototype.savePath = function savePath(path) { }; /** - * Set change and receiving depth (depth is the index of the _next_ address). - * Allocate all addresses up to depth. Note that this also allocates - * new lookahead addresses. - * @param {Number} depth - * @returns {Promise} - Returns {@link WalletKey}, {@link WalletKey}. + * Initialize address depths (including lookahead). + * @returns {Promise} */ -Account.prototype.setDepth = co(function* setDepth(receiveDepth, changeDepth, nestedDepth) { - var i = -1; - var receive, change, nested, lookahead; +Account.prototype.initDepth = co(function* initDepth() { + var i, key; - if (receiveDepth > this.receiveDepth) { - for (i = this.receiveDepth; i < receiveDepth; i++) { - receive = this.deriveReceive(i); - yield this.saveKey(receive); - } + // Receive Address + this.receive = this.deriveReceive(0); + this.receiveDepth = 1; - for (i = receiveDepth; i < receiveDepth + this.lookahead; i++) { - lookahead = this.deriveReceive(i); - yield this.saveKey(lookahead); - } + yield this.saveKey(this.receive); - this.receive = receive; - this.receiveDepth = receiveDepth; + // Change Address + this.change = this.deriveChange(0); + this.changeDepth = 1; + + yield this.saveKey(this.change); + + // Nested Address + if (this.witness) { + this.nested = this.deriveNested(0); + this.nestedDepth = 1; + + yield this.saveKey(this.nested); } - if (changeDepth > this.changeDepth) { - for (i = this.changeDepth; i < changeDepth; i++) { - change = this.deriveChange(i); - yield this.saveKey(change); - } - - for (i = changeDepth; i < changeDepth + this.lookahead; i++) { - lookahead = this.deriveChange(i); - yield this.saveKey(lookahead); - } - - this.change = change; - this.changeDepth = changeDepth; + // Lookaheads + for (i = 0; i < this.lookahead; i++) { + key = this.deriveReceive(i + 1); + yield this.saveKey(key); } - if (this.witness && nestedDepth > this.nestedDepth) { - for (i = this.nestedDepth; i < nestedDepth; i++) { - nested = this.deriveNested(i); - yield this.saveKey(nested); - } - - for (i = nestedDepth; i < nestedDepth + this.lookahead; i++) { - lookahead = this.deriveNested(i); - yield this.saveKey(lookahead); - } - - this.nested = nested; - this.nestedDepth = nestedDepth; + for (i = 0; i < this.lookahead; i++) { + key = this.deriveChange(i + 1); + yield this.saveKey(key); } - if (i === -1) - return; + if (this.witness) { + for (i = 0; i < this.lookahead; i++) { + key = this.deriveNested(i + 1); + yield this.saveKey(key); + } + } this.save(); +}); - return receive || nested; +/** + * Allocate new lookahead addresses if necessary. + * @param {Number} receiveDepth + * @param {Number} changeDepth + * @param {Number} nestedDepth + * @returns {Promise} - Returns {@link WalletKey}. + */ + +Account.prototype.syncDepth = co(function* syncDepth(receive, change, nested) { + var derived = false; + var result = null; + var i, depth, key; + + if (receive > this.receiveDepth) { + depth = this.receiveDepth + this.lookahead; + + assert(receive < depth); + + for (i = depth; i < receive + this.lookahead; i++) { + key = this.deriveReceive(i); + yield this.saveKey(key); + } + + this.receive = this.deriveReceive(receive - 1); + this.receiveDepth = receive; + + derived = true; + result = this.receive; + } + + if (change > this.changeDepth) { + depth = this.changeDepth + this.lookahead; + + assert(change < depth); + + for (i = depth; i < change + this.lookahead; i++) { + key = this.deriveChange(i); + yield this.saveKey(key); + } + + this.change = this.deriveChange(change - 1); + this.changeDepth = change; + + derived = true; + } + + if (this.witness && nested > this.nestedDepth) { + depth = this.nestedDepth + this.lookahead; + + assert(nested < depth); + + for (i = depth; i < nested + this.lookahead; i++) { + key = this.deriveNested(i); + yield this.saveKey(key); + } + + this.nested = this.deriveNested(nested - 1); + this.nestedDepth = nested; + + derived = true; + result = this.nested; + } + + if (derived) + this.save(); + + return result; }); /** diff --git a/lib/wallet/wallet.js b/lib/wallet/wallet.js index a196c29a..ce91138b 100644 --- a/lib/wallet/wallet.js +++ b/lib/wallet/wallet.js @@ -1659,7 +1659,7 @@ Wallet.prototype.getKey = co(function* getKey(address) { Wallet.prototype.getPrivateKey = co(function* getPrivateKey(address, passphrase) { var hash = Address.getHash(address, 'hex'); - var path, account; + var path, account, key; if (!hash) return; @@ -1676,7 +1676,12 @@ Wallet.prototype.getPrivateKey = co(function* getPrivateKey(address, passphrase) yield this.unlock(passphrase); - return account.derivePath(path, this.master); + key = account.derivePath(path, this.master); + + if (!key.privateKey) + return; + + return key; }); /** @@ -1796,7 +1801,7 @@ Wallet.prototype.syncOutputDepth = co(function* syncOutputDepth(details) { if (!account) continue; - ring = yield account.setDepth(receive, change, nested); + ring = yield account.syncDepth(receive, change, nested); if (ring) derived.push(ring);