Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6eaefd223 | ||
|
|
c097b9c81e | ||
|
|
cb6e5c811b | ||
|
|
e969b3844f | ||
|
|
07d320d630 | ||
|
|
7b739e8eb9 | ||
|
|
e956310d43 | ||
|
|
b444d23f00 | ||
|
|
fe1ab3fc52 | ||
|
|
33d4ff9079 | ||
|
|
b9a2a749d8 | ||
|
|
b136254de9 | ||
|
|
bfedefd8c4 | ||
|
|
12860e83de | ||
|
|
2a067655c5 | ||
|
|
b93026db3a | ||
|
|
1d76ea1e14 | ||
|
|
16f07d9a7a | ||
|
|
990d5c472a | ||
|
|
41818121ae | ||
|
|
67e6545d88 | ||
|
|
43e1412066 | ||
|
|
12d8fd898a | ||
|
|
a245166a65 | ||
|
|
d25098240b | ||
|
|
0ef43d8555 | ||
|
|
a83c454525 | ||
|
|
bd63966e43 | ||
|
|
6973183179 | ||
|
|
4328a49b63 | ||
|
|
2e56677ab9 | ||
|
|
69393ae38c | ||
|
|
4e0851d859 | ||
|
|
4f47030c53 | ||
|
|
2e4c46cc41 | ||
|
|
00047173d5 | ||
|
|
cb95f56e9c | ||
|
|
bb8d05e556 | ||
|
|
b2900f01b9 | ||
|
|
75c204c109 | ||
|
|
fff3333c6c | ||
|
|
ce29b1d74e | ||
|
|
b9a3043de6 | ||
|
|
c8e5a1dda5 | ||
|
|
3cbf41caad | ||
|
|
db518ff059 | ||
|
|
af727e9f91 | ||
|
|
5e7df878ce | ||
|
|
ee52f9ef5a | ||
|
|
15819275f5 | ||
|
|
25aaeee5af | ||
|
|
b8aeff8750 | ||
|
|
1aea9f2006 | ||
|
|
8d02a1e7e6 | ||
|
|
d716cf99ef | ||
|
|
b75262f501 | ||
|
|
03f16394db | ||
|
|
d9352f0cc5 | ||
|
|
654b4a675b | ||
|
|
cd6382afca | ||
|
|
347df714c4 | ||
|
|
66a132ccfb | ||
|
|
0d5fb299af | ||
|
|
1377f69351 | ||
|
|
a26112a640 | ||
|
|
c964c962c4 | ||
|
|
4623696d6b |
@ -3,3 +3,4 @@ test/
|
||||
.project
|
||||
.gitmodules
|
||||
.travis.yml
|
||||
Dockerfile
|
||||
|
||||
26
.travis.yml
26
.travis.yml
@ -1,12 +1,18 @@
|
||||
# need sudo for docker
|
||||
sudo: required
|
||||
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.8"
|
||||
- "0.10"
|
||||
- "0.11"
|
||||
before_install:
|
||||
- sudo add-apt-repository --yes ppa:bitcoin/bitcoin
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install bitcoind
|
||||
after_install:
|
||||
|
||||
# skip install step (npm install)
|
||||
# See http://docs.travis-ci.com/user/customizing-the-build/#Skipping-the-Installation-Step
|
||||
install: true
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
before_script:
|
||||
- git submodule update --init
|
||||
|
||||
- docker build -t node-bitcoin .
|
||||
|
||||
script:
|
||||
- docker run node-bitcoin
|
||||
|
||||
56
Changelog.md
56
Changelog.md
@ -1,5 +1,61 @@
|
||||
# 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)
|
||||
* fix bug in test suite that was supposed to detect missing commands
|
||||
* add missing commands
|
||||
* `prioritiseTransaction`
|
||||
* `importWallet`
|
||||
|
||||
## v2.3.1 (2015/06/24)
|
||||
* add missing `getMempoolInfo` for bitcoind v0.10
|
||||
|
||||
## v2.3.0 (2015/02/04)
|
||||
* drop node v0.8.x support
|
||||
* update testnet-box
|
||||
* update devDependencies
|
||||
* add commands for bitcoind v0.10
|
||||
* `estimateFee`
|
||||
* `estimatePriority`
|
||||
* `getChainTips`
|
||||
* `importAddress`
|
||||
|
||||
## v2.2.0 (2014/08/29)
|
||||
* add commands for bitcoind v0.9.x
|
||||
* `decodeScript`
|
||||
* `dumpWallet`
|
||||
* `getBestBlockHash`
|
||||
* `getBlockchainInfo`
|
||||
* `getNetTotals`
|
||||
* `getNetworkInfo`
|
||||
* `getNetworkHashPs`
|
||||
* `getRawChangeAddress`
|
||||
* `getUnconfirmedBalance`
|
||||
* `getWalletInfo`
|
||||
* `ping`
|
||||
* `verifyChain`
|
||||
|
||||
## v2.1.2 (2014/04/16)
|
||||
* lazy load `http`/`https` module
|
||||
|
||||
## v2.1.1 (2014/03/25)
|
||||
* change default request timeout from `5000`ms to `30000`ms
|
||||
|
||||
## v2.1.0 (2014/03/12)
|
||||
* remove `deprecate` dependency
|
||||
* add request timeout option (defaults to 5000ms)
|
||||
|
||||
21
Dockerfile
Normal file
21
Dockerfile
Normal file
@ -0,0 +1,21 @@
|
||||
# Dockerfile for running node-bitcoin tests
|
||||
FROM freewil/bitcoin-testnet-box
|
||||
MAINTAINER Sean Lavine <lavis88@gmail.com>
|
||||
|
||||
# install node.js
|
||||
USER root
|
||||
RUN apt-get install --yes curl
|
||||
RUN curl --silent --location https://deb.nodesource.com/setup_0.12 | bash -
|
||||
RUN apt-get install --yes nodejs
|
||||
|
||||
# set permissions for tester user on project
|
||||
ADD . /home/tester/node-bitcoin
|
||||
RUN chown --recursive tester:tester /home/tester/node-bitcoin
|
||||
|
||||
# install module dependencies
|
||||
USER tester
|
||||
WORKDIR /home/tester/node-bitcoin
|
||||
RUN npm install
|
||||
|
||||
# run test suite
|
||||
CMD ["npm", "test"]
|
||||
24
LICENSE
Normal file
24
LICENSE
Normal file
@ -0,0 +1,24 @@
|
||||
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/>
|
||||
22
Readme.md
22
Readme.md
@ -1,9 +1,25 @@
|
||||
# node-bitcoin
|
||||
[![travis][travis-image]][travis-url]
|
||||
[![npm][npm-image]][npm-url]
|
||||
[![downloads][downloads-image]][downloads-url]
|
||||
[![js-standard-style][standard-image]][standard-url]
|
||||
|
||||
[](https://travis-ci.org/freewil/node-bitcoin)
|
||||
[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.
|
||||
|
||||
**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 methods are exposed as lower camelcase methods on the `bitcoin.Client`
|
||||
object, or you may call the API directly using the `cmd` method.
|
||||
@ -22,7 +38,7 @@ var client = new bitcoin.Client({
|
||||
port: 8332,
|
||||
user: 'username',
|
||||
pass: 'password',
|
||||
timeout: 5000
|
||||
timeout: 30000
|
||||
});
|
||||
```
|
||||
|
||||
@ -67,7 +83,7 @@ recommended to enable `ssl`, otherwise an attacker may intercept your RPC creden
|
||||
resulting in theft of your bitcoins.
|
||||
|
||||
When enabling `ssl` by setting the configuration option to `true`, the `sslStrict`
|
||||
option (verifies the server certificate) will also be enabled by default. It is
|
||||
option (verifies the server certificate) will also be enabled by default. It is
|
||||
highly recommended to specify the `sslCa` as well, even if your bitcoind has
|
||||
a certificate signed by an actual CA, to ensure you are connecting
|
||||
to your own bitcoind.
|
||||
|
||||
@ -5,36 +5,58 @@ module.exports = {
|
||||
createMultiSig: 'createmultisig',
|
||||
createRawTransaction: 'createrawtransaction', // bitcoind v0.7.0+
|
||||
decodeRawTransaction: 'decoderawtransaction', // bitcoind v0.7.0+
|
||||
decodeScript: 'decodescript',
|
||||
dumpPrivKey: 'dumpprivkey',
|
||||
dumpWallet: 'dumpwallet', // bitcoind v0.9.0+
|
||||
encryptWallet: 'encryptwallet',
|
||||
estimateFee: 'estimatefee', // bitcoind v0.10.0x
|
||||
estimatePriority: 'estimatepriority', // bitcoind v0.10.0+
|
||||
generate: 'generate', // bitcoind v0.11.0+
|
||||
getAccount: 'getaccount',
|
||||
getAccountAddress: 'getaccountaddress',
|
||||
getAddedNodeInfo: 'getaddednodeinfo', // bitcoind v0.8.0+
|
||||
getAddressesByAccount: 'getaddressesbyaccount',
|
||||
getBalance: 'getbalance',
|
||||
getBestBlockHash: 'getbestblockhash', // bitcoind v0.9.0+
|
||||
getBlock: 'getblock',
|
||||
getBlockStats: 'getblockstats',
|
||||
getBlockFilter: 'getblockfilter',
|
||||
getBlockchainInfo: 'getblockchaininfo', // bitcoind v0.9.2+
|
||||
getBlockCount: 'getblockcount',
|
||||
getBlockHash: 'getblockhash',
|
||||
getBlockHeader: 'getblockheader',
|
||||
getBlockTemplate: 'getblocktemplate', // bitcoind v0.7.0+
|
||||
getChainTips: 'getchaintips', // bitcoind v0.10.0+
|
||||
getChainTxStats: 'getchaintxstats',
|
||||
getConnectionCount: 'getconnectioncount',
|
||||
getDifficulty: 'getdifficulty',
|
||||
getGenerate: 'getgenerate',
|
||||
getHashesPerSecond: 'gethashespersec',
|
||||
getHashesPerSec: 'gethashespersec',
|
||||
getInfo: 'getinfo',
|
||||
getMempoolAncestors: 'getmempoolancestors',
|
||||
getMempoolDescendants: 'getmempooldescendants',
|
||||
getMempoolEntry: 'getmempoolentry',
|
||||
getMempoolInfo: 'getmempoolinfo', // bitcoind v0.10+
|
||||
getMiningInfo: 'getmininginfo',
|
||||
getNetTotals: 'getnettotals',
|
||||
getNetworkInfo: 'getnetworkinfo', // bitcoind v0.9.2+
|
||||
getNetworkHashPs: 'getnetworkhashps', // bitcoind v0.9.0+
|
||||
getNewAddress: 'getnewaddress',
|
||||
getPeerInfo: 'getpeerinfo', // bitcoind v0.7.0+
|
||||
getRawChangeAddress: 'getrawchangeaddress', // bitcoin v0.9+
|
||||
getRawMemPool: 'getrawmempool', // bitcoind v0.7.0+
|
||||
getRawTransaction: 'getrawtransaction', // bitcoind v0.7.0+
|
||||
getReceivedByAccount: 'getreceivedbyaccount',
|
||||
getReceivedByAddress: 'getreceivedbyaddress',
|
||||
getTransaction: 'gettransaction',
|
||||
getTxOut: 'gettxout', // bitcoind v0.7.0+
|
||||
getTxOutProof: 'gettxoutproof', // bitcoind v0.11.0+
|
||||
getTxOutSetInfo: 'gettxoutsetinfo', // bitcoind v0.7.0+
|
||||
getWork: 'getwork',
|
||||
getUnconfirmedBalance: 'getunconfirmedbalance', // bitcoind v0.9.0+
|
||||
getWalletInfo: 'getwalletinfo', // bitcoind v0.9.2+
|
||||
help: 'help',
|
||||
importAddress: 'importaddress', // bitcoind v0.10.0+
|
||||
importPrivKey: 'importprivkey',
|
||||
importWallet: 'importwallet', // bitcoind v0.9.0+
|
||||
keypoolRefill: 'keypoolrefill',
|
||||
keyPoolRefill: 'keypoolrefill',
|
||||
listAccounts: 'listaccounts',
|
||||
@ -47,6 +69,8 @@ module.exports = {
|
||||
listUnspent: 'listunspent', // bitcoind v0.7.0+
|
||||
lockUnspent: 'lockunspent', // bitcoind v0.8.0+
|
||||
move: 'move',
|
||||
ping: 'ping', // bitcoind v0.9.0+
|
||||
prioritiseTransaction: 'prioritisetransaction', // bitcoind v0.10.0+
|
||||
sendFrom: 'sendfrom',
|
||||
sendMany: 'sendmany',
|
||||
sendRawTransaction: 'sendrawtransaction', // bitcoind v0.7.0+
|
||||
@ -59,8 +83,10 @@ module.exports = {
|
||||
stop: 'stop',
|
||||
submitBlock: 'submitblock', // bitcoind v0.7.0+
|
||||
validateAddress: 'validateaddress',
|
||||
verifyChain: 'verifychain', // bitcoind v0.9.0+
|
||||
verifyMessage: 'verifymessage',
|
||||
verifyTxOutProof: 'verifytxoutproof', // bitcoind v0.11.0+
|
||||
walletLock: 'walletlock',
|
||||
walletPassphrase: 'walletpassphrase',
|
||||
walletPassphraseChange: 'walletpassphrasechange'
|
||||
};
|
||||
}
|
||||
|
||||
80
lib/index.js
80
lib/index.js
@ -1,62 +1,58 @@
|
||||
var commands = require('./commands'),
|
||||
rpc = require('./jsonrpc');
|
||||
var commands = require('./commands')
|
||||
var rpc = require('./jsonrpc')
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ===----------------------------------------------------------------------===//
|
||||
// Client
|
||||
//===----------------------------------------------------------------------===//
|
||||
function Client(opts) {
|
||||
this.rpc = new rpc.Client(opts);
|
||||
// ===----------------------------------------------------------------------===//
|
||||
function Client (opts) {
|
||||
this.rpc = new rpc.Client(opts)
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ===----------------------------------------------------------------------===//
|
||||
// cmd
|
||||
//===----------------------------------------------------------------------===//
|
||||
Client.prototype.cmd = function() {
|
||||
var args = [].slice.call(arguments);
|
||||
var cmd = args.shift();
|
||||
// ===----------------------------------------------------------------------===//
|
||||
Client.prototype.cmd = function () {
|
||||
var args = [].slice.call(arguments)
|
||||
var cmd = args.shift()
|
||||
|
||||
callRpc(cmd, args, this.rpc);
|
||||
callRpc(cmd, args, this.rpc)
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ===----------------------------------------------------------------------===//
|
||||
// callRpc
|
||||
//===----------------------------------------------------------------------===//
|
||||
function callRpc(cmd, args, rpc) {
|
||||
var fn = args[args.length-1];
|
||||
// ===----------------------------------------------------------------------===//
|
||||
function callRpc (cmd, args, rpc) {
|
||||
var fn = args[args.length - 1]
|
||||
|
||||
// If the last function is a callback, pop it from the args list
|
||||
if(typeof fn === 'function') {
|
||||
args.pop();
|
||||
// If the last argument is a callback, pop it from the args list
|
||||
if (typeof fn === 'function') {
|
||||
args.pop()
|
||||
} else {
|
||||
fn = function() {};
|
||||
fn = function () {}
|
||||
}
|
||||
|
||||
rpc.call(cmd, args, function(){
|
||||
var args = [].slice.call(arguments);
|
||||
args.unshift(null);
|
||||
fn.apply(this, args);
|
||||
}, function(err){
|
||||
fn(err);
|
||||
});
|
||||
return rpc.call(cmd, args, function () {
|
||||
var args = [].slice.call(arguments)
|
||||
args.unshift(null)
|
||||
fn.apply(this, args)
|
||||
}, function (err) {
|
||||
fn(err)
|
||||
})
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ===----------------------------------------------------------------------===//
|
||||
// Initialize wrappers
|
||||
//===----------------------------------------------------------------------===//
|
||||
(function() {
|
||||
|
||||
// ===----------------------------------------------------------------------===//
|
||||
(function () {
|
||||
for (var protoFn in commands) {
|
||||
(function(protoFn) {
|
||||
Client.prototype[protoFn] = function() {
|
||||
var args = [].slice.call(arguments);
|
||||
callRpc(commands[protoFn], args, this.rpc);
|
||||
};
|
||||
})(protoFn);
|
||||
(function (protoFn) {
|
||||
Client.prototype[protoFn] = function () {
|
||||
var args = [].slice.call(arguments)
|
||||
return callRpc(commands[protoFn], args, this.rpc)
|
||||
}
|
||||
})(protoFn)
|
||||
}
|
||||
|
||||
})();
|
||||
})()
|
||||
|
||||
// Export!
|
||||
module.exports.Client = Client;
|
||||
module.exports.Client = Client
|
||||
|
||||
301
lib/jsonrpc.js
301
lib/jsonrpc.js
@ -1,156 +1,155 @@
|
||||
var http = require('http'),
|
||||
https = require('https');
|
||||
var http = require('http')
|
||||
var https = require('https')
|
||||
|
||||
var Client = function(opts) {
|
||||
this.opts = opts || {};
|
||||
this.http = this.opts.ssl ? https : http;
|
||||
};
|
||||
var Client = function (opts) {
|
||||
this.opts = opts || {}
|
||||
this.http = this.opts.ssl ? https : http
|
||||
}
|
||||
|
||||
Client.prototype.call = function(method, params, callback, errback, path) {
|
||||
var time = Date.now();
|
||||
var requestJSON;
|
||||
|
||||
if (Array.isArray(method)) {
|
||||
// multiple rpc batch call
|
||||
requestJSON = [];
|
||||
method.forEach(function(batchCall, i) {
|
||||
requestJSON.push({
|
||||
id: time + '-' + i,
|
||||
method: batchCall.method,
|
||||
params: batchCall.params
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// single rpc call
|
||||
requestJSON = {
|
||||
id: time,
|
||||
method: method,
|
||||
params: params
|
||||
};
|
||||
}
|
||||
Client.prototype.call = function (method, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var time = Date.now()
|
||||
var requestJSON
|
||||
|
||||
// First we encode the request into JSON
|
||||
var requestJSON = JSON.stringify(requestJSON);
|
||||
|
||||
// prepare request options
|
||||
var requestOptions = {
|
||||
host: this.opts.host || 'localhost',
|
||||
port: this.opts.port || 8332,
|
||||
method: 'POST',
|
||||
path: path || '/',
|
||||
headers: {
|
||||
'Host': this.opts.host || 'localhost',
|
||||
'Content-Length': requestJSON.length
|
||||
},
|
||||
agent: false,
|
||||
rejectUnauthorized: this.opts.ssl && this.opts.sslStrict !== false
|
||||
};
|
||||
|
||||
if (this.opts.ssl && this.opts.sslCa) {
|
||||
requestOptions.ca = this.opts.sslCa;
|
||||
}
|
||||
|
||||
// use HTTP auth if user and password set
|
||||
if (this.opts.user && this.opts.pass) {
|
||||
requestOptions.auth = this.opts.user + ':' + this.opts.pass;
|
||||
}
|
||||
|
||||
// Now we'll make a request to the server
|
||||
var cbCalled = false;
|
||||
var request = this.http.request(requestOptions);
|
||||
|
||||
// start request timeout timer
|
||||
var reqTimeout = setTimeout(function() {
|
||||
if (cbCalled) return;
|
||||
cbCalled = true;
|
||||
request.abort();
|
||||
var err = new Error('ETIMEDOUT');
|
||||
err.code = 'ETIMEDOUT';
|
||||
errback(err);
|
||||
}, this.opts.timeout || 5000);
|
||||
|
||||
// set additional timeout on socket in case of remote freeze after sending headers
|
||||
request.setTimeout(this.opts.timeout || 5000, function() {
|
||||
if (cbCalled) return;
|
||||
cbCalled = true;
|
||||
request.abort();
|
||||
var err = new Error('ESOCKETTIMEDOUT')
|
||||
err.code = 'ESOCKETTIMEDOUT'
|
||||
errback(err);
|
||||
});
|
||||
|
||||
request.on('error', function(err) {
|
||||
if (cbCalled) return;
|
||||
cbCalled = true;
|
||||
clearTimeout(reqTimeout);
|
||||
errback(err);
|
||||
});
|
||||
|
||||
request.on('response', function(response) {
|
||||
clearTimeout(reqTimeout);
|
||||
|
||||
// We need to buffer the response chunks in a nonblocking way.
|
||||
var buffer = '';
|
||||
response.on('data', function(chunk) {
|
||||
buffer = buffer + chunk;
|
||||
});
|
||||
// When all the responses are finished, we decode the JSON and
|
||||
// depending on whether it's got a result or an error, we call
|
||||
// emitSuccess or emitError on the promise.
|
||||
response.on('end', function() {
|
||||
var err;
|
||||
|
||||
if (cbCalled) return;
|
||||
cbCalled = true;
|
||||
|
||||
try {
|
||||
var decoded = JSON.parse(buffer);
|
||||
} catch (e) {
|
||||
if (response.statusCode !== 200) {
|
||||
err = new Error('Invalid params, response status code: ' + response.statusCode);
|
||||
err.code = -32602;
|
||||
errback(err);
|
||||
} else {
|
||||
err = new Error('Problem parsing JSON response from server');
|
||||
err.code = -32603;
|
||||
errback(err);
|
||||
}
|
||||
return;
|
||||
if (Array.isArray(method)) {
|
||||
// multiple rpc batch call
|
||||
requestJSON = []
|
||||
method.forEach(function (batchCall, i) {
|
||||
requestJSON.push({
|
||||
id: time + '-' + i,
|
||||
method: batchCall.method,
|
||||
params: batchCall.params
|
||||
})
|
||||
})
|
||||
} else {
|
||||
// single rpc call
|
||||
requestJSON = {
|
||||
id: time,
|
||||
method: method,
|
||||
params: params
|
||||
}
|
||||
|
||||
if (!Array.isArray(decoded)) {
|
||||
decoded = [decoded];
|
||||
}
|
||||
|
||||
// iterate over each response, normally there will be just one
|
||||
// unless a batch rpc call response is being processed
|
||||
decoded.forEach(function(decodedResponse, i) {
|
||||
if (decodedResponse.hasOwnProperty('error') && decodedResponse.error != null) {
|
||||
if (errback) {
|
||||
err = new Error(decodedResponse.error.message || '');
|
||||
if (decodedResponse.error.code) {
|
||||
err.code = decodedResponse.error.code;
|
||||
}
|
||||
errback(err);
|
||||
}
|
||||
} else if (decodedResponse.hasOwnProperty('result')) {
|
||||
if (callback) {
|
||||
callback(decodedResponse.result, response.headers);
|
||||
}
|
||||
} else {
|
||||
if (errback) {
|
||||
err = new Error(decodedResponse.error.message || '');
|
||||
if (decodedResponse.error.code) {
|
||||
err.code = decodedResponse.error.code;
|
||||
}
|
||||
errback(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
request.end(requestJSON);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports.Client = Client;
|
||||
// First we encode the request into JSON
|
||||
requestJSON = JSON.stringify(requestJSON)
|
||||
|
||||
// prepare request options
|
||||
var requestOptions = {
|
||||
host: this.opts.host || 'localhost',
|
||||
port: this.opts.port || 8332,
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
headers: {
|
||||
'Host': this.opts.host || 'localhost',
|
||||
'Content-Length': requestJSON.length
|
||||
},
|
||||
agent: false,
|
||||
rejectUnauthorized: this.opts.ssl && this.opts.sslStrict !== false
|
||||
}
|
||||
|
||||
if (this.opts.ssl && this.opts.sslCa) {
|
||||
requestOptions.ca = this.opts.sslCa
|
||||
}
|
||||
|
||||
// use HTTP auth if user and password set
|
||||
if (this.opts.user && this.opts.pass) {
|
||||
requestOptions.auth = this.opts.user + ':' + this.opts.pass
|
||||
}
|
||||
|
||||
// Now we'll make a request to the server
|
||||
var cbCalled = false
|
||||
var request = this.http.request(requestOptions)
|
||||
|
||||
// start request timeout timer
|
||||
var reqTimeout = setTimeout(function () {
|
||||
if (cbCalled) return
|
||||
cbCalled = true
|
||||
request.abort()
|
||||
var err = new Error('ETIMEDOUT')
|
||||
err.code = 'ETIMEDOUT'
|
||||
reject(err)
|
||||
}, this.opts.timeout || 30000)
|
||||
|
||||
// set additional timeout on socket in case of remote freeze after sending headers
|
||||
request.setTimeout(this.opts.timeout || 30000, function () {
|
||||
if (cbCalled) return
|
||||
cbCalled = true
|
||||
request.abort()
|
||||
var err = new Error('ESOCKETTIMEDOUT')
|
||||
err.code = 'ESOCKETTIMEDOUT'
|
||||
reject(err)
|
||||
})
|
||||
|
||||
request.on('error', function (err) {
|
||||
if (cbCalled) return
|
||||
cbCalled = true
|
||||
clearTimeout(reqTimeout)
|
||||
reject(err)
|
||||
})
|
||||
|
||||
request.on('response', function (response) {
|
||||
clearTimeout(reqTimeout)
|
||||
|
||||
// We need to buffer the response chunks in a nonblocking way.
|
||||
var buffer = ''
|
||||
response.on('data', function (chunk) {
|
||||
buffer = buffer + chunk
|
||||
})
|
||||
// When all the responses are finished, we decode the JSON and
|
||||
// depending on whether it's got a result or an error, we call
|
||||
// emitSuccess or emitError on the promise.
|
||||
response.on('end', function () {
|
||||
var err
|
||||
|
||||
if (cbCalled) return
|
||||
cbCalled = true
|
||||
|
||||
try {
|
||||
var decoded = JSON.parse(buffer)
|
||||
} catch (e) {
|
||||
if (response.statusCode !== 200) {
|
||||
err = new Error('Invalid params, response status code: ' + response.statusCode)
|
||||
err.code = -32602
|
||||
reject(err)
|
||||
} else {
|
||||
err = new Error('Problem parsing JSON response from server')
|
||||
err.code = -32603
|
||||
reject(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (!Array.isArray(decoded)) {
|
||||
decoded = [decoded]
|
||||
}
|
||||
|
||||
// iterate over each response, normally there will be just one
|
||||
// unless a batch rpc call response is being processed
|
||||
decoded.forEach(function (decodedResponse, i) {
|
||||
if (decodedResponse.hasOwnProperty('error') && decodedResponse.error != null) {
|
||||
if (reject) {
|
||||
err = new Error(decodedResponse.error.message || '')
|
||||
if (decodedResponse.error.code) {
|
||||
err.code = decodedResponse.error.code
|
||||
}
|
||||
reject(err)
|
||||
}
|
||||
} else if (decodedResponse.hasOwnProperty('result')) {
|
||||
resolve(decodedResponse.result, response.headers)
|
||||
} else {
|
||||
if (reject) {
|
||||
err = new Error(decodedResponse.error.message || '')
|
||||
if (decodedResponse.error.code) {
|
||||
err.code = decodedResponse.error.code
|
||||
}
|
||||
reject(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
request.end(requestJSON);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports.Client = Client
|
||||
|
||||
24
package.json
24
package.json
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "bitcoin",
|
||||
"name": "@mempool/bitcoin",
|
||||
"description": "Communicate with bitcoind via JSON-RPC",
|
||||
"version": "2.1.0",
|
||||
"version": "3.0.3",
|
||||
"main": "lib/index.js",
|
||||
"keywords": [
|
||||
"bitcoin",
|
||||
@ -13,18 +13,28 @@
|
||||
],
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"mocha": "~1.13.0",
|
||||
"clone": "~0.1.10"
|
||||
"clone": "^1.0.2",
|
||||
"mocha": "^2.3.3",
|
||||
"standard": "^5.3.1"
|
||||
},
|
||||
"optionalDependencies": {},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/freewil/node-bitcoin.git"
|
||||
"url": "git://github.com/mempool/node-bitcoin.git"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
"node": ">= 0.10.0"
|
||||
},
|
||||
"scripts": {
|
||||
"pretest": "standard --verbose",
|
||||
"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"
|
||||
}
|
||||
|
||||
563
test/index.js
563
test/index.js
@ -1,317 +1,292 @@
|
||||
var assert = require('assert'),
|
||||
clone = require('clone'),
|
||||
http = require('http'),
|
||||
bitcoin = require('../'),
|
||||
config = require('./config');
|
||||
/* global describe, it */
|
||||
|
||||
var assert = require('assert')
|
||||
var clone = require('clone')
|
||||
var http = require('http')
|
||||
var bitcoin = require('../')
|
||||
var config = require('./config')
|
||||
|
||||
var test = {
|
||||
account: 'test'
|
||||
};
|
||||
}
|
||||
|
||||
var makeClient = function makeClient() {
|
||||
return new bitcoin.Client(config);
|
||||
};
|
||||
var makeClient = function makeClient () {
|
||||
return new bitcoin.Client(config)
|
||||
}
|
||||
|
||||
var notEmpty = function notEmpty(data) {
|
||||
if (data === 0) return;
|
||||
assert.ok(data);
|
||||
};
|
||||
var notEmpty = function notEmpty (data) {
|
||||
if (data === 0) return
|
||||
assert.ok(data)
|
||||
}
|
||||
|
||||
var makeServer = function(port) {
|
||||
var server = http.createServer();
|
||||
server.listen(port);
|
||||
return server;
|
||||
};
|
||||
var makeServer = function (port) {
|
||||
var server = http.createServer()
|
||||
server.listen(port)
|
||||
return server
|
||||
}
|
||||
|
||||
describe('Client', function() {
|
||||
|
||||
describe('getAccountAddress()', function() {
|
||||
it('should be able to get an account address', function(done) {
|
||||
var client = makeClient();
|
||||
client.getAccountAddress(test.account, function(err, address) {
|
||||
assert.ifError(err);
|
||||
assert.ok(address);
|
||||
client.getAccount(address, function(err, account) {
|
||||
assert.ifError(err);
|
||||
assert.equal(account, test.account);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('listTransactions()', function() {
|
||||
it('should be able to listTransactions with specific count', function(done) {
|
||||
var client = makeClient();
|
||||
client.listTransactions(test.account, 15, function(err, txs) {
|
||||
assert.ifError(err);
|
||||
assert.ok(txs);
|
||||
assert.ok(Array.isArray(txs));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to listTransactions without specific count', function(done) {
|
||||
var client = makeClient();
|
||||
client.listTransactions(test.account, function(err, txs) {
|
||||
assert.ifError(err);
|
||||
assert.ok(txs);
|
||||
assert.ok(Array.isArray(txs));
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getNewAddress()', function() {
|
||||
it('should be able to get new address', function(done) {
|
||||
var client = makeClient();
|
||||
client.getNewAddress(test.account, function(err, address) {
|
||||
assert.ifError(err);
|
||||
client.getAddressesByAccount(test.account, function(err, addresses) {
|
||||
assert.ifError(err);
|
||||
assert.ok(addresses && addresses.length > 0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getBalance()', function() {
|
||||
it('should return balance without any args', function(done) {
|
||||
var client = makeClient();
|
||||
client.getBalance(function(err, balance) {
|
||||
assert.ifError(err);
|
||||
assert.ok(typeof balance === 'number');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDifficulty()', function() {
|
||||
it('should get difficulty', function(done) {
|
||||
var client = makeClient();
|
||||
client.getDifficulty(function(err, difficulty) {
|
||||
assert.ifError(err);
|
||||
assert.ok(typeof difficulty === 'number');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getInfo()', function() {
|
||||
it('should get info', function(done) {
|
||||
var client = makeClient();
|
||||
client.getInfo(function(err, info, headers) {
|
||||
assert.ifError(err);
|
||||
notEmpty(info);
|
||||
assert.ok(info.errors === '');
|
||||
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() {
|
||||
it('should return help', function(done) {
|
||||
var client = makeClient();
|
||||
client.help(function(err, help) {
|
||||
assert.ifError(err);
|
||||
notEmpty(help);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getWork()', function() {
|
||||
it('should get work', function(done) {
|
||||
var client = makeClient();
|
||||
client.getWork(function(err, work) {
|
||||
assert.ifError(err);
|
||||
notEmpty(work);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('bitcoin related error should be an Error object', function(done) {
|
||||
var client = makeClient();
|
||||
client.cmd('nomethod', function(err, expectedValue) {
|
||||
assert.ok(err instanceof Error);
|
||||
assert.equal(err.message, 'Method not found');
|
||||
assert.equal(err.code, -32601);
|
||||
assert.equal(expectedValue, undefined);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('running batch of rpc calls', function(done) {
|
||||
this.timeout(5000);
|
||||
var batch = [];
|
||||
describe('Client', function () {
|
||||
describe('getAccountAddress()', function () {
|
||||
it('should be able to get an account address', function (done) {
|
||||
var client = makeClient()
|
||||
client.getAccountAddress(test.account, function (err, address) {
|
||||
assert.ifError(err)
|
||||
assert.ok(address)
|
||||
client.getAccount(address, function (err, account) {
|
||||
assert.ifError(err)
|
||||
assert.equal(account, test.account)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('listTransactions()', function () {
|
||||
it('should be able to listTransactions with specific count', function (done) {
|
||||
var client = makeClient()
|
||||
client.listTransactions(test.account, 15, function (err, txs) {
|
||||
assert.ifError(err)
|
||||
assert.ok(txs)
|
||||
assert.ok(Array.isArray(txs))
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('should be able to listTransactions without specific count', function (done) {
|
||||
var client = makeClient()
|
||||
client.listTransactions(test.account, function (err, txs) {
|
||||
assert.ifError(err)
|
||||
assert.ok(txs)
|
||||
assert.ok(Array.isArray(txs))
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('getNewAddress()', function () {
|
||||
it('should be able to get new address', function (done) {
|
||||
var client = makeClient()
|
||||
client.getNewAddress(test.account, function (err, address) {
|
||||
assert.ifError(err)
|
||||
client.getAddressesByAccount(test.account, function (err, addresses) {
|
||||
assert.ifError(err)
|
||||
assert.ok(addresses && addresses.length > 0)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('getBalance()', function () {
|
||||
it('should return balance without any args', function (done) {
|
||||
var client = makeClient()
|
||||
client.getBalance(function (err, balance) {
|
||||
assert.ifError(err)
|
||||
assert.ok(typeof balance === 'number')
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('getDifficulty()', function () {
|
||||
it('should get difficulty', function (done) {
|
||||
var client = makeClient()
|
||||
client.getDifficulty(function (err, difficulty) {
|
||||
assert.ifError(err)
|
||||
assert.ok(typeof difficulty === 'number')
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('getInfo()', function () {
|
||||
it('should get info', function (done) {
|
||||
var client = makeClient()
|
||||
client.getInfo(function (err, info, headers) {
|
||||
assert.ifError(err)
|
||||
notEmpty(info)
|
||||
assert.ok(info.errors === '')
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('help()', function () {
|
||||
it('should return help', function (done) {
|
||||
var client = makeClient()
|
||||
client.help(function (err, help) {
|
||||
assert.ifError(err)
|
||||
notEmpty(help)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('bitcoin related error should be an Error object', function (done) {
|
||||
var client = makeClient()
|
||||
client.cmd('nomethod', function (err, expectedValue) {
|
||||
assert.ok(err instanceof Error)
|
||||
assert.equal(err.message, 'Method not found')
|
||||
assert.equal(err.code, -32601)
|
||||
assert.equal(expectedValue, undefined)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('running batch of rpc calls', function (done) {
|
||||
this.timeout(5000)
|
||||
var batch = []
|
||||
for (var i = 0; i < 10; ++i) {
|
||||
batch.push({
|
||||
method: 'getnewaddress',
|
||||
params: [test.account]
|
||||
});
|
||||
})
|
||||
}
|
||||
var client = makeClient();
|
||||
var batchCallbackCount = 0;
|
||||
client.cmd(batch, function(err, address) {
|
||||
assert.ifError(err);
|
||||
assert.ok(++batchCallbackCount <= 10);
|
||||
assert.ok(address);
|
||||
if (batchCallbackCount === 10) done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('invalid credentials', function() {
|
||||
var badCredentials = clone(config);
|
||||
badCredentials.user = 'baduser';
|
||||
badCredentials.pass = 'badpwd';
|
||||
var client = new bitcoin.Client(badCredentials);
|
||||
|
||||
it('should still return client object', function(done) {
|
||||
assert.ok(client instanceof bitcoin.Client);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should return status 401 with html', function(done) {
|
||||
client.getDifficulty(function(err, difficulty) {
|
||||
assert.ok(err instanceof Error);
|
||||
assert.equal(err.message, 'Invalid params, response status code: 401');
|
||||
assert.equal(err.code, -32602);
|
||||
assert.equal(difficulty, undefined);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('creating client on non-listening port', function() {
|
||||
var badPort = clone(config);
|
||||
badPort.port = 9897;
|
||||
badPort.user = 'baduser';
|
||||
badPort.pass = 'badpwd';
|
||||
var client = new bitcoin.Client(badPort);
|
||||
|
||||
it('will return client object', function(done) {
|
||||
assert.ok(client instanceof bitcoin.Client);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should not call callback more than once', function(done) {
|
||||
client.listSinceBlock(function(err, result) {
|
||||
assert.ok(err instanceof Error);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('request timeouts', function() {
|
||||
it('should occur by default after 5000ms', function(done) {
|
||||
this.timeout(7500);
|
||||
var server = makeServer(19998);
|
||||
var request;
|
||||
var response;
|
||||
server.on('request', function(req, res) {
|
||||
request = req;
|
||||
response = res;
|
||||
});
|
||||
var client = makeClient()
|
||||
var batchCallbackCount = 0
|
||||
client.cmd(batch, function (err, address) {
|
||||
assert.ifError(err)
|
||||
assert.ok(++batchCallbackCount <= 10)
|
||||
assert.ok(address)
|
||||
if (batchCallbackCount === 10) done()
|
||||
})
|
||||
})
|
||||
|
||||
describe('invalid credentials', function () {
|
||||
var badCredentials = clone(config)
|
||||
badCredentials.user = 'baduser'
|
||||
badCredentials.pass = 'badpwd'
|
||||
var client = new bitcoin.Client(badCredentials)
|
||||
|
||||
it('should still return client object', function (done) {
|
||||
assert.ok(client instanceof bitcoin.Client)
|
||||
done()
|
||||
})
|
||||
|
||||
it('should return status 401 with html', function (done) {
|
||||
client.getDifficulty(function (err, difficulty) {
|
||||
assert.ok(err instanceof Error)
|
||||
assert.equal(err.message, 'Invalid params, response status code: 401')
|
||||
assert.equal(err.code, -32602)
|
||||
assert.equal(difficulty, undefined)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('creating client on non-listening port', function () {
|
||||
var badPort = clone(config)
|
||||
badPort.port = 9897
|
||||
badPort.user = 'baduser'
|
||||
badPort.pass = 'badpwd'
|
||||
var client = new bitcoin.Client(badPort)
|
||||
|
||||
it('will return client object', function (done) {
|
||||
assert.ok(client instanceof bitcoin.Client)
|
||||
done()
|
||||
})
|
||||
|
||||
it('should not call callback more than once', function (done) {
|
||||
client.listSinceBlock(function (err, result) {
|
||||
assert.ok(err instanceof Error)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('request timeouts', function () {
|
||||
it('should occur by default after 30000ms', function (done) {
|
||||
this.timeout(31000)
|
||||
var server = makeServer(19998)
|
||||
var request // eslint-disable-line no-unused-vars
|
||||
var response
|
||||
server.on('request', function (req, res) {
|
||||
request = req
|
||||
response = res
|
||||
})
|
||||
var client = new bitcoin.Client({
|
||||
host: 'localhost',
|
||||
port: 19998,
|
||||
user: 'admin1',
|
||||
pass: '123'
|
||||
});
|
||||
var start = Date.now();
|
||||
client.getInfo(function(err, info) {
|
||||
var delta = Date.now() - start;
|
||||
assert.ok(err instanceof Error);
|
||||
assert.ok(err.code === 'ETIMEDOUT' || err.code === 'ESOCKETTIMEDOUT');
|
||||
assert.ok(delta >= 5000, 'delta should be >= 5000: ' + delta);
|
||||
response.end();
|
||||
server.close();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should be customizable', function(done) {
|
||||
this.timeout(4500);
|
||||
var server = makeServer(19999);
|
||||
var request;
|
||||
var response;
|
||||
server.on('request', function(req, res) {
|
||||
request = req;
|
||||
response = res;
|
||||
});
|
||||
})
|
||||
var start = Date.now()
|
||||
client.getInfo(function (err, info) {
|
||||
var delta = Date.now() - start
|
||||
assert.ok(err instanceof Error)
|
||||
assert.ok(err.code === 'ETIMEDOUT' || err.code === 'ESOCKETTIMEDOUT')
|
||||
assert.ok(delta >= 30000, 'delta should be >= 30000: ' + delta)
|
||||
response.end()
|
||||
server.close()
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('should be customizable', function (done) {
|
||||
this.timeout(4500)
|
||||
var server = makeServer(19999)
|
||||
var request // eslint-disable-line no-unused-vars
|
||||
var response
|
||||
server.on('request', function (req, res) {
|
||||
request = req
|
||||
response = res
|
||||
})
|
||||
var client = new bitcoin.Client({
|
||||
host: 'localhost',
|
||||
port: 19999,
|
||||
user: 'admin1',
|
||||
pass: '123',
|
||||
timeout: 2500
|
||||
});
|
||||
var start = Date.now();
|
||||
client.getInfo(function(err, info) {
|
||||
var delta = Date.now() - start;
|
||||
assert.ok(err instanceof Error);
|
||||
assert.ok(err.code === 'ETIMEDOUT' || err.code === 'ESOCKETTIMEDOUT');
|
||||
assert.ok(delta >= 2500, 'delta should be >= 2500:' + delta);
|
||||
response.end();
|
||||
server.close();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('response headers', function() {
|
||||
var assertResHeaders = function(resHeaders) {
|
||||
assert.ok(resHeaders);
|
||||
assert.ok(resHeaders.server);
|
||||
assert.ok(/bitcoin/.test(resHeaders.server));
|
||||
};
|
||||
it('should be returned for no parameter calls', function(done) {
|
||||
var client = makeClient();
|
||||
client.getInfo(function(err, info, resHeaders) {
|
||||
assert.ifError(err);
|
||||
notEmpty(info);
|
||||
assert.ok(info.errors === '');
|
||||
assertResHeaders(resHeaders);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should be returned for 1-parameter call', function(done) {
|
||||
var client = makeClient();
|
||||
client.getNewAddress(test.account, function(err, address, resHeaders) {
|
||||
assert.ifError(err);
|
||||
assert.ok(address);
|
||||
assertResHeaders(resHeaders);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should be returned for 2-parameter call', function(done) {
|
||||
var client = makeClient();
|
||||
client.listTransactions(test.account, 15, function(err, txs, resHeaders) {
|
||||
assert.ifError(err);
|
||||
assert.ok(txs);
|
||||
assert.ok(Array.isArray(txs));
|
||||
assertResHeaders(resHeaders);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
})
|
||||
var start = Date.now()
|
||||
client.getInfo(function (err, info) {
|
||||
var delta = Date.now() - start
|
||||
assert.ok(err instanceof Error)
|
||||
assert.ok(err.code === 'ETIMEDOUT' || err.code === 'ESOCKETTIMEDOUT')
|
||||
assert.ok(delta >= 2500, 'delta should be >= 2500:' + delta)
|
||||
response.end()
|
||||
server.close()
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('response headers', function () {
|
||||
var assertResHeaders = function (resHeaders) {
|
||||
assert.ok(resHeaders)
|
||||
assert.ok(resHeaders.server)
|
||||
assert.ok(/bitcoin/.test(resHeaders.server))
|
||||
}
|
||||
it('should be returned for no parameter calls', function (done) {
|
||||
var client = makeClient()
|
||||
client.getInfo(function (err, info, resHeaders) {
|
||||
assert.ifError(err)
|
||||
notEmpty(info)
|
||||
assert.ok(info.errors === '')
|
||||
assertResHeaders(resHeaders)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('should be returned for 1-parameter call', function (done) {
|
||||
var client = makeClient()
|
||||
client.getNewAddress(test.account, function (err, address, resHeaders) {
|
||||
assert.ifError(err)
|
||||
assert.ok(address)
|
||||
assertResHeaders(resHeaders)
|
||||
done()
|
||||
})
|
||||
|
||||
it('should be returned for 2-parameter call', function (done) {
|
||||
var client = makeClient()
|
||||
client.listTransactions(test.account, 15, function (err, txs, resHeaders) {
|
||||
assert.ifError(err)
|
||||
assert.ok(txs)
|
||||
assert.ok(Array.isArray(txs))
|
||||
assertResHeaders(resHeaders)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,78 +1,75 @@
|
||||
var assert = require('assert'),
|
||||
bitcoin = require('../'),
|
||||
config = require('./config'),
|
||||
commands = require('../lib/commands');
|
||||
|
||||
|
||||
var getHelpCommands = function(client, cb) {
|
||||
var commandRegex = /^([a-z]+)/;
|
||||
client.cmd('help', function(err, commandList) {
|
||||
if (err) return cb(err);
|
||||
|
||||
var helpCommands = [];
|
||||
|
||||
/* global describe, it */
|
||||
|
||||
var assert = require('assert')
|
||||
var bitcoin = require('../')
|
||||
var config = require('./config')
|
||||
var commands = require('../lib/commands')
|
||||
|
||||
var getHelpCommands = function (client, cb) {
|
||||
var commandRegex = /^([a-z]+)/
|
||||
client.cmd('help', function (err, commandList) {
|
||||
if (err) return cb(err)
|
||||
|
||||
var helpCommands = []
|
||||
|
||||
// split up the command list by newlines
|
||||
var commandListLines = commandList.split('\n');
|
||||
var result;
|
||||
var commandListLines = commandList.split('\n')
|
||||
var result
|
||||
for (var i in commandListLines) {
|
||||
result = commandRegex.exec(commandListLines[i]);
|
||||
if (!result) {
|
||||
return cb(new Error('command list line failed to match regex: ' + commandListLines[i]));
|
||||
}
|
||||
helpCommands.push(result[1]);
|
||||
result = commandRegex.exec(commandListLines[i])
|
||||
if (!result) continue
|
||||
helpCommands.push(result[1])
|
||||
}
|
||||
cb(null, helpCommands);
|
||||
});
|
||||
};
|
||||
|
||||
describe('Client Commands', function() {
|
||||
|
||||
it('should have all the commands listed by `help`', function(done) {
|
||||
var client = new bitcoin.Client(config);
|
||||
getHelpCommands(client, function(err, helpCommands) {
|
||||
assert.ifError(err);
|
||||
|
||||
cb(null, helpCommands)
|
||||
})
|
||||
}
|
||||
|
||||
describe('Client Commands', function () {
|
||||
it('should have all the commands listed by `help`', function (done) {
|
||||
var client = new bitcoin.Client(config)
|
||||
getHelpCommands(client, function (err, helpCommands) {
|
||||
assert.ifError(err)
|
||||
|
||||
for (var i in helpCommands) {
|
||||
var found = true;
|
||||
var found = false
|
||||
for (var j in commands) {
|
||||
if (commands[j] === helpCommands[i]) {
|
||||
found = true;
|
||||
break;
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
assert.ok(found, 'missing command found in `help`: ' + helpCommands[i]);
|
||||
assert.ok(found, 'missing command found in `help`: ' + helpCommands[i])
|
||||
}
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not have any commands not listed by `help`', function(done) {
|
||||
var client = new bitcoin.Client(config);
|
||||
getHelpCommands(client, function(err, helpCommands) {
|
||||
assert.ifError(err);
|
||||
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('should not have any commands not listed by `help`', function (done) {
|
||||
var client = new bitcoin.Client(config)
|
||||
getHelpCommands(client, function (err, helpCommands) {
|
||||
assert.ifError(err)
|
||||
|
||||
for (var i in commands) {
|
||||
var found = false;
|
||||
var found = false
|
||||
for (var j in helpCommands) {
|
||||
if (commands[i] === helpCommands[j]) {
|
||||
found = true;
|
||||
break;
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ignore commands not found in help because they are hidden
|
||||
// if the wallet isn't encrypted
|
||||
var ignore = ['walletlock', 'walletpassphrase', 'walletpassphrasechange'];
|
||||
var ignore = ['walletlock', 'walletpassphrase', 'walletpassphrasechange']
|
||||
if (~ignore.indexOf(commands[i])) {
|
||||
assert.ok(!found, 'command found in `help`: ' + commands[i]);
|
||||
assert.ok(!found, 'command found in `help`: ' + commands[i])
|
||||
} else {
|
||||
assert.ok(found, 'command not found in `help`: ' + commands[i]);
|
||||
assert.ok(found, 'command not found in `help`: ' + commands[i])
|
||||
}
|
||||
}
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
119
test/ssl.js
119
test/ssl.js
@ -1,56 +1,63 @@
|
||||
var assert = require('assert'),
|
||||
fs = require('fs'),
|
||||
clone = require('clone'),
|
||||
bitcoin = require('../'),
|
||||
config = require('./config');
|
||||
|
||||
var getInfo = function(opts, cb) {
|
||||
var client = new bitcoin.Client(opts);
|
||||
client.getInfo(cb);
|
||||
};
|
||||
|
||||
describe('Client SSL', function() {
|
||||
it('use sslStrict by default', function(done) {
|
||||
var opts = clone(config);
|
||||
opts.ssl = true;
|
||||
getInfo(opts, function(err, info) {
|
||||
assert.ok(err instanceof Error);
|
||||
assert.equal(err.message, 'DEPTH_ZERO_SELF_SIGNED_CERT');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('strictSSL should fail with self-signed certificate', function(done) {
|
||||
var opts = clone(config);
|
||||
opts.ssl = true;
|
||||
opts.sslStrict = true;
|
||||
getInfo(opts, function(err, info) {
|
||||
assert.ok(err instanceof Error);
|
||||
assert.equal(err.message, 'DEPTH_ZERO_SELF_SIGNED_CERT');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('self-signed certificate with sslStrict false', function(done) {
|
||||
var opts = clone(config);
|
||||
opts.ssl = true;
|
||||
opts.sslStrict = false;
|
||||
getInfo(opts, function(err, info) {
|
||||
assert.ifError(err);
|
||||
assert.ok(info);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('self-signed certificate with sslStrict and CA specified', function(done) {
|
||||
var opts = clone(config);
|
||||
opts.ssl = true;
|
||||
opts.sslCa = fs.readFileSync(__dirname + '/testnet-box/1/testnet3/server.cert');
|
||||
getInfo(opts, function(err, info) {
|
||||
assert.ifError(err);
|
||||
assert.ok(info);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
/* global describe, it */
|
||||
|
||||
var assert = require('assert')
|
||||
var fs = require('fs')
|
||||
var clone = require('clone')
|
||||
var bitcoin = require('../')
|
||||
var config = require('./config')
|
||||
|
||||
var getInfo = function (opts, cb) {
|
||||
var client = new bitcoin.Client(opts)
|
||||
client.getInfo(cb)
|
||||
}
|
||||
|
||||
describe('Client SSL', function () {
|
||||
it('use sslStrict by default', function (done) {
|
||||
var opts = clone(config)
|
||||
opts.ssl = true
|
||||
getInfo(opts, function (err, info) {
|
||||
assert.ok(err instanceof Error)
|
||||
// node v0.11 adds `code` param to this error
|
||||
// and uses a user-friendly `message`
|
||||
// continue using err.message for v0.8 and v0.10
|
||||
assert.equal(err.code || err.message, 'DEPTH_ZERO_SELF_SIGNED_CERT')
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('strictSSL should fail with self-signed certificate', function (done) {
|
||||
var opts = clone(config)
|
||||
opts.ssl = true
|
||||
opts.sslStrict = true
|
||||
getInfo(opts, function (err, info) {
|
||||
assert.ok(err instanceof Error)
|
||||
// node v0.11 adds `code` param to this error
|
||||
// and uses a user-friendly `message`
|
||||
// continue using err.message for v0.8 and v0.10
|
||||
assert.equal(err.code || err.message, 'DEPTH_ZERO_SELF_SIGNED_CERT')
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('self-signed certificate with sslStrict false', function (done) {
|
||||
var opts = clone(config)
|
||||
opts.ssl = true
|
||||
opts.sslStrict = false
|
||||
getInfo(opts, function (err, info) {
|
||||
assert.ifError(err)
|
||||
assert.ok(info)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('self-signed certificate with sslStrict and CA specified', function (done) {
|
||||
var opts = clone(config)
|
||||
opts.ssl = true
|
||||
opts.sslCa = fs.readFileSync(__dirname + '/testnet-box/1/regtest/server.cert')
|
||||
getInfo(opts, function (err, info) {
|
||||
assert.ifError(err)
|
||||
assert.ok(info)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit 9427aeb95b3ef23fcfa44dcd72aeea18a2a16981
|
||||
Subproject commit 24f5214acfddfec498cca21dd96dac480e9b9013
|
||||
Loading…
Reference in New Issue
Block a user