diff --git a/lib/services/address/index.js b/lib/services/address/index.js index 783764b0..9da49bb5 100644 --- a/lib/services/address/index.js +++ b/lib/services/address/index.js @@ -1,5 +1,6 @@ 'use strict'; +var assert = require('assert'); var BaseService = require('../../service'); var inherits = require('util').inherits; var async = require('async'); @@ -277,7 +278,7 @@ AddressService.prototype.blockHandler = function(block, connectBlock, callback) }); next(); } else { // uncommon and slower, this happens during a reorg - self.node.services.transaction.getTransaction(input.prevTxId, {}, function(err, tx) { + self.node.services.transaction.getTransaction(input.prevTxId.toString('hex'), {}, function(err, tx) { var utxo = tx.outputs[input.outputIndex]; var inputValue = self._encoding.encodeUtxoIndexValue(tx.__height, utxo.satoshis, utxo._scriptBuffer); operations.push({ @@ -1104,7 +1105,7 @@ AddressService.prototype.getAddressHistory = function(addresses, options, callba }); }, function() { async.mapLimit(txids, self.concurrency, function(txid, next) { - self.node.services.transaction.getTransaction(txid, options, function(err, tx) { + self.node.services.transaction.getTransaction(txid.toString('hex'), options, function(err, tx) { if(err) { return next(err); } @@ -1170,6 +1171,7 @@ AddressService.prototype.getAddressTxidsWithHeights = function(address, options, stream.on('data', function(buffer) { var key = self._encoding.decodeAddressIndexKey(buffer); + assert(key.txid.length === 64, 'AddressService, Txid: ' + key.txid + ' with length: ' + key.txid.length + ' does not resemble a txid.'); txids[key.txid] = key.height; }); diff --git a/lib/services/db/index.js b/lib/services/db/index.js index 027ca1ea..7d6c4919 100644 --- a/lib/services/db/index.js +++ b/lib/services/db/index.js @@ -176,6 +176,7 @@ DB.prototype.start = function(callback) { throw err; } + log.info('Bitcoin network tip is currently: ' + self.bitcoind.tiphash + ' at height: ' + self.bitcoind.height); self._sync.sync(); }); @@ -300,7 +301,6 @@ DB.prototype.loadTips = function(callback) { } var hash; - //genesis block, set to -1 because we have no yet processed the blocks if (!tipData) { hash = new Array(65).join('0'); self[tip] = { diff --git a/lib/services/transaction/index.js b/lib/services/transaction/index.js index fbaf9912..ac11903b 100644 --- a/lib/services/transaction/index.js +++ b/lib/services/transaction/index.js @@ -1,10 +1,13 @@ 'use strict'; +var assert = require('assert'); var async = require('async'); var BaseService = require('../../service'); var inherits = require('util').inherits; var Encoding = require('./encoding'); var levelup = require('levelup'); +var index = require('../../../'); +var log = index.log; /** * The Transaction Service builds upon the Database Service and the Bitcoin Service to add additional @@ -154,13 +157,14 @@ TransactionService.prototype._getInputValues = function(tx, callback) { TransactionService.prototype.getTransaction = function(txid, options, callback) { var self = this; + assert(txid.length === 64, 'Transaction, Txid: ' + txid + ' with length: ' + txid.length + ' does not resemble a txid.'); + if(self.currentTransactions[txid]) { return setImmediate(function() { callback(null, self.currentTransactions[txid]); }); } - txid = txid.toString('hex'); var key = self.encoding.encodeTransactionKey(txid); async.waterfall([ diff --git a/lib/services/wallet-api/index.js b/lib/services/wallet-api/index.js index bc151e70..32acd663 100644 --- a/lib/services/wallet-api/index.js +++ b/lib/services/wallet-api/index.js @@ -1,6 +1,7 @@ 'use strict'; var async = require('async'); +var assert = require('assert'); var BaseService = require('../../service'); var inherits = require('util').inherits; var index = require('../../'); @@ -522,7 +523,7 @@ WalletService.prototype._endpointGetAddresses = function() { } res.status(200).jsonp({ - addresses: addresses + addresses: addresses.length }); }); }); @@ -614,6 +615,53 @@ WalletService.prototype._endpointRegisterWallet = function() { }; }; +WalletService.prototype._endpointResyncAddresses = function() { + + var self = this; + + return function(req, res) { + var walletId = req.params.walletId; + + + if (!walletId) { + return utils.sendError(new Error('WalletId must be given.'), res); + } + + if (!self._isJobQueueReady()) { + return utils.sendError(new Error('Job queue is currently overloaded, please try again later.'), res); + } + + self.db.pauseSync(function() { + + self._getAddresses(walletId, function(err, oldAddresses) { + + if(err) { + return utils.sendError(err, res); + } + + if(!oldAddresses) { + return res.status(404).send('Not found'); + } + + self._removeWallet(walletId, function(err) { + + if(err) { + return utils.sendError(err, res); + } + + self._createWallet(walletId, function() { + + var jobId = utils.generateJobId(); + self._importAddresses(walletId, oldAddresses, jobId, self._jobCompletionCallback.bind(self)); + res.status(200).jsonp({jobId: jobId}); + + }); + }); + }); + }); + }; +}; + WalletService.prototype._endpointPostAddresses = function() { var self = this; return function(req, res) { @@ -668,6 +716,7 @@ WalletService.prototype._endpointGetTransactions = function() { transform._transform = function(chunk, enc, callback) { var txid = self._encoding.decodeWalletTransactionKey(chunk).txid.toString('hex'); + assert(txid.length === 64, 'WalletService, Txid: ' + txid + ' with length: ' + txid.length + ' does not resemble a txid.'); self._getTransactionFromDb(options, txid, function(err, tx) { @@ -1023,6 +1072,7 @@ WalletService.prototype._importAddresses = function(walletId, addresses, jobId, return callback(err, jobResults); } + log.info('loaded addresses, count: ', oldAddresses.length); async.parallel( [ self._getUTXOIndexOperations.bind(self, walletId, addresses, jobId), @@ -1087,6 +1137,7 @@ WalletService.prototype._getUTXOIndexOperations = function(walletId, addresses, return callback(err); } + log.info('completed gathering utxos: ', utxos.length); var operations = []; for(var i = 0; i < utxos.length; i++) { @@ -1122,11 +1173,15 @@ WalletService.prototype._getTxidIndexOperations = function(walletId, addresses, var self = this; var txids = {}; + var logCount = 0; async.eachLimit(addresses, 10, function(address, next) { self.node.services.address.getAddressTxidsWithHeights(address, null, function(err, tmpTxids) { if(err) { return next(err); } + if (logCount++ % 1000 === 0) { + log.info('loaded 10 addresses, total count: ', Object.keys(txids).length); + } txids = _.merge(txids, tmpTxids); return next(); }); @@ -1135,7 +1190,6 @@ WalletService.prototype._getTxidIndexOperations = function(walletId, addresses, return callback(err); } - //there is a big problem when we have multiple txs for our wallet for the same height! var operations = Object.keys(txids).map(function(txid) { return { @@ -1304,6 +1358,9 @@ WalletService.prototype._setupWriteRoutes = function(app) { v.checkAddresses, s._endpointPostAddresses() ); + app.put('/wallets/:walletId/addresses/resync', + s._endpointResyncAddresses() + ); };