Add wallet addresses index discovery on importing backup
This commit is contained in:
parent
107414ec7e
commit
29920abdb3
7 changed files with 167 additions and 3 deletions
|
|
@ -159,6 +159,27 @@ Insight.prototype.sendRawTransaction = function(rawtx, cb) {
|
|||
});
|
||||
};
|
||||
|
||||
Insight.prototype.checkActivity = function(addresses, cb) {
|
||||
if (!addresses) throw new Error('address must be set');
|
||||
|
||||
this.getTransactions(addresses, function onResult(txs) {
|
||||
var flatArray = function (xss) { return xss.reduce(function(r, xs) { return r.concat(xs); }, []); };
|
||||
var getInputs = function (t) { return t.vin.map(function (vin) { return vin.addr }); };
|
||||
var getOutputs = function (t) { return flatArray(
|
||||
t.vout.map(function (vout) { return vout.scriptPubKey.addresses; })
|
||||
);};
|
||||
|
||||
var activityMap = new Array(addresses.length);
|
||||
var activeAddress = flatArray(txs.map(function(t) { return getInputs(t).concat(getOutputs(t)); }));
|
||||
activeAddress.forEach(function (addr) {
|
||||
var index = addresses.indexOf(addr);
|
||||
if (index != -1) activityMap[index] = true;
|
||||
});
|
||||
|
||||
cb(null, activityMap);
|
||||
});
|
||||
};
|
||||
|
||||
Insight.prototype._request = function(options, callback) {
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ AddressIndex.prototype.toObj = function() {
|
|||
AddressIndex.prototype.checkRange = function(index, isChange) {
|
||||
if ((isChange && index > this.changeIndex) ||
|
||||
(!isChange && index > this.receiveIndex)) {
|
||||
throw new Error('Out of bounds at index %d isChange: %d', index, isChange);
|
||||
throw new Error('Out of bounds at index ' + index + ' isChange: ' + isChange);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -157,8 +157,6 @@ PublicKeyRing.prototype.getPubKeys = function(index, isChange) {
|
|||
|
||||
// TODO this could be cached
|
||||
PublicKeyRing.prototype.getRedeemScript = function (index, isChange) {
|
||||
this.indexes.checkRange(index, isChange);
|
||||
|
||||
var pubKeys = this.getPubKeys(index, isChange);
|
||||
var script = Script.createMultisig(this.requiredCopayers, pubKeys);
|
||||
return script;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ var coinUtil = bitcore.util;
|
|||
var buffertools = bitcore.buffertools;
|
||||
var Builder = bitcore.TransactionBuilder;
|
||||
var http = require('http');
|
||||
var async = require('async');
|
||||
var EventEmitter = imports.EventEmitter || require('events').EventEmitter;
|
||||
var copay = copay || require('../../../copay');
|
||||
var SecureRandom = bitcore.SecureRandom;
|
||||
|
|
@ -711,6 +712,71 @@ Wallet.prototype.createTxSync = function(toAddress, amountSatStr, comment, utxos
|
|||
return ntxid;
|
||||
};
|
||||
|
||||
Wallet.prototype.updateIndexes = function(callback) {
|
||||
var self = this;
|
||||
var start = self.publicKeyRing.indexes.changeIndex;
|
||||
self.indexDiscovery(start, true, 20, function(err, changeIndex) {
|
||||
if (err) return callback(err);
|
||||
if (changeIndex != -1)
|
||||
self.publicKeyRing.indexes.changeIndex = changeIndex + 1;
|
||||
|
||||
start = self.publicKeyRing.indexes.receiveIndex;
|
||||
self.indexDiscovery(start, false, 20, function(err, receiveIndex) {
|
||||
if (err) return callback(err);
|
||||
if (receiveIndex != -1)
|
||||
self.publicKeyRing.indexes.receiveIndex = receiveIndex + 1;
|
||||
|
||||
self.emit('publicKeyRingUpdated');
|
||||
self.store();
|
||||
callback();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Wallet.prototype.deriveAddresses = function(index, amout, isChange) {
|
||||
var ret = new Array(amout);
|
||||
for(var i = 0; i < amout; i++) {
|
||||
ret[i] = this.publicKeyRing.getAddress(index + i, isChange).toString();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// This function scans the publicKeyRing branch starting at index @start and reports the index with last activity,
|
||||
// using a scan window of @gap. The argument @change defines the branch to scan: internal or external.
|
||||
// Returns -1 if no activity is found in range.
|
||||
Wallet.prototype.indexDiscovery = function(start, change, gap, cb) {
|
||||
var scanIndex = start;
|
||||
var lastActive = -1;
|
||||
var hasActivity = false;
|
||||
|
||||
var self = this;
|
||||
async.doWhilst(
|
||||
function _do(next) {
|
||||
// Optimize window to minimize the derivations.
|
||||
var scanWindow = (lastActive == -1) ? gap : gap - (scanIndex - lastActive) + 1;
|
||||
var addresses = self.deriveAddresses(scanIndex, scanWindow, change);
|
||||
self.blockchain.checkActivity(addresses, function(err, actives){
|
||||
if (err) throw err;
|
||||
|
||||
// Check for new activities in the newlly scanned addresses
|
||||
var recentActive = actives.reduce(function(r, e, i) {
|
||||
return e ? scanIndex + i : r;
|
||||
}, lastActive);
|
||||
hasActivity = lastActive != recentActive;
|
||||
lastActive = recentActive;
|
||||
scanIndex += scanWindow;
|
||||
next();
|
||||
});
|
||||
},
|
||||
function _while() { return hasActivity; },
|
||||
function _finnaly(err) {
|
||||
if (err) return cb(err);
|
||||
cb(null, lastActive);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Wallet.prototype.disconnect = function() {
|
||||
this.log('## DISCONNECTING');
|
||||
this.network.disconnect();
|
||||
|
|
|
|||
|
|
@ -71,6 +71,11 @@ WalletFactory.prototype.fromEncryptedObj = function(base64, password) {
|
|||
var walletObj = this.storage.import(base64);
|
||||
if (!walletObj) return false;
|
||||
var w = this.fromObj(walletObj);
|
||||
var self = this;
|
||||
w.updateIndexes(function(err) {
|
||||
if (err) throw err;
|
||||
self.log('Indexes updated');
|
||||
});
|
||||
return w;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue