|
|
@ -902,50 +902,80 @@ WalletService.prototype._getUtxosForCurrentWallet = function(addresses, cb) { |
|
|
|
return utxo.txid + '|' + utxo.vout |
|
|
|
}; |
|
|
|
|
|
|
|
async.waterfall([ |
|
|
|
var allAddresses, allUtxos, utxoIndex; |
|
|
|
|
|
|
|
async.series([ |
|
|
|
|
|
|
|
function(next) { |
|
|
|
if (_.isArray(addresses)) { |
|
|
|
if (!_.isEmpty(addresses)) { |
|
|
|
next(null, addresses); |
|
|
|
} else { |
|
|
|
next(null, []); |
|
|
|
} |
|
|
|
} else { |
|
|
|
self.storage.fetchAddresses(self.walletId, next); |
|
|
|
allAddresses = addresses; |
|
|
|
return next(); |
|
|
|
} |
|
|
|
self.storage.fetchAddresses(self.walletId, function(err, addresses) { |
|
|
|
allAddresses = addresses; |
|
|
|
return next(); |
|
|
|
}); |
|
|
|
}, |
|
|
|
function(addresses, next) { |
|
|
|
if (addresses.length == 0) return next(null, []); |
|
|
|
function(next) { |
|
|
|
if (allAddresses.length == 0) return cb(null, []); |
|
|
|
|
|
|
|
var addressStrs = _.pluck(addresses, 'address'); |
|
|
|
var addressStrs = _.pluck(allAddresses, 'address'); |
|
|
|
self._getUtxos(addressStrs, function(err, utxos) { |
|
|
|
if (err) return next(err); |
|
|
|
if (utxos.length == 0) return next(null, []); |
|
|
|
allUtxos = utxos; |
|
|
|
utxoIndex = _.indexBy(allUtxos, utxoKey); |
|
|
|
return next(); |
|
|
|
}); |
|
|
|
}, |
|
|
|
function(next) { |
|
|
|
self.getPendingTxs({}, function(err, txps) { |
|
|
|
if (err) return next(err); |
|
|
|
|
|
|
|
self.getPendingTxs({}, function(err, txps) { |
|
|
|
if (err) return next(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; |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// Needed for the clients to sign UTXOs
|
|
|
|
var addressToPath = _.indexBy(addresses, 'address'); |
|
|
|
_.each(utxos, function(utxo) { |
|
|
|
utxo.path = addressToPath[utxo.address].path; |
|
|
|
utxo.publicKeys = addressToPath[utxo.address].publicKeys; |
|
|
|
}); |
|
|
|
|
|
|
|
return next(null, utxos); |
|
|
|
var lockedInputs = _.map(_.flatten(_.pluck(txps, 'inputs')), utxoKey); |
|
|
|
_.each(lockedInputs, function(input) { |
|
|
|
if (utxoIndex[input]) { |
|
|
|
utxoIndex[input].locked = true; |
|
|
|
} |
|
|
|
}); |
|
|
|
return next(); |
|
|
|
}); |
|
|
|
}, |
|
|
|
], cb); |
|
|
|
function(next) { |
|
|
|
var now = Math.floor(Date.now() / 1000); |
|
|
|
// Fetch latest broadcasted txs and remove any spent inputs from the
|
|
|
|
// list of UTXOs returned by the block explorer. This counteracts any out-of-sync
|
|
|
|
// effects between broadcasting a tx and getting the list of UTXOs.
|
|
|
|
// This is especially true in the case of having multiple instances of the block explorer.
|
|
|
|
self.storage.fetchBroadcastedTxs(self.walletId, { |
|
|
|
minTs: now - 24 * 3600, |
|
|
|
limit: 100 |
|
|
|
}, function(err, txs) { |
|
|
|
if (err) return next(err); |
|
|
|
var spentInputs = _.map(_.flatten(_.pluck(txs, 'inputs')), utxoKey); |
|
|
|
_.each(spentInputs, function(input) { |
|
|
|
if (utxoIndex[input]) { |
|
|
|
utxoIndex[input].spent = true; |
|
|
|
} |
|
|
|
}); |
|
|
|
allUtxos = _.reject(allUtxos, { |
|
|
|
spent: true |
|
|
|
}); |
|
|
|
return next(); |
|
|
|
}); |
|
|
|
}, |
|
|
|
function(next) { |
|
|
|
// Needed for the clients to sign UTXOs
|
|
|
|
var addressToPath = _.indexBy(allAddresses, 'address'); |
|
|
|
_.each(allUtxos, function(utxo) { |
|
|
|
utxo.path = addressToPath[utxo.address].path; |
|
|
|
utxo.publicKeys = addressToPath[utxo.address].publicKeys; |
|
|
|
}); |
|
|
|
return next(); |
|
|
|
}, |
|
|
|
], function(err) { |
|
|
|
return cb(err, allUtxos); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
/** |
|
|
@ -1883,7 +1913,6 @@ WalletService.prototype.createTx = function(opts, cb) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
self._runLocked(cb, function(cb) { |
|
|
|
|
|
|
|
var wallet, txp, changeAddress; |
|
|
|
async.series([ |
|
|
|
|
|
|
@ -2442,14 +2471,14 @@ WalletService.prototype.getPendingTxs = function(opts, cb) { |
|
|
|
txp.deleteLockTime = self.getRemainingDeleteLockTime(txp); |
|
|
|
}); |
|
|
|
|
|
|
|
async.each(txps, function(txp, a_cb) { |
|
|
|
if (txp.status != 'accepted') return a_cb(); |
|
|
|
async.each(txps, function(txp, next) { |
|
|
|
if (txp.status != 'accepted') return next(); |
|
|
|
|
|
|
|
self._checkTxInBlockchain(txp, function(err, isInBlockchain) { |
|
|
|
if (err || !isInBlockchain) return a_cb(err); |
|
|
|
if (err || !isInBlockchain) return next(err); |
|
|
|
self._processBroadcast(txp, { |
|
|
|
byThirdParty: true |
|
|
|
}, a_cb); |
|
|
|
}, next); |
|
|
|
}); |
|
|
|
}, function(err) { |
|
|
|
return cb(err, _.reject(txps, function(txp) { |
|
|
|