implement utxos for external addresses

This commit is contained in:
Ivan Socolsky 2015-08-13 12:01:22 -03:00
parent 4dbcb639fe
commit fca67fba8a
2 changed files with 76 additions and 24 deletions

View File

@ -618,15 +618,31 @@ WalletService.prototype._getBlockchainExplorer = function(network) {
return this.blockchainExplorer;
};
/**
* Returns list of UTXOs
* @param {Object} opts
* @returns {Array} utxos - List of UTXOs.
*/
WalletService.prototype.getUtxos = function(opts, cb) {
WalletService.prototype._getUtxosForAddresses = function(addresses, cb) {
var self = this;
opts = opts || {};
if (addresses.length == 0) return cb(null, []);
var networkName = Bitcore.Address(addresses[0]).toObject().network;
var bc = self._getBlockchainExplorer(networkName);
bc.getUnspentUtxos(addresses, function(err, utxos) {
if (err) return cb(err);
var utxos = _.map(utxos, function(utxo) {
var u = _.pick(utxo, ['txid', 'vout', 'address', 'scriptPubKey', 'amount', 'satoshis', 'confirmations']);
u.confirmations = u.confirmations || 0;
u.locked = false;
u.satoshis = u.satoshis ? +u.satoshis : Utils.strip(u.amount * 1e8);
delete u.amount;
return u;
});
return cb(null, utxos);
});
};
WalletService.prototype._getUtxosForCurrentWallet = function(cb) {
var self = this;
function utxoKey(utxo) {
return utxo.txid + '|' + utxo.vout
@ -635,29 +651,17 @@ WalletService.prototype.getUtxos = function(opts, cb) {
// Get addresses for this wallet
self.storage.fetchAddresses(self.walletId, function(err, addresses) {
if (err) return cb(err);
if (addresses.length == 0) return cb(null, []);
var addressStrs = _.pluck(addresses, 'address');
var addressToPath = _.indexBy(addresses, 'address'); // TODO : check performance
var networkName = Bitcore.Address(addressStrs[0]).toObject().network;
var bc = self._getBlockchainExplorer(networkName);
bc.getUnspentUtxos(addressStrs, function(err, inutxos) {
self._getUtxosForAddresses(addressStrs, function(err, utxos) {
if (err) return cb(err);
if (utxos.length == 0) return cb(null, []);
var utxos = _.map(inutxos, function(utxo) {
var u = _.pick(utxo, ['txid', 'vout', 'address', 'scriptPubKey', 'amount', 'satoshis', 'confirmations']);
u.confirmations = u.confirmations || 0;
u.locked = false;
return u;
});
self.getPendingTxs({}, function(err, txps) {
if (err) return cb(err);
var lockedInputs = _.map(_.flatten(_.pluck(txps, 'inputs')), utxoKey);
var utxoIndex = _.indexBy(utxos, utxoKey);
_.each(lockedInputs, function(input) {
if (utxoIndex[input]) {
utxoIndex[input].locked = true;
@ -665,9 +669,8 @@ WalletService.prototype.getUtxos = function(opts, cb) {
});
// Needed for the clients to sign UTXOs
var addressToPath = _.indexBy(addresses, 'address');
_.each(utxos, function(utxo) {
utxo.satoshis = utxo.satoshis ? +utxo.satoshis : Utils.strip(utxo.amount * 1e8);
delete utxo.amount;
utxo.path = addressToPath[utxo.address].path;
utxo.publicKeys = addressToPath[utxo.address].publicKeys;
});
@ -678,6 +681,24 @@ WalletService.prototype.getUtxos = function(opts, cb) {
});
};
/**
* Returns list of UTXOs
* @param {Object} opts
* @param {Array} opts.addresses (optional) - List of addresses from where to fetch UTXOs.
* @returns {Array} utxos - List of UTXOs.
*/
WalletService.prototype.getUtxos = function(opts, cb) {
var self = this;
opts = opts || {};
if (_.isUndefined(opts.addresses)) {
self._getUtxosForCurrentWallet(cb);
} else {
self._getUtxosForAddresses(opts.addresses, cb);
}
};
WalletService.prototype._totalizeUtxos = function(utxos) {
var balance = {
totalAmount: _.sum(utxos, 'satoshis'),

View File

@ -159,7 +159,12 @@ helpers.stubUtxos = function(server, wallet, amounts, cb) {
confirmations: confirmations,
};
});
blockchainExplorer.getUnspentUtxos = sinon.stub().callsArgWith(1, null, utxos);
blockchainExplorer.getUnspentUtxos = function(addresses, cb) {
var selected = _.filter(utxos, function(utxo) {
return _.contains(addresses, utxo.address);
});
return cb(null, selected);
};
return cb(utxos);
});
@ -1367,6 +1372,32 @@ describe('Wallet service', function() {
should.exist(utxos);
utxos.length.should.equal(2);
_.sum(utxos, 'satoshis').should.equal(3 * 1e8);
server.getMainAddresses({}, function(err, addresses) {
var utxo = utxos[0];
var address = _.find(addresses, {
address: utxo.address
});
should.exist(address);
utxo.path.should.equal(address.path);
utxo.publicKeys.should.deep.equal(address.publicKeys);
done();
});
});
});
});
it('should get UTXOs for specific addresses', function(done) {
helpers.stubUtxos(server, wallet, [1, 2, 3], function(utxos) {
_.uniq(utxos, 'address').length.should.be.above(1);
var address = utxos[0].address;
var amount = _.sum(_.filter(utxos, {
address: address
}), 'satoshis');
server.getUtxos({
addresses: [address]
}, function(err, utxos) {
should.not.exist(err);
should.exist(utxos);
_.sum(utxos, 'satoshis').should.equal(amount);
done();
});
});