scan + basic tests
This commit is contained in:
parent
5349529444
commit
ed43742189
|
@ -29,7 +29,7 @@ function BlockChainExplorer(opts) {
|
||||||
}
|
}
|
||||||
var explorer = new Explorers.Insight(url, network);
|
var explorer = new Explorers.Insight(url, network);
|
||||||
explorer.getTransactions = _.bind(getTransactionsInsight, explorer, url);
|
explorer.getTransactions = _.bind(getTransactionsInsight, explorer, url);
|
||||||
explorer.getActivity = _.bind(getActivityInsight, explorer, url);
|
explorer.getAddressActivity = _.bind(getAddressActivityInsight, explorer, url);
|
||||||
explorer.initSocket = _.bind(initSocketInsight, explorer, url);
|
explorer.initSocket = _.bind(initSocketInsight, explorer, url);
|
||||||
return explorer;
|
return explorer;
|
||||||
default:
|
default:
|
||||||
|
@ -56,7 +56,7 @@ function getTransactionsInsight(url, addresses, from, to, cb) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function getActivityInsight(url, addresses, cb) {
|
function getAddressActivityInsight(url, addresses, cb) {
|
||||||
getTransactionsInsight(url, addresses, 0, 0, function(err, result) {
|
getTransactionsInsight(url, addresses, 0, 0, function(err, result) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
return cb(null, result.items > 0);
|
return cb(null, result.items > 0);
|
||||||
|
|
|
@ -1044,6 +1044,10 @@ WalletService.prototype.getTxHistory = function(opts, cb) {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
WalletService.scanConfig = {
|
||||||
|
SCAN_WINDOW: 10,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scan the blockchain looking for addresses having some activity
|
* Scan the blockchain looking for addresses having some activity
|
||||||
*
|
*
|
||||||
|
@ -1051,6 +1055,78 @@ WalletService.prototype.getTxHistory = function(opts, cb) {
|
||||||
* @param {Boolean} opts.includeCopayerBranches (defaults to false)
|
* @param {Boolean} opts.includeCopayerBranches (defaults to false)
|
||||||
*/
|
*/
|
||||||
WalletService.prototype.scan = function(opts, cb) {
|
WalletService.prototype.scan = function(opts, cb) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
opts = opts || {};
|
||||||
|
|
||||||
|
var allAddresses = [];
|
||||||
|
|
||||||
|
function deriveAddresses(size, isChange, derivator, cb) {
|
||||||
|
async.map(_.range(size), function(i, next) {
|
||||||
|
next(null, derivator(isChange));
|
||||||
|
}, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
function checkActivity(addresses, cb) {
|
||||||
|
var bc = self._getBlockchainExplorer();
|
||||||
|
bc.getAddressActivity(addresses, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
function scanBranch(isChange, derivator, cb) {
|
||||||
|
var activity = true;
|
||||||
|
async.whilst(function() {
|
||||||
|
return activity;
|
||||||
|
}, function(next) {
|
||||||
|
deriveAddresses(WalletService.scanConfig.SCAN_WINDOW, isChange, derivator, function(err, addresses) {
|
||||||
|
if (err) return next(err);
|
||||||
|
allAddresses.push(addresses);
|
||||||
|
checkActivity(_.pluck(addresses, 'address'), function(err, thereIsActivity) {
|
||||||
|
if (err) return next(err);
|
||||||
|
activity = thereIsActivity;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, cb);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Utils.runLocked(self.walletId, cb, function(cb) {
|
||||||
|
self.getWallet({}, function(err, wallet) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
if (!wallet.isComplete())
|
||||||
|
return cb(new ClientError('Wallet is not complete'));
|
||||||
|
|
||||||
|
var derivators = [];
|
||||||
|
derivators.push(_.bind(wallet.createAddress, wallet));
|
||||||
|
if (opts.includeCopayerBranches) {
|
||||||
|
_.each(wallet.copayers, function(copayer) {
|
||||||
|
derivators.push(_.bind(copayer.createAddress, copayer, wallet));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var branches = _.flatten(
|
||||||
|
_.map(derivators, function(derivator) {
|
||||||
|
return _.map([false, true], function(isChange) {
|
||||||
|
return {
|
||||||
|
derivator: derivator,
|
||||||
|
isChange: isChange
|
||||||
|
};
|
||||||
|
})
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
async.each(branches, function(branch, next) {
|
||||||
|
scanBranch(branch.isChange, branch.derivator, function(err) {
|
||||||
|
next(err);
|
||||||
|
});
|
||||||
|
}, function(err) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
self.storage.storeAddressAndWallet(wallet, _.flatten(allAddresses), function(err) {
|
||||||
|
return cb(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -343,16 +343,20 @@ Storage.prototype.fetchAddresses = function(walletId, cb) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Storage.prototype.storeAddressAndWallet = function(wallet, address, cb) {
|
Storage.prototype.storeAddressAndWallet = function(wallet, addresses, cb) {
|
||||||
var ops = [{
|
var ops = _.map([].concat(addresses), function(address) {
|
||||||
|
return {
|
||||||
|
type: 'put',
|
||||||
|
key: KEY.ADDRESS(wallet.id, address.address),
|
||||||
|
value: address,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
ops.unshift({
|
||||||
type: 'put',
|
type: 'put',
|
||||||
key: KEY.WALLET(wallet.id),
|
key: KEY.WALLET(wallet.id),
|
||||||
value: wallet,
|
value: wallet,
|
||||||
}, {
|
});
|
||||||
type: 'put',
|
|
||||||
key: KEY.ADDRESS(wallet.id, address.address),
|
|
||||||
value: address,
|
|
||||||
}, ];
|
|
||||||
this.db.batch(ops, cb);
|
this.db.batch(ops, cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ describe('Blockchain explorer', function() {
|
||||||
should.exist(exp);
|
should.exist(exp);
|
||||||
exp.should.respondTo('broadcast');
|
exp.should.respondTo('broadcast');
|
||||||
exp.should.respondTo('getTransactions');
|
exp.should.respondTo('getTransactions');
|
||||||
exp.should.respondTo('getActivity');
|
exp.should.respondTo('getAddressActivity');
|
||||||
exp.should.respondTo('getUnspentUtxos');
|
exp.should.respondTo('getUnspentUtxos');
|
||||||
exp.should.respondTo('initSocket');
|
exp.should.respondTo('initSocket');
|
||||||
var exp = BlockchainExplorer({
|
var exp = BlockchainExplorer({
|
||||||
|
|
|
@ -169,6 +169,12 @@ helpers.stubHistory = function(txs) {
|
||||||
blockchainExplorer.getTransactions = sinon.stub().callsArgWith(3, null, txs);
|
blockchainExplorer.getTransactions = sinon.stub().callsArgWith(3, null, txs);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
helpers.stubAddressActivity = function(activeAddresses) {
|
||||||
|
blockchainExplorer.getAddressActivity = function(addresses, cb) {
|
||||||
|
return cb(null, _.intersection(activeAddresses, addresses).length > 0);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
helpers.clientSign = WalletUtils.signTxp;
|
helpers.clientSign = WalletUtils.signTxp;
|
||||||
|
|
||||||
helpers.createProposalOpts = function(toAddress, amount, message, signingKey) {
|
helpers.createProposalOpts = function(toAddress, amount, message, signingKey) {
|
||||||
|
@ -2473,6 +2479,67 @@ describe('Wallet service', function() {
|
||||||
}, done);
|
}, done);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#scan', function() {
|
||||||
|
WalletService.scanConfig.SCAN_WINDOW = 2;
|
||||||
|
|
||||||
|
it('should scan main addresses', function(done) {
|
||||||
|
helpers.stubAddressActivity(['3K2VWMXheGZ4qG35DyGjA2dLeKfaSr534A']);
|
||||||
|
helpers.createAndJoinWallet(1, 2, function(server, wallet) {
|
||||||
|
var expectedPaths = [
|
||||||
|
'm/2147483647/0/0',
|
||||||
|
'm/2147483647/0/1',
|
||||||
|
'm/2147483647/0/2',
|
||||||
|
'm/2147483647/0/3',
|
||||||
|
'm/2147483647/1/0',
|
||||||
|
'm/2147483647/1/1',
|
||||||
|
];
|
||||||
|
server.scan({}, function(err) {
|
||||||
|
should.not.exist(err);
|
||||||
|
server.storage.fetchAddresses(wallet.id, function(err, addresses) {
|
||||||
|
should.exist(addresses);
|
||||||
|
addresses.length.should.equal(expectedPaths.length);
|
||||||
|
var paths = _.pluck(addresses, 'path');
|
||||||
|
_.difference(paths, expectedPaths).length.should.equal(0);
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('should scan main addresses & copayer addresses', function(done) {
|
||||||
|
helpers.stubAddressActivity(['3K2VWMXheGZ4qG35DyGjA2dLeKfaSr534A']);
|
||||||
|
helpers.createAndJoinWallet(1, 2, function(server, wallet) {
|
||||||
|
var expectedPaths = [
|
||||||
|
'm/2147483647/0/0',
|
||||||
|
'm/2147483647/0/1',
|
||||||
|
'm/2147483647/0/2',
|
||||||
|
'm/2147483647/0/3',
|
||||||
|
'm/2147483647/1/0',
|
||||||
|
'm/2147483647/1/1',
|
||||||
|
'm/0/0/0',
|
||||||
|
'm/0/0/1',
|
||||||
|
'm/0/1/0',
|
||||||
|
'm/0/1/1',
|
||||||
|
'm/1/0/0',
|
||||||
|
'm/1/0/1',
|
||||||
|
'm/1/1/0',
|
||||||
|
'm/1/1/1',
|
||||||
|
];
|
||||||
|
server.scan({
|
||||||
|
includeCopayerBranches: true
|
||||||
|
}, function(err) {
|
||||||
|
should.not.exist(err);
|
||||||
|
server.storage.fetchAddresses(wallet.id, function(err, addresses) {
|
||||||
|
should.exist(addresses);
|
||||||
|
addresses.length.should.equal(expectedPaths.length);
|
||||||
|
var paths = _.pluck(addresses, 'path');
|
||||||
|
_.difference(paths, expectedPaths).length.should.equal(0);
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue