simplify scanning.

This commit is contained in:
Christopher Jeffrey 2016-02-13 15:58:27 -08:00
parent 2a5c35cf05
commit 06ba355363
2 changed files with 49 additions and 130 deletions

View File

@ -259,9 +259,9 @@ HDPrivateKey.prototype.scan44 = function scan44(options, txByAddress, callback)
assert(accounts[accountIndex] == null || chainConstant === 1);
if (chainConstant === 0)
accounts[accountIndex] = { addressDepth: addressIndex };
accounts[accountIndex] = { addressDepth: addressIndex - gap };
else
accounts[accountIndex].changeDepth = addressIndex;
accounts[accountIndex].changeDepth = addressIndex - gap;
// 4. if no transactions are found on the
// external chain, stop discovery
@ -410,9 +410,9 @@ HDPrivateKey.prototype.scan45 = function scan45(options, txByAddress, callback)
assert(cosigners[cosignerIndex] == null || chainConstant === 1);
if (chainConstant === 0)
cosigners[cosignerIndex] = { addressDepth: addressIndex };
cosigners[cosignerIndex] = { addressDepth: addressIndex - gap };
else
cosigners[cosginerIndex].changeDepth = addressIndex;
cosigners[cosginerIndex].changeDepth = addressIndex - gap;
if (total === 0) {
if (chainConstant === 0)

View File

@ -636,149 +636,54 @@ Wallet.prototype.getOutputPaths = function getOutputPaths(tx) {
Wallet.prototype.getOutputDepth = function getOutputDepth(tx) {
var paths = this.getOutputPaths(tx);
var depth = { change: -1, receive: -1 };
var depth = { changeDepth: -1, receiveDepth: -1 };
var i, path;
for (i = 0; i < paths.length; i++) {
path = this.parsePath(paths[i]);
if (path.change) {
if (path.index > depth.change)
depth.change = path.index;
if (path.index > depth.changeDepth)
depth.changeDepth = path.index;
} else {
if (path.index > depth.receive)
depth.receive = path.index;
if (path.index > depth.receiveDepth)
depth.receiveDepth = path.index;
}
}
depth.change++;
depth.receive++;
depth.changeDepth++;
depth.receiveDepth++;
return depth;
};
Wallet.prototype.syncOutputDepth = function syncOutputDepth(tx) {
var depth = this.getOutputDepth(tx);
if (depth.change >= this.changeDepth)
this.setChangeDepth(depth.change + 1);
if (depth.receive >= this.receiveDepth)
this.setReceiveDepth(depth.receive + 1);
if (depth.changeDepth >= this.changeDepth)
this.setChangeDepth(depth.changeDepth + 1);
if (depth.receiveDepth >= this.receiveDepth)
this.setReceiveDepth(depth.receiveDepth + 1);
};
Wallet.prototype.scan = function scan(txByAddress, callback) {
function done(err, depths) {
var self = this;
return this._scan({}, txByAddress, function(err, depth) {
if (err)
return callback(err);
if (depths.changeDepth >= this.changeDepth)
this.setChangeDepth(depths.changeDepth + 1);
if (depth.changeDepth >= this.changeDepth)
this.setChangeDepth(depth.changeDepth + 1);
if (depths.receiveDepth >= this.receiveDepth)
this.setReceiveDepth(depths.receiveDepth + 1);
}
if (depth.receiveDepth >= this.receiveDepth)
this.setReceiveDepth(depth.receiveDepth + 1);
if (this.derivation === 'bip44')
return this._scan44({ current: true }, txByAddress, done);
if (this.derivation === 'bip45')
return this._scan45({}, txByAddress, done);
return callback(null, self);
});
};
Wallet.prototype._scan44 = function scan44(options, txByAddress, callback) {
Wallet.prototype._scan = function _scan(options, txByAddress, callback) {
var self = this;
var accounts = [];
var isAccount = this.master.isAccount44();
var _accountKey = this.accountKey;
assert(this._initialized);
return (function chainCheck(change) {
return (function scanner(accountIndex) {
var addressIndex = 0;
var total = 0;
var gap = 0;
if (options.current)
accountIndex = self.accountIndex;
// 1. derive the first account's node (index = 0)
self.accountKey = isAccount
? self.master
: self.master.deriveAccount44(accountIndex);
if (isAccount)
accountIndex = new bn(self.master.childIndex).toNumber() - constants.hd.hardened;
// 2. derive the external chain node of this account
// 3. scan addresses of the external chain;
// respect the gap limit described below
return (function next() {
var address = self.deriveAddress(change, addressIndex++);
var addr = address.getAddress();
return txByAddress(addr, function(err, txs) {
var result;
if (err) {
self.accountKey = _accountKey;
return callback(err);
}
if (txs) {
if (typeof txs === 'boolean')
result = txs;
else if (typeof txs === 'number')
result = txs > 0;
else if (Array.isArray(txs))
result = txs.length > 0;
else
result = false;
}
if (result) {
total++;
gap = 0;
return next();
}
if (++gap < 20)
return next();
assert(accounts[accountIndex] == null || change === true);
if (change === false)
accounts[accountIndex] = { receiveDepth: addressIndex };
else
accounts[accountIndex].changeDepth = addressIndex;
// 4. if no transactions are found on the
// external chain, stop discovery
if (total === 0) {
if (change === false)
return chainCheck(true);
self.accountKey = _accountKey;
if (isAccount || options.current)
return callback(null, accounts[accountIndex]);
return callback(null, accounts);
}
// 5. if there are some transactions, increase
// the account index and go to step 1
if (isAccount || options.current) {
if (change === false)
return chainCheck(true);
self.accountKey = _accountKey;
return callback(null, accounts[accountIndex]);
}
return scanner(accountIndex + 1);
});
})();
})(0);
})(false);
};
Wallet.prototype._scan45 = function scan45(options, txByAddress, callback) {
var depths = { changeDepth: 0, receiveDepth: 0 };
var depth = { changeDepth: 0, receiveDepth: 0 };
assert(this._initialized);
@ -789,9 +694,8 @@ Wallet.prototype._scan45 = function scan45(options, txByAddress, callback) {
return (function next() {
var address = self.deriveAddress(change, addressIndex++);
var addr = address.getAddress();
return txByAddress(addr, function(err, txs) {
return txByAddress(address.getAddress(), function(err, txs) {
var result;
if (err)
@ -806,6 +710,9 @@ Wallet.prototype._scan45 = function scan45(options, txByAddress, callback) {
result = txs.length > 0;
else
result = false;
if (Array.isArray(txs) && (txs[0] instanceof bcoin.tx))
txs.forEach(function(tx) { self.addTX(tx); });
}
if (result) {
@ -817,41 +724,53 @@ Wallet.prototype._scan45 = function scan45(options, txByAddress, callback) {
if (++gap < 20)
return next();
assert(depths.receiveDepth === 0 || change === true);
assert(depth.receiveDepth === 0 || change === true);
if (change === false)
depths.receiveDepth = addressIndex;
depth.receiveDepth = addressIndex - gap;
else
depths.changeDepth = addressIndex;
depth.changeDepth = addressIndex - gap;
if (change === false)
return chainCheck(true);
return callback(null, depths);
return callback(null, depth);
});
})();
})(false);
};
Wallet.prototype.scriptInputs = function scriptInputs(tx, index) {
var addresses;
this.fillPrevout(tx);
var addresses = this.deriveInputs(tx);
addresses = this.deriveInputs(tx);
return addresses.reduce(function(total, address) {
return total + address.scriptInputs(tx, index);
}, 0);
};
Wallet.prototype.signInputs = function signInputs(tx, type, index) {
var addresses;
this.fillPrevout(tx);
var addresses = this.deriveInputs(tx);
addresses = this.deriveInputs(tx);
return addresses.reduce(function(total, address) {
return total + address.signInputs(tx, type, index);
}, 0);
};
Wallet.prototype.sign = function sign(tx, type, index) {
var addresses;
this.fillPrevout(tx);
var addresses = this.deriveInputs(tx);
addresses = this.deriveInputs(tx);
return addresses.reduce(function(total, address) {
return total + address.sign(tx, type, index);
}, 0);