Compare commits

..

No commits in common. "master" and "v2.3.2" have entirely different histories.

13 changed files with 564 additions and 629 deletions

View File

@ -1,18 +1,14 @@
# need sudo for docker
sudo: required
language: node_js language: node_js
# skip install step (npm install) node_js:
# See http://docs.travis-ci.com/user/customizing-the-build/#Skipping-the-Installation-Step - "0.10"
install: true - "0.12"
- "iojs"
services: before_install:
- docker - sudo add-apt-repository --yes ppa:bitcoin/bitcoin
- sudo apt-get update
- sudo apt-get install bitcoind
before_script: after_install:
- git submodule update --init - git submodule update --init
- docker build -t node-bitcoin .
script:
- docker run node-bitcoin

View File

@ -1,21 +1,5 @@
# node-bitcoin changelog # node-bitcoin changelog
## v3.0.1 (2015/10/25)
* fix redefinition of already defined variable (does not actually affect behavior)
## v3.0.0 (2015/10/18)
* make public domain license explicit
* remove commands dropped in bitcoind v0.11
* `getHashesPerSecond`
* `getHashesPerSec`
* add missing commands for bitcoind v0.11
* `generate`
* `verifyTxOutProof`
## v2.4.0 (2015/07/16)
* don't lazy-load http/https modules
* add command for bitcoind v0.11.0: `getTxOutProof`
## v2.3.2 (2015/06/26) ## v2.3.2 (2015/06/26)
* fix bug in test suite that was supposed to detect missing commands * fix bug in test suite that was supposed to detect missing commands
* add missing commands * add missing commands

View File

@ -1,11 +1,10 @@
# Dockerfile for running node-bitcoin tests
FROM freewil/bitcoin-testnet-box FROM freewil/bitcoin-testnet-box
MAINTAINER Sean Lavine <lavis88@gmail.com> MAINTAINER Sean Lavine <lavis88@gmail.com>
# install node.js # install node.js (sudo for bash needed?)
USER root USER root
RUN apt-get install --yes curl RUN apt-get install --yes curl
RUN curl --silent --location https://deb.nodesource.com/setup_0.12 | bash - RUN curl -sL https://deb.nodesource.com/setup_0.12 | bash -
RUN apt-get install --yes nodejs RUN apt-get install --yes nodejs
# set permissions for tester user on project # set permissions for tester user on project

24
LICENSE
View File

@ -1,24 +0,0 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>

View File

@ -1,25 +1,7 @@
# node-bitcoin # node-bitcoin [![Build Status](https://travis-ci.org/freewil/node-bitcoin.svg?branch=master)](https://travis-ci.org/freewil/node-bitcoin)
[![travis][travis-image]][travis-url]
[![npm][npm-image]][npm-url]
[![downloads][downloads-image]][downloads-url]
[![js-standard-style][standard-image]][standard-url]
[travis-image]: https://travis-ci.org/freewil/node-bitcoin.svg?branch=master
[travis-url]: https://travis-ci.org/freewil/node-bitcoin
[npm-image]: https://img.shields.io/npm/v/bitcoin.svg?style=flat
[npm-url]: https://npmjs.org/package/bitcoin
[downloads-image]: https://img.shields.io/npm/dm/bitcoin.svg?style=flat
[downloads-url]: https://npmjs.org/package/bitcoin
[standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat
[standard-url]: http://standardjs.com
node-bitcoin is a simple wrapper for the Bitcoin client's JSON-RPC API. node-bitcoin is a simple wrapper for the Bitcoin client's JSON-RPC API.
**Unmaintained, please see [bitcoin-core](https://github.com/ruimarinho/bitcoin-core)**
The API is equivalent to the API document [here](https://en.bitcoin.it/wiki/Original_Bitcoin_client/API_Calls_list). The API is equivalent to the API document [here](https://en.bitcoin.it/wiki/Original_Bitcoin_client/API_Calls_list).
The methods are exposed as lower camelcase methods on the `bitcoin.Client` The methods are exposed as lower camelcase methods on the `bitcoin.Client`
object, or you may call the API directly using the `cmd` method. object, or you may call the API directly using the `cmd` method.

View File

@ -11,7 +11,6 @@ module.exports = {
encryptWallet: 'encryptwallet', encryptWallet: 'encryptwallet',
estimateFee: 'estimatefee', // bitcoind v0.10.0x estimateFee: 'estimatefee', // bitcoind v0.10.0x
estimatePriority: 'estimatepriority', // bitcoind v0.10.0+ estimatePriority: 'estimatepriority', // bitcoind v0.10.0+
generate: 'generate', // bitcoind v0.11.0+
getAccount: 'getaccount', getAccount: 'getaccount',
getAccountAddress: 'getaccountaddress', getAccountAddress: 'getaccountaddress',
getAddedNodeInfo: 'getaddednodeinfo', // bitcoind v0.8.0+ getAddedNodeInfo: 'getaddednodeinfo', // bitcoind v0.8.0+
@ -19,22 +18,17 @@ module.exports = {
getBalance: 'getbalance', getBalance: 'getbalance',
getBestBlockHash: 'getbestblockhash', // bitcoind v0.9.0+ getBestBlockHash: 'getbestblockhash', // bitcoind v0.9.0+
getBlock: 'getblock', getBlock: 'getblock',
getBlockStats: 'getblockstats',
getBlockFilter: 'getblockfilter',
getBlockchainInfo : 'getblockchaininfo', // bitcoind v0.9.2+ getBlockchainInfo : 'getblockchaininfo', // bitcoind v0.9.2+
getBlockCount: 'getblockcount', getBlockCount: 'getblockcount',
getBlockHash: 'getblockhash', getBlockHash: 'getblockhash',
getBlockHeader: 'getblockheader',
getBlockTemplate: 'getblocktemplate', // bitcoind v0.7.0+ getBlockTemplate: 'getblocktemplate', // bitcoind v0.7.0+
getChainTips: 'getchaintips', // bitcoind v0.10.0+ getChainTips: 'getchaintips', // bitcoind v0.10.0+
getChainTxStats: 'getchaintxstats',
getConnectionCount: 'getconnectioncount', getConnectionCount: 'getconnectioncount',
getDifficulty: 'getdifficulty', getDifficulty: 'getdifficulty',
getGenerate: 'getgenerate', getGenerate: 'getgenerate',
getHashesPerSecond: 'gethashespersec',
getHashesPerSec: 'gethashespersec',
getInfo: 'getinfo', getInfo: 'getinfo',
getMempoolAncestors: 'getmempoolancestors',
getMempoolDescendants: 'getmempooldescendants',
getMempoolEntry: 'getmempoolentry',
getMempoolInfo: 'getmempoolinfo', // bitcoind v0.10+ getMempoolInfo: 'getmempoolinfo', // bitcoind v0.10+
getMiningInfo: 'getmininginfo', getMiningInfo: 'getmininginfo',
getNetTotals: 'getnettotals', getNetTotals: 'getnettotals',
@ -49,7 +43,6 @@ module.exports = {
getReceivedByAddress: 'getreceivedbyaddress', getReceivedByAddress: 'getreceivedbyaddress',
getTransaction: 'gettransaction', getTransaction: 'gettransaction',
getTxOut: 'gettxout', // bitcoind v0.7.0+ getTxOut: 'gettxout', // bitcoind v0.7.0+
getTxOutProof: 'gettxoutproof', // bitcoind v0.11.0+
getTxOutSetInfo: 'gettxoutsetinfo', // bitcoind v0.7.0+ getTxOutSetInfo: 'gettxoutsetinfo', // bitcoind v0.7.0+
getUnconfirmedBalance: 'getunconfirmedbalance', // bitcoind v0.9.0+ getUnconfirmedBalance: 'getunconfirmedbalance', // bitcoind v0.9.0+
getWalletInfo: 'getwalletinfo', // bitcoind v0.9.2+ getWalletInfo: 'getwalletinfo', // bitcoind v0.9.2+
@ -85,8 +78,7 @@ module.exports = {
validateAddress: 'validateaddress', validateAddress: 'validateaddress',
verifyChain: 'verifychain', // bitcoind v0.9.0+ verifyChain: 'verifychain', // bitcoind v0.9.0+
verifyMessage: 'verifymessage', verifyMessage: 'verifymessage',
verifyTxOutProof: 'verifytxoutproof', // bitcoind v0.11.0+
walletLock: 'walletlock', walletLock: 'walletlock',
walletPassphrase: 'walletpassphrase', walletPassphrase: 'walletpassphrase',
walletPassphraseChange: 'walletpassphrasechange' walletPassphraseChange: 'walletpassphrasechange'
} };

View File

@ -1,58 +1,62 @@
var commands = require('./commands') var commands = require('./commands'),
var rpc = require('./jsonrpc') rpc = require('./jsonrpc');
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Client // Client
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
function Client(opts) { function Client(opts) {
this.rpc = new rpc.Client(opts) this.rpc = new rpc.Client(opts);
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// cmd // cmd
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
Client.prototype.cmd = function() { Client.prototype.cmd = function() {
var args = [].slice.call(arguments) var args = [].slice.call(arguments);
var cmd = args.shift() var cmd = args.shift();
callRpc(cmd, args, this.rpc) callRpc(cmd, args, this.rpc);
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// callRpc // callRpc
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
function callRpc(cmd, args, rpc) { function callRpc(cmd, args, rpc) {
var fn = args[args.length - 1] var fn = args[args.length-1];
// If the last argument is a callback, pop it from the args list // If the last argument is a callback, pop it from the args list
if (typeof fn === 'function') { if (typeof fn === 'function') {
args.pop() args.pop();
} else { } else {
fn = function () {} fn = function() {};
} }
return rpc.call(cmd, args, function () { rpc.call(cmd, args, function(){
var args = [].slice.call(arguments) var args = [].slice.call(arguments);
args.unshift(null) args.unshift(null);
fn.apply(this, args) fn.apply(this, args);
}, function(err){ }, function(err){
fn(err) fn(err);
}) });
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Initialize wrappers // Initialize wrappers
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
(function() { (function() {
for (var protoFn in commands) { for (var protoFn in commands) {
(function(protoFn) { (function(protoFn) {
Client.prototype[protoFn] = function() { Client.prototype[protoFn] = function() {
var args = [].slice.call(arguments) var args = [].slice.call(arguments);
return callRpc(commands[protoFn], args, this.rpc) callRpc(commands[protoFn], args, this.rpc);
};
})(protoFn);
} }
})(protoFn)
} })();
})()
// Export! // Export!
module.exports.Client = Client module.exports.Client = Client;

View File

@ -1,155 +1,153 @@
var http = require('http')
var https = require('https')
var Client = function(opts) { var Client = function(opts) {
this.opts = opts || {} this.opts = opts || {};
this.http = this.opts.ssl ? https : http this.http = this.opts.ssl ? require('https') : require('http');
} };
Client.prototype.call = function (method, params) { Client.prototype.call = function(method, params, callback, errback, path) {
return new Promise((resolve, reject) => { var time = Date.now();
var time = Date.now() var requestJSON;
var requestJSON
if (Array.isArray(method)) { if (Array.isArray(method)) {
// multiple rpc batch call // multiple rpc batch call
requestJSON = [] requestJSON = [];
method.forEach(function(batchCall, i) { method.forEach(function(batchCall, i) {
requestJSON.push({ requestJSON.push({
id: time + '-' + i, id: time + '-' + i,
method: batchCall.method, method: batchCall.method,
params: batchCall.params params: batchCall.params
}) });
}) });
} else { } else {
// single rpc call // single rpc call
requestJSON = { requestJSON = {
id: time, id: time,
method: method, method: method,
params: params params: params
} };
} }
// First we encode the request into JSON // First we encode the request into JSON
requestJSON = JSON.stringify(requestJSON) var requestJSON = JSON.stringify(requestJSON);
// prepare request options // prepare request options
var requestOptions = { var requestOptions = {
host: this.opts.host || 'localhost', host: this.opts.host || 'localhost',
port: this.opts.port || 8332, port: this.opts.port || 8332,
method: 'POST', method: 'POST',
path: '/', path: path || '/',
headers: { headers: {
'Host': this.opts.host || 'localhost', 'Host': this.opts.host || 'localhost',
'Content-Length': requestJSON.length 'Content-Length': requestJSON.length
}, },
agent: false, agent: false,
rejectUnauthorized: this.opts.ssl && this.opts.sslStrict !== false rejectUnauthorized: this.opts.ssl && this.opts.sslStrict !== false
} };
if (this.opts.ssl && this.opts.sslCa) { if (this.opts.ssl && this.opts.sslCa) {
requestOptions.ca = this.opts.sslCa requestOptions.ca = this.opts.sslCa;
} }
// use HTTP auth if user and password set // use HTTP auth if user and password set
if (this.opts.user && this.opts.pass) { if (this.opts.user && this.opts.pass) {
requestOptions.auth = this.opts.user + ':' + this.opts.pass requestOptions.auth = this.opts.user + ':' + this.opts.pass;
} }
// Now we'll make a request to the server // Now we'll make a request to the server
var cbCalled = false var cbCalled = false;
var request = this.http.request(requestOptions) var request = this.http.request(requestOptions);
// start request timeout timer // start request timeout timer
var reqTimeout = setTimeout(function() { var reqTimeout = setTimeout(function() {
if (cbCalled) return if (cbCalled) return;
cbCalled = true cbCalled = true;
request.abort() request.abort();
var err = new Error('ETIMEDOUT') var err = new Error('ETIMEDOUT');
err.code = 'ETIMEDOUT' err.code = 'ETIMEDOUT';
reject(err) errback(err);
}, this.opts.timeout || 30000) }, this.opts.timeout || 30000);
// set additional timeout on socket in case of remote freeze after sending headers // set additional timeout on socket in case of remote freeze after sending headers
request.setTimeout(this.opts.timeout || 30000, function() { request.setTimeout(this.opts.timeout || 30000, function() {
if (cbCalled) return if (cbCalled) return;
cbCalled = true cbCalled = true;
request.abort() request.abort();
var err = new Error('ESOCKETTIMEDOUT') var err = new Error('ESOCKETTIMEDOUT')
err.code = 'ESOCKETTIMEDOUT' err.code = 'ESOCKETTIMEDOUT'
reject(err) errback(err);
}) });
request.on('error', function(err) { request.on('error', function(err) {
if (cbCalled) return if (cbCalled) return;
cbCalled = true cbCalled = true;
clearTimeout(reqTimeout) clearTimeout(reqTimeout);
reject(err) errback(err);
}) });
request.on('response', function(response) { request.on('response', function(response) {
clearTimeout(reqTimeout) clearTimeout(reqTimeout);
// We need to buffer the response chunks in a nonblocking way. // We need to buffer the response chunks in a nonblocking way.
var buffer = '' var buffer = '';
response.on('data', function(chunk) { response.on('data', function(chunk) {
buffer = buffer + chunk buffer = buffer + chunk;
}) });
// When all the responses are finished, we decode the JSON and // When all the responses are finished, we decode the JSON and
// depending on whether it's got a result or an error, we call // depending on whether it's got a result or an error, we call
// emitSuccess or emitError on the promise. // emitSuccess or emitError on the promise.
response.on('end', function() { response.on('end', function() {
var err var err;
if (cbCalled) return if (cbCalled) return;
cbCalled = true cbCalled = true;
try { try {
var decoded = JSON.parse(buffer) var decoded = JSON.parse(buffer);
} catch (e) { } catch (e) {
if (response.statusCode !== 200) { if (response.statusCode !== 200) {
err = new Error('Invalid params, response status code: ' + response.statusCode) err = new Error('Invalid params, response status code: ' + response.statusCode);
err.code = -32602 err.code = -32602;
reject(err) errback(err);
} else { } else {
err = new Error('Problem parsing JSON response from server') err = new Error('Problem parsing JSON response from server');
err.code = -32603 err.code = -32603;
reject(err) errback(err);
} }
return return;
} }
if (!Array.isArray(decoded)) { if (!Array.isArray(decoded)) {
decoded = [decoded] decoded = [decoded];
} }
// iterate over each response, normally there will be just one // iterate over each response, normally there will be just one
// unless a batch rpc call response is being processed // unless a batch rpc call response is being processed
decoded.forEach(function(decodedResponse, i) { decoded.forEach(function(decodedResponse, i) {
if (decodedResponse.hasOwnProperty('error') && decodedResponse.error != null) { if (decodedResponse.hasOwnProperty('error') && decodedResponse.error != null) {
if (reject) { if (errback) {
err = new Error(decodedResponse.error.message || '') err = new Error(decodedResponse.error.message || '');
if (decodedResponse.error.code) { if (decodedResponse.error.code) {
err.code = decodedResponse.error.code err.code = decodedResponse.error.code;
} }
reject(err) errback(err);
} }
} else if (decodedResponse.hasOwnProperty('result')) { } else if (decodedResponse.hasOwnProperty('result')) {
resolve(decodedResponse.result, response.headers) if (callback) {
callback(decodedResponse.result, response.headers);
}
} else { } else {
if (reject) { if (errback) {
err = new Error(decodedResponse.error.message || '') err = new Error(decodedResponse.error.message || '');
if (decodedResponse.error.code) { if (decodedResponse.error.code) {
err.code = decodedResponse.error.code err.code = decodedResponse.error.code;
} }
reject(err) errback(err);
} }
} }
})
})
})
request.end(requestJSON);
}); });
}
module.exports.Client = Client });
});
request.end(requestJSON);
};
module.exports.Client = Client;

View File

@ -1,7 +1,7 @@
{ {
"name": "@mempool/bitcoin", "name": "bitcoin",
"description": "Communicate with bitcoind via JSON-RPC", "description": "Communicate with bitcoind via JSON-RPC",
"version": "3.0.3", "version": "2.3.2",
"main": "lib/index.js", "main": "lib/index.js",
"keywords": [ "keywords": [
"bitcoin", "bitcoin",
@ -13,28 +13,18 @@
], ],
"dependencies": {}, "dependencies": {},
"devDependencies": { "devDependencies": {
"clone": "^1.0.2", "clone": "^0.1.18",
"mocha": "^2.3.3", "mocha": "^2.1.0"
"standard": "^5.3.1"
}, },
"optionalDependencies": {}, "optionalDependencies": {},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git://github.com/mempool/node-bitcoin.git" "url": "git://github.com/freewil/node-bitcoin.git"
}, },
"engines": { "engines": {
"node": ">= 0.10.0" "node": ">= 0.10.0"
}, },
"scripts": { "scripts": {
"pretest": "standard --verbose",
"test": "make test" "test": "make test"
}, }
"bugs": {
"url": "https://github.com/mempool/node-bitcoin/issues"
},
"homepage": "https://github.com/mempool/node-bitcoin#readme",
"directories": {
"test": "test"
},
"license": "Unlicense"
} }

View File

@ -1,292 +1,306 @@
/* global describe, it */ var assert = require('assert'),
clone = require('clone'),
var assert = require('assert') http = require('http'),
var clone = require('clone') bitcoin = require('../'),
var http = require('http') config = require('./config');
var bitcoin = require('../')
var config = require('./config')
var test = { var test = {
account: 'test' account: 'test'
} };
var makeClient = function makeClient() { var makeClient = function makeClient() {
return new bitcoin.Client(config) return new bitcoin.Client(config);
} };
var notEmpty = function notEmpty(data) { var notEmpty = function notEmpty(data) {
if (data === 0) return if (data === 0) return;
assert.ok(data) assert.ok(data);
} };
var makeServer = function(port) { var makeServer = function(port) {
var server = http.createServer() var server = http.createServer();
server.listen(port) server.listen(port);
return server return server;
} };
describe('Client', function() { describe('Client', function() {
describe('getAccountAddress()', function() { describe('getAccountAddress()', function() {
it('should be able to get an account address', function(done) { it('should be able to get an account address', function(done) {
var client = makeClient() var client = makeClient();
client.getAccountAddress(test.account, function(err, address) { client.getAccountAddress(test.account, function(err, address) {
assert.ifError(err) assert.ifError(err);
assert.ok(address) assert.ok(address);
client.getAccount(address, function(err, account) { client.getAccount(address, function(err, account) {
assert.ifError(err) assert.ifError(err);
assert.equal(account, test.account) assert.equal(account, test.account);
done() done();
}) });
}) });
}) });
}) });
describe('listTransactions()', function() { describe('listTransactions()', function() {
it('should be able to listTransactions with specific count', function(done) { it('should be able to listTransactions with specific count', function(done) {
var client = makeClient() var client = makeClient();
client.listTransactions(test.account, 15, function(err, txs) { client.listTransactions(test.account, 15, function(err, txs) {
assert.ifError(err) assert.ifError(err);
assert.ok(txs) assert.ok(txs);
assert.ok(Array.isArray(txs)) assert.ok(Array.isArray(txs));
done() done();
}) });
}) });
it('should be able to listTransactions without specific count', function(done) { it('should be able to listTransactions without specific count', function(done) {
var client = makeClient() var client = makeClient();
client.listTransactions(test.account, function(err, txs) { client.listTransactions(test.account, function(err, txs) {
assert.ifError(err) assert.ifError(err);
assert.ok(txs) assert.ok(txs);
assert.ok(Array.isArray(txs)) assert.ok(Array.isArray(txs));
done() done();
}) });
}) });
}) });
describe('getNewAddress()', function() { describe('getNewAddress()', function() {
it('should be able to get new address', function(done) { it('should be able to get new address', function(done) {
var client = makeClient() var client = makeClient();
client.getNewAddress(test.account, function(err, address) { client.getNewAddress(test.account, function(err, address) {
assert.ifError(err) assert.ifError(err);
client.getAddressesByAccount(test.account, function(err, addresses) { client.getAddressesByAccount(test.account, function(err, addresses) {
assert.ifError(err) assert.ifError(err);
assert.ok(addresses && addresses.length > 0) assert.ok(addresses && addresses.length > 0);
done() done();
}) });
}) });
}) });
}) });
describe('getBalance()', function() { describe('getBalance()', function() {
it('should return balance without any args', function(done) { it('should return balance without any args', function(done) {
var client = makeClient() var client = makeClient();
client.getBalance(function(err, balance) { client.getBalance(function(err, balance) {
assert.ifError(err) assert.ifError(err);
assert.ok(typeof balance === 'number') assert.ok(typeof balance === 'number');
done() done();
}) });
}) });
}) });
describe('getDifficulty()', function() { describe('getDifficulty()', function() {
it('should get difficulty', function(done) { it('should get difficulty', function(done) {
var client = makeClient() var client = makeClient();
client.getDifficulty(function(err, difficulty) { client.getDifficulty(function(err, difficulty) {
assert.ifError(err) assert.ifError(err);
assert.ok(typeof difficulty === 'number') assert.ok(typeof difficulty === 'number');
done() done();
}) });
}) });
}) });
describe('getInfo()', function() { describe('getInfo()', function() {
it('should get info', function(done) { it('should get info', function(done) {
var client = makeClient() var client = makeClient();
client.getInfo(function(err, info, headers) { client.getInfo(function(err, info, headers) {
assert.ifError(err) assert.ifError(err);
notEmpty(info) notEmpty(info);
assert.ok(info.errors === '') assert.ok(info.errors === '');
done() done();
}) });
}) });
}) });
describe('getHashesPerSec()', function() {
it('should get hashes per second', function(done) {
var client = makeClient();
client.getHashesPerSec(function(err, data) {
assert.ifError(err);
notEmpty(data);
assert.ok(typeof data === 'number');
done();
});
});
});
describe('help()', function() { describe('help()', function() {
it('should return help', function(done) { it('should return help', function(done) {
var client = makeClient() var client = makeClient();
client.help(function(err, help) { client.help(function(err, help) {
assert.ifError(err) assert.ifError(err);
notEmpty(help) notEmpty(help);
done() done();
}) });
}) });
}) });
it('bitcoin related error should be an Error object', function(done) { it('bitcoin related error should be an Error object', function(done) {
var client = makeClient() var client = makeClient();
client.cmd('nomethod', function(err, expectedValue) { client.cmd('nomethod', function(err, expectedValue) {
assert.ok(err instanceof Error) assert.ok(err instanceof Error);
assert.equal(err.message, 'Method not found') assert.equal(err.message, 'Method not found');
assert.equal(err.code, -32601) assert.equal(err.code, -32601);
assert.equal(expectedValue, undefined) assert.equal(expectedValue, undefined);
done() done();
}) });
}) });
it('running batch of rpc calls', function(done) { it('running batch of rpc calls', function(done) {
this.timeout(5000) this.timeout(5000);
var batch = [] var batch = [];
for (var i = 0; i < 10; ++i) { for (var i = 0; i < 10; ++i) {
batch.push({ batch.push({
method: 'getnewaddress', method: 'getnewaddress',
params: [test.account] params: [test.account]
}) });
} }
var client = makeClient() var client = makeClient();
var batchCallbackCount = 0 var batchCallbackCount = 0;
client.cmd(batch, function(err, address) { client.cmd(batch, function(err, address) {
assert.ifError(err) assert.ifError(err);
assert.ok(++batchCallbackCount <= 10) assert.ok(++batchCallbackCount <= 10);
assert.ok(address) assert.ok(address);
if (batchCallbackCount === 10) done() if (batchCallbackCount === 10) done();
}) });
}) });
describe('invalid credentials', function() { describe('invalid credentials', function() {
var badCredentials = clone(config) var badCredentials = clone(config);
badCredentials.user = 'baduser' badCredentials.user = 'baduser';
badCredentials.pass = 'badpwd' badCredentials.pass = 'badpwd';
var client = new bitcoin.Client(badCredentials) var client = new bitcoin.Client(badCredentials);
it('should still return client object', function(done) { it('should still return client object', function(done) {
assert.ok(client instanceof bitcoin.Client) assert.ok(client instanceof bitcoin.Client);
done() done();
}) });
it('should return status 401 with html', function(done) { it('should return status 401 with html', function(done) {
client.getDifficulty(function(err, difficulty) { client.getDifficulty(function(err, difficulty) {
assert.ok(err instanceof Error) assert.ok(err instanceof Error);
assert.equal(err.message, 'Invalid params, response status code: 401') assert.equal(err.message, 'Invalid params, response status code: 401');
assert.equal(err.code, -32602) assert.equal(err.code, -32602);
assert.equal(difficulty, undefined) assert.equal(difficulty, undefined);
done() done();
}) });
}) });
}) });
describe('creating client on non-listening port', function() { describe('creating client on non-listening port', function() {
var badPort = clone(config) var badPort = clone(config);
badPort.port = 9897 badPort.port = 9897;
badPort.user = 'baduser' badPort.user = 'baduser';
badPort.pass = 'badpwd' badPort.pass = 'badpwd';
var client = new bitcoin.Client(badPort) var client = new bitcoin.Client(badPort);
it('will return client object', function(done) { it('will return client object', function(done) {
assert.ok(client instanceof bitcoin.Client) assert.ok(client instanceof bitcoin.Client);
done() done();
}) });
it('should not call callback more than once', function(done) { it('should not call callback more than once', function(done) {
client.listSinceBlock(function(err, result) { client.listSinceBlock(function(err, result) {
assert.ok(err instanceof Error) assert.ok(err instanceof Error);
done() done();
}) });
}) });
}) });
describe('request timeouts', function() { describe('request timeouts', function() {
it('should occur by default after 30000ms', function(done) { it('should occur by default after 30000ms', function(done) {
this.timeout(31000) this.timeout(31000);
var server = makeServer(19998) var server = makeServer(19998);
var request // eslint-disable-line no-unused-vars var request;
var response var response;
server.on('request', function(req, res) { server.on('request', function(req, res) {
request = req request = req;
response = res response = res;
}) });
var client = new bitcoin.Client({ var client = new bitcoin.Client({
host: 'localhost', host: 'localhost',
port: 19998, port: 19998,
user: 'admin1', user: 'admin1',
pass: '123' pass: '123'
}) });
var start = Date.now() var start = Date.now();
client.getInfo(function(err, info) { client.getInfo(function(err, info) {
var delta = Date.now() - start var delta = Date.now() - start;
assert.ok(err instanceof Error) assert.ok(err instanceof Error);
assert.ok(err.code === 'ETIMEDOUT' || err.code === 'ESOCKETTIMEDOUT') assert.ok(err.code === 'ETIMEDOUT' || err.code === 'ESOCKETTIMEDOUT');
assert.ok(delta >= 30000, 'delta should be >= 30000: ' + delta) assert.ok(delta >= 30000, 'delta should be >= 30000: ' + delta);
response.end() response.end();
server.close() server.close();
done() done();
}) });
}) });
it('should be customizable', function(done) { it('should be customizable', function(done) {
this.timeout(4500) this.timeout(4500);
var server = makeServer(19999) var server = makeServer(19999);
var request // eslint-disable-line no-unused-vars var request;
var response var response;
server.on('request', function(req, res) { server.on('request', function(req, res) {
request = req request = req;
response = res response = res;
}) });
var client = new bitcoin.Client({ var client = new bitcoin.Client({
host: 'localhost', host: 'localhost',
port: 19999, port: 19999,
user: 'admin1', user: 'admin1',
pass: '123', pass: '123',
timeout: 2500 timeout: 2500
}) });
var start = Date.now() var start = Date.now();
client.getInfo(function(err, info) { client.getInfo(function(err, info) {
var delta = Date.now() - start var delta = Date.now() - start;
assert.ok(err instanceof Error) assert.ok(err instanceof Error);
assert.ok(err.code === 'ETIMEDOUT' || err.code === 'ESOCKETTIMEDOUT') assert.ok(err.code === 'ETIMEDOUT' || err.code === 'ESOCKETTIMEDOUT');
assert.ok(delta >= 2500, 'delta should be >= 2500:' + delta) assert.ok(delta >= 2500, 'delta should be >= 2500:' + delta);
response.end() response.end();
server.close() server.close();
done() done();
}) });
}) });
})
});
describe('response headers', function() { describe('response headers', function() {
var assertResHeaders = function(resHeaders) { var assertResHeaders = function(resHeaders) {
assert.ok(resHeaders) assert.ok(resHeaders);
assert.ok(resHeaders.server) assert.ok(resHeaders.server);
assert.ok(/bitcoin/.test(resHeaders.server)) assert.ok(/bitcoin/.test(resHeaders.server));
} };
it('should be returned for no parameter calls', function(done) { it('should be returned for no parameter calls', function(done) {
var client = makeClient() var client = makeClient();
client.getInfo(function(err, info, resHeaders) { client.getInfo(function(err, info, resHeaders) {
assert.ifError(err) assert.ifError(err);
notEmpty(info) notEmpty(info);
assert.ok(info.errors === '') assert.ok(info.errors === '');
assertResHeaders(resHeaders) assertResHeaders(resHeaders);
done() done();
}) });
}) });
it('should be returned for 1-parameter call', function(done) { it('should be returned for 1-parameter call', function(done) {
var client = makeClient() var client = makeClient();
client.getNewAddress(test.account, function(err, address, resHeaders) { client.getNewAddress(test.account, function(err, address, resHeaders) {
assert.ifError(err) assert.ifError(err);
assert.ok(address) assert.ok(address);
assertResHeaders(resHeaders) assertResHeaders(resHeaders);
done() done();
}) });
it('should be returned for 2-parameter call', function(done) { it('should be returned for 2-parameter call', function(done) {
var client = makeClient() var client = makeClient();
client.listTransactions(test.account, 15, function(err, txs, resHeaders) { client.listTransactions(test.account, 15, function(err, txs, resHeaders) {
assert.ifError(err) assert.ifError(err);
assert.ok(txs) assert.ok(txs);
assert.ok(Array.isArray(txs)) assert.ok(Array.isArray(txs));
assertResHeaders(resHeaders) assertResHeaders(resHeaders);
done() done();
}) });
}) });
}) });
})
}) });
});

View File

@ -1,75 +1,76 @@
/* global describe, it */ var assert = require('assert'),
bitcoin = require('../'),
config = require('./config'),
commands = require('../lib/commands');
var assert = require('assert')
var bitcoin = require('../')
var config = require('./config')
var commands = require('../lib/commands')
var getHelpCommands = function(client, cb) { var getHelpCommands = function(client, cb) {
var commandRegex = /^([a-z]+)/ var commandRegex = /^([a-z]+)/;
client.cmd('help', function(err, commandList) { client.cmd('help', function(err, commandList) {
if (err) return cb(err) if (err) return cb(err);
var helpCommands = [] var helpCommands = [];
// split up the command list by newlines // split up the command list by newlines
var commandListLines = commandList.split('\n') var commandListLines = commandList.split('\n');
var result var result;
for (var i in commandListLines) { for (var i in commandListLines) {
result = commandRegex.exec(commandListLines[i]) result = commandRegex.exec(commandListLines[i]);
if (!result) continue if (!result) continue;
helpCommands.push(result[1]) helpCommands.push(result[1]);
}
cb(null, helpCommands)
})
} }
cb(null, helpCommands);
});
};
describe('Client Commands', function() { describe('Client Commands', function() {
it('should have all the commands listed by `help`', function(done) { it('should have all the commands listed by `help`', function(done) {
var client = new bitcoin.Client(config) var client = new bitcoin.Client(config);
getHelpCommands(client, function(err, helpCommands) { getHelpCommands(client, function(err, helpCommands) {
assert.ifError(err) assert.ifError(err);
for (var i in helpCommands) { for (var i in helpCommands) {
var found = false var found = false;
for (var j in commands) { for (var j in commands) {
if (commands[j] === helpCommands[i]) { if (commands[j] === helpCommands[i]) {
found = true found = true;
break break;
} }
} }
assert.ok(found, 'missing command found in `help`: ' + helpCommands[i]) assert.ok(found, 'missing command found in `help`: ' + helpCommands[i]);
} }
done() done();
}) });
}) });
it('should not have any commands not listed by `help`', function(done) { it('should not have any commands not listed by `help`', function(done) {
var client = new bitcoin.Client(config) var client = new bitcoin.Client(config);
getHelpCommands(client, function(err, helpCommands) { getHelpCommands(client, function(err, helpCommands) {
assert.ifError(err) assert.ifError(err);
for (var i in commands) { for (var i in commands) {
var found = false var found = false;
for (var j in helpCommands) { for (var j in helpCommands) {
if (commands[i] === helpCommands[j]) { if (commands[i] === helpCommands[j]) {
found = true found = true;
break break;
} }
} }
// ignore commands not found in help because they are hidden // ignore commands not found in help because they are hidden
// if the wallet isn't encrypted // if the wallet isn't encrypted
var ignore = ['walletlock', 'walletpassphrase', 'walletpassphrasechange'] var ignore = ['walletlock', 'walletpassphrase', 'walletpassphrasechange'];
if (~ignore.indexOf(commands[i])) { if (~ignore.indexOf(commands[i])) {
assert.ok(!found, 'command found in `help`: ' + commands[i]) assert.ok(!found, 'command found in `help`: ' + commands[i]);
} else { } else {
assert.ok(found, 'command not found in `help`: ' + commands[i]) assert.ok(found, 'command not found in `help`: ' + commands[i]);
} }
} }
done() done();
}) });
}) });
})
});

View File

@ -1,63 +1,62 @@
/* global describe, it */ var assert = require('assert'),
fs = require('fs'),
var assert = require('assert') clone = require('clone'),
var fs = require('fs') bitcoin = require('../'),
var clone = require('clone') config = require('./config');
var bitcoin = require('../')
var config = require('./config')
var getInfo = function(opts, cb) { var getInfo = function(opts, cb) {
var client = new bitcoin.Client(opts) var client = new bitcoin.Client(opts);
client.getInfo(cb) client.getInfo(cb);
} };
describe('Client SSL', function() { describe('Client SSL', function() {
it('use sslStrict by default', function(done) { it('use sslStrict by default', function(done) {
var opts = clone(config) var opts = clone(config);
opts.ssl = true opts.ssl = true;
getInfo(opts, function(err, info) { getInfo(opts, function(err, info) {
assert.ok(err instanceof Error) assert.ok(err instanceof Error);
// node v0.11 adds `code` param to this error // node v0.11 adds `code` param to this error
// and uses a user-friendly `message` // and uses a user-friendly `message`
// continue using err.message for v0.8 and v0.10 // continue using err.message for v0.8 and v0.10
assert.equal(err.code || err.message, 'DEPTH_ZERO_SELF_SIGNED_CERT') assert.equal(err.code || err.message, 'DEPTH_ZERO_SELF_SIGNED_CERT');
done() done();
}) });
}) });
it('strictSSL should fail with self-signed certificate', function(done) { it('strictSSL should fail with self-signed certificate', function(done) {
var opts = clone(config) var opts = clone(config);
opts.ssl = true opts.ssl = true;
opts.sslStrict = true opts.sslStrict = true;
getInfo(opts, function(err, info) { getInfo(opts, function(err, info) {
assert.ok(err instanceof Error) assert.ok(err instanceof Error);
// node v0.11 adds `code` param to this error // node v0.11 adds `code` param to this error
// and uses a user-friendly `message` // and uses a user-friendly `message`
// continue using err.message for v0.8 and v0.10 // continue using err.message for v0.8 and v0.10
assert.equal(err.code || err.message, 'DEPTH_ZERO_SELF_SIGNED_CERT') assert.equal(err.code || err.message, 'DEPTH_ZERO_SELF_SIGNED_CERT');
done() done();
}) });
}) });
it('self-signed certificate with sslStrict false', function(done) { it('self-signed certificate with sslStrict false', function(done) {
var opts = clone(config) var opts = clone(config);
opts.ssl = true opts.ssl = true;
opts.sslStrict = false opts.sslStrict = false;
getInfo(opts, function(err, info) { getInfo(opts, function(err, info) {
assert.ifError(err) assert.ifError(err);
assert.ok(info) assert.ok(info);
done() done();
}) });
}) });
it('self-signed certificate with sslStrict and CA specified', function(done) { it('self-signed certificate with sslStrict and CA specified', function(done) {
var opts = clone(config) var opts = clone(config);
opts.ssl = true opts.ssl = true;
opts.sslCa = fs.readFileSync(__dirname + '/testnet-box/1/regtest/server.cert') opts.sslCa = fs.readFileSync(__dirname + '/testnet-box/1/regtest/server.cert');
getInfo(opts, function(err, info) { getInfo(opts, function(err, info) {
assert.ifError(err) assert.ifError(err);
assert.ok(info) assert.ok(info);
done() done();
}) });
}) });
})
});

@ -1 +1 @@
Subproject commit 24f5214acfddfec498cca21dd96dac480e9b9013 Subproject commit 54e884df1f49959b21cf4e2014424a172722ed5c