|
|
@ -1243,35 +1243,65 @@ WalletService.prototype._totalizeUtxos = function(utxos) { |
|
|
|
|
|
|
|
WalletService.prototype._getBalanceFromAddresses = function(opts, cb, i) { |
|
|
|
var self = this; |
|
|
|
|
|
|
|
var opts = opts || {}; |
|
|
|
opts.addresses = opts.addresses || []; |
|
|
|
|
|
|
|
|
|
|
|
function checkBalanceCache(cb) { |
|
|
|
if (opts.addresses.length < Defaults.BALANCE_CACHE_ADDRESS_THRESOLD || !opts.fastCache) |
|
|
|
return cb(); |
|
|
|
|
|
|
|
self.storage.checkAndUseBalanceCache(self.walletId, opts.addresses, opts.fastCache, cb); |
|
|
|
}; |
|
|
|
|
|
|
|
function storeBalanceCache(balance, cb) { |
|
|
|
if (opts.addresses.length < Defaults.BALANCE_CACHE_ADDRESS_THRESOLD) |
|
|
|
return cb(null, balance); |
|
|
|
|
|
|
|
self.storage.storeBalanceCache(self.walletId, opts.addresses, balance, function(err) { |
|
|
|
if (err) |
|
|
|
log.warn('Could not save cache:',err); |
|
|
|
|
|
|
|
return cb(null, balance); |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
// This lock is to prevent server starvation on big wallets
|
|
|
|
self._runLocked(cb, function(cb) { |
|
|
|
self._getUtxosForCurrentWallet({ |
|
|
|
coin: opts.coin, |
|
|
|
addresses: opts.addresses |
|
|
|
}, function(err, utxos) { |
|
|
|
checkBalanceCache(function(err, cache) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
var balance = self._totalizeUtxos(utxos); |
|
|
|
if (cache) { |
|
|
|
log.info('Using UTXO Cache'); |
|
|
|
return cb(null, cache, true); |
|
|
|
} |
|
|
|
|
|
|
|
// Compute balance by address
|
|
|
|
var byAddress = {}; |
|
|
|
_.each(_.indexBy(_.sortBy(utxos, 'address'), 'address'), function(value, key) { |
|
|
|
byAddress[key] = { |
|
|
|
address: key, |
|
|
|
path: value.path, |
|
|
|
amount: 0, |
|
|
|
}; |
|
|
|
}); |
|
|
|
self._getUtxosForCurrentWallet({ |
|
|
|
coin: opts.coin, |
|
|
|
addresses: opts.addresses |
|
|
|
}, function(err, utxos) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
_.each(utxos, function(utxo) { |
|
|
|
byAddress[utxo.address].amount += utxo.satoshis; |
|
|
|
}); |
|
|
|
var balance = self._totalizeUtxos(utxos); |
|
|
|
|
|
|
|
balance.byAddress = _.values(byAddress); |
|
|
|
return cb(null, balance); |
|
|
|
// Compute balance by address
|
|
|
|
var byAddress = {}; |
|
|
|
_.each(_.indexBy(_.sortBy(utxos, 'address'), 'address'), function(value, key) { |
|
|
|
byAddress[key] = { |
|
|
|
address: key, |
|
|
|
path: value.path, |
|
|
|
amount: 0, |
|
|
|
}; |
|
|
|
}); |
|
|
|
|
|
|
|
_.each(utxos, function(utxo) { |
|
|
|
byAddress[utxo.address].amount += utxo.satoshis; |
|
|
|
}); |
|
|
|
|
|
|
|
balance.byAddress = _.values(byAddress); |
|
|
|
|
|
|
|
storeBalanceCache(balance, cb); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}; |
|
|
@ -1281,10 +1311,17 @@ WalletService.prototype._getBalanceOneStep = function(opts, cb) { |
|
|
|
|
|
|
|
self.storage.fetchAddresses(self.walletId, function(err, addresses) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
if (addresses.length == opts.alreadyQueriedLength) { |
|
|
|
log.info('Query Skipped, all active addresses'); |
|
|
|
return cb(null,null, true); |
|
|
|
} |
|
|
|
|
|
|
|
self._getBalanceFromAddresses({ |
|
|
|
coin: opts.coin, |
|
|
|
addresses: addresses |
|
|
|
}, function(err, balance) { |
|
|
|
addresses: addresses, |
|
|
|
fastCache: opts.fastCache, |
|
|
|
}, function(err, balance, cacheUsed) { |
|
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
// Update cache
|
|
|
@ -1293,7 +1330,7 @@ WalletService.prototype._getBalanceOneStep = function(opts, cb) { |
|
|
|
if (err) { |
|
|
|
log.warn('Could not update wallet cache', err); |
|
|
|
} |
|
|
|
return cb(null, balance); |
|
|
|
return cb(null, balance, cacheUsed); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
@ -1367,10 +1404,10 @@ WalletService.prototype.getBalance = function(opts, cb, i) { |
|
|
|
} |
|
|
|
|
|
|
|
if (!opts.twoStep) { |
|
|
|
opts.fastCache = Defaults.BALANCE_CACHE_DIRECT_DURATION; |
|
|
|
return self._getBalanceOneStep(opts, cb); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
self.storage.getTwoStepCache(self.walletId, function(err, twoStepCache) { |
|
|
|
if (err) return cb(err); |
|
|
|
twoStepCache = twoStepCache || {}; |
|
|
@ -1392,9 +1429,9 @@ WalletService.prototype.getBalance = function(opts, cb, i) { |
|
|
|
self._getBalanceFromAddresses({ |
|
|
|
coin: opts.coin, |
|
|
|
addresses: activeAddresses |
|
|
|
}, function(err, partialBalance) { |
|
|
|
}, function(err, partialBalance, cacheUsed) { |
|
|
|
if (err) return cb(err); |
|
|
|
cb(null, partialBalance); |
|
|
|
cb(null, partialBalance, cacheUsed); |
|
|
|
|
|
|
|
var now = Math.floor(Date.now() / 1000); |
|
|
|
|
|
|
@ -1406,13 +1443,19 @@ WalletService.prototype.getBalance = function(opts, cb, i) { |
|
|
|
|
|
|
|
setTimeout(function() { |
|
|
|
log.debug('Running full balance query'); |
|
|
|
self._getBalanceOneStep(opts, function(err, fullBalance) { |
|
|
|
|
|
|
|
opts.alreadyQueriedLength = activeAddresses.length; |
|
|
|
opts.fastCache = Defaults.BALANCE_CACHE_DURATION; |
|
|
|
|
|
|
|
self._getBalanceOneStep(opts, function(err, fullBalance, skipped) { |
|
|
|
if (err) return; |
|
|
|
if (!_.isEqual(partialBalance, fullBalance)) { |
|
|
|
if (!skipped && !_.isEqual(partialBalance, fullBalance)) { |
|
|
|
log.info('Balance in active addresses differs from final balance'); |
|
|
|
self._notify('BalanceUpdated', fullBalance, { |
|
|
|
isGlobal: true |
|
|
|
}); |
|
|
|
} else if (skipped) { |
|
|
|
return; |
|
|
|
} else { |
|
|
|
// updates cache
|
|
|
|
twoStepCache.lastEmpty = now; |
|
|
|