From 82232c0f5563fc9acc653237f1e67bbd12a3f8da Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Fri, 8 Apr 2016 10:35:01 -0400 Subject: [PATCH] bitcoind: wrap rpc errors as instances of error --- lib/services/bitcoind.js | 73 ++++++++++++++++++++++------------------ lib/transaction.js | 2 +- regtest/bitcoind.js | 15 +++++++++ 3 files changed, 57 insertions(+), 33 deletions(-) diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index 6d9c1a06..8319b57d 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -183,24 +183,30 @@ Bitcoin.prototype._resetCaches = function() { this.summaryCache.reset(); }; +Bitcoin.prototype._wrapRPCError = function(errObj) { + var err = new Error(errObj.message); + err.code = errObj.code; + return err; +}; + Bitcoin.prototype._initChain = function(callback) { var self = this; self.client.getBestBlockHash(function(err, response) { if (err) { - return callback(err); + return callback(self._wrapRPCError(err)); } self.client.getBlock(response.result, function(err, response) { if (err) { - return callback(err); + return callback(self._wrapRPCError(err)); } self.height = response.result.height; self.client.getBlockHash(0, function(err, response) { if (err) { - return callback(err); + return callback(self._wrapRPCError(err)); } var blockhash = response.result; self.getBlock(blockhash, function(err, block) { @@ -239,7 +245,7 @@ Bitcoin.prototype._zmqBlockHandler = function(node, message) { self.tiphash = message.toString('hex'); node.client.getBlock(self.tiphash, function(err, response) { if (err) { - return log.error(err); + return log.error(self._wrapRPCError(err)); } self.height = response.result.height; $.checkState(self.height >= 0); @@ -318,7 +324,7 @@ Bitcoin.prototype._checkReindex = function(node, callback) { var interval = setInterval(function() { node.client.syncPercentage(function(err, percentSynced) { if (err) { - return log.error(err); + return log.error(self._wrapRPCError(err)); } log.info('Bitcoin Core Daemon Reindex Percentage: ' + percentSynced.toFixed(2)); if (Math.round(percentSynced) >= 100) { @@ -339,15 +345,15 @@ Bitcoin.prototype._checkReindex = function(node, callback) { Bitcoin.prototype._loadTipFromNode = function(node, callback) { var self = this; node.client.getBestBlockHash(function(err, response) { - if (err) { - if (!(err instanceof Error)) { - log.warn(err.message); - } - return callback(new Error('Could not connect to bitcoind RPC')); + if (err && err.code === -28) { + log.warn(err.message); + return callback(self._wrapRPCError(err)); + } else if (err) { + return callback(self._wrapRPCError(err)); } node.client.getBlock(response.result, function(err, response) { if (err) { - return callback(err); + return callback(self._wrapRPCError(err)); } self.height = response.result.height; $.checkState(self.height >= 0); @@ -518,9 +524,10 @@ Bitcoin.prototype.isSynced = function(callback) { * @returns {Number} An estimated percentage of the syncronization status */ Bitcoin.prototype.syncPercentage = function(callback) { + var self = this; this.client.getBlockchainInfo(function(err, response) { if (err) { - return callback(err); + return callback(self._wrapRPCError(err)); } var percentSynced = response.result.verificationprogress * 100; callback(null, percentSynced); @@ -542,7 +549,7 @@ Bitcoin.prototype.getAddressBalance = function(addressArg, options, callback) { } else { this.client.getAddressBalance({addresses: addresses}, function(err, response) { if (err) { - return callback(err); + return callback(self._wrapRPCError(err)); } self.balanceCache.set(cacheKey, response.result); callback(null, response.result); @@ -565,7 +572,7 @@ Bitcoin.prototype.getAddressUnspentOutputs = function(addressArg, options, callb } else { self.client.getAddressUtxos({addresses: addresses}, function(err, response) { if (err) { - return callback(err); + return callback(self._wrapRPCError(err)); } self.utxosCache.set(cacheKey, response.result); callback(null, response.result); @@ -614,7 +621,7 @@ Bitcoin.prototype.getAddressTxids = function(addressArg, options, callback) { } else { self.client.getAddressTxids({addresses: addresses}, function(err, response) { if (err) { - return callback(err); + return callback(self._wrapRPCError(err)); } response.result.reverse(); self.txidsCache.set(cacheKey, response.result); @@ -627,7 +634,7 @@ Bitcoin.prototype.getAddressTxids = function(addressArg, options, callback) { if (queryMempool) { self.client.getAddressMempool({addresses: addresses}, function(err, response) { if (err) { - return callback(err); + return callback(self._wrapRPCError(err)); } mempoolTxids = self._getTxidsFromMempool(response.result); finish(); @@ -850,7 +857,7 @@ Bitcoin.prototype.getAddressSummary = function(addressArg, options, callback) { } self.client.getAddressMempool({'addresses': [addressArg]}, function(err, response) { if (err) { - return done(err); + return done(self._wrapRPCError(err)); } mempoolTxids = self._getTxidsFromMempool(response.result); summary.unconfirmedAppearances = mempoolTxids.length; @@ -895,7 +902,7 @@ Bitcoin.prototype.getBlock = function(blockArg, callback) { function queryBlock(blockhash) { self.client.getBlock(blockhash, false, function(err, response) { if (err) { - return callback(err); + return callback(self._wrapRPCError(err)); } var blockObj = bitcore.Block.fromString(response.result); self.blockCache.set(blockArg, blockObj); @@ -912,7 +919,7 @@ Bitcoin.prototype.getBlock = function(blockArg, callback) { if (_.isNumber(blockArg)) { self.client.getBlockHash(blockArg, function(err, response) { if (err) { - return callback(err); + return callback(self._wrapRPCError(err)); } var blockhash = response.result; queryBlock(blockhash); @@ -928,7 +935,7 @@ Bitcoin.prototype.getBlockHashesByTimestamp = function(high, low, callback) { var self = this; self.client.getBlockHashes(high, low, function(err, response) { if (err) { - return callback(err); + return callback(self._wrapRPCError(err)); } callback(null, response.result); }); @@ -954,7 +961,7 @@ Bitcoin.prototype.getBlockHeader = function(block, callback) { if (err && response.error.code === -5) { return callback(null, null); } else if (err) { - return callback(err); + return callback(self._wrapRPCError(err)); } // TODO format response prevHash instead of previousblockhash, etc. callback(null, response.result); @@ -966,7 +973,7 @@ Bitcoin.prototype.getBlockHeader = function(block, callback) { if (err && response.error.code === -8) { return callback(null, null); } else if (err) { - return callback(err); + return callback(self._wrapRPCError(err)); } var blockhash = response.result; queryHeader(blockhash); @@ -982,9 +989,10 @@ Bitcoin.prototype.getBlockHeader = function(block, callback) { * @returns {Number} */ Bitcoin.prototype.estimateFee = function(blocks, callback) { + var self = this; this.client.estimateFee(blocks, function(err, response) { if (err) { - return callback(err); + return callback(self._wrapRPCError(err)); } callback(null, response.result); }); @@ -997,6 +1005,7 @@ Bitcoin.prototype.estimateFee = function(blocks, callback) { * @param {Boolean} allowAbsurdFees - Enable large fees */ Bitcoin.prototype.sendTransaction = function(tx, allowAbsurdFees, callback) { + var self = this; var txString; if (tx instanceof Transaction) { txString = tx.serialize(); @@ -1010,7 +1019,7 @@ Bitcoin.prototype.sendTransaction = function(tx, allowAbsurdFees, callback) { this.client.sendRawTransaction(txString, allowAbsurdFees, function(err, response) { if (err) { - return callback(err); + return callback(self._wrapRPCError(err)); } callback(null, response.result); }); @@ -1035,7 +1044,7 @@ Bitcoin.prototype.getTransaction = function(txid, queryMempool, callback) { if (err && response.error.code === -5) { return callback(null, null); } else if (err) { - return callback(err); + return callback(self._wrapRPCError(err)); } var tx = Transaction(); tx.fromString(response.result); @@ -1066,11 +1075,10 @@ Bitcoin.prototype.getTransactionWithBlockInfo = function(txid, queryMempool, cal }); } else { self.client.getRawTransaction(txid, 1, function(err, response) { - if (err) { - return callback(err); - } - if (!response.result) { - return callback(new errors.Transaction.NotFound()); + if (err && response.error.code === -5) { + return callback(null, null); + } else if (err) { + return callback(self._wrapRPCError(err)); } var tx = Transaction(); tx.fromString(response.result.hex); @@ -1091,9 +1099,10 @@ Bitcoin.prototype.getTransactionWithBlockInfo = function(txid, queryMempool, cal * @returns {String} */ Bitcoin.prototype.getBestBlockHash = function(callback) { + var self = this; this.client.getBestBlockHash(function(err, response) { if (err) { - return callback(err); + return callback(self._wrapRPCError(err)); } callback(null, response.result); }); @@ -1122,7 +1131,7 @@ Bitcoin.prototype.getInfo = function(callback) { var self = this; this.client.getInfo(function(err, response) { if (err) { - return callback(err); + return callback(self._wrapRPCError(err)); } var result = response.result; result.network = self.node.network.name; diff --git a/lib/transaction.js b/lib/transaction.js index 1f826c45..1acb350d 100644 --- a/lib/transaction.js +++ b/lib/transaction.js @@ -32,7 +32,7 @@ Transaction.prototype._populateInput = function(db, input, poolTransactions, cal } var txid = input.prevTxId.toString('hex'); db.getTransaction(txid, true, function(err, prevTx) { - if(err instanceof errors.Transaction.NotFoundError) { + if(!prevTx) { // Check the pool for transaction for(var i = 0; i < poolTransactions.length; i++) { if(txid === poolTransactions[i].hash) { diff --git a/regtest/bitcoind.js b/regtest/bitcoind.js index 74d9ffa5..9b7a8f05 100644 --- a/regtest/bitcoind.js +++ b/regtest/bitcoind.js @@ -149,6 +149,19 @@ describe('Bitcoind Functionality', function() { }); }); + describe('get errors as error instances', function() { + it('will wrap an rpc into a javascript error', function(done) { + bitcoind.client.getBlock(1000000000, function(err, response) { + var error = bitcoind._wrapRPCError(err); + (error instanceof Error).should.equal(true); + error.message.should.equal(err.message); + error.code.should.equal(err.code); + should.exist(error.stack); + done(); + }); + }); + }); + describe('get blocks by height', function() { [0,1,2,3,4,5,6,7,8,9].forEach(function(i) { @@ -303,6 +316,7 @@ describe('Bitcoind Functionality', function() { tx.to(destKey.toAddress(), utxos[1].amount * 1e8 - 1000); bitcoind.sendTransaction(tx.uncheckedSerialize(), function(err, hash) { should.exist(err); + (err instanceof Error).should.equal(true); should.not.exist(hash); done(); }); @@ -316,6 +330,7 @@ describe('Bitcoind Functionality', function() { var num = 23; bitcoind.sendTransaction(num, function(err, hash) { should.exist(err); + (err instanceof Error).should.equal(true); should.not.exist(hash); done(); });