From 0bbc388ca61ccacf526bc7b72ddff2a3f04c871f Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 21 Jul 2015 09:09:59 -0400 Subject: [PATCH 1/3] Cleanup configuration options --- .jshintrc | 42 +++++++++++++++++++++++++++++++++++++ README.md | 10 ++++++++- benchmarks/index.js | 2 +- example/node.js | 24 ++++----------------- lib/node.js | 51 ++++++++++++++++++++++++++++++++++++++++----- package.json | 2 +- 6 files changed, 103 insertions(+), 28 deletions(-) create mode 100644 .jshintrc diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 00000000..9d37e492 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,42 @@ +{ + "bitwise": false, + "browser": true, + "camelcase": false, + "curly": true, + "devel": false, + "eqeqeq": true, + "esnext": true, + "freeze": true, + "immed": true, + "indent": 2, + "latedef": true, + "newcap": false, + "noarg": true, + "node": true, + "noempty": true, + "nonew": true, + "quotmark": "single", + "regexp": true, + "smarttabs": false, + "strict": true, + "trailing": true, + "undef": true, + "unused": true, + "maxparams": 4, + "maxstatements": 15, + "maxcomplexity": 10, + "maxdepth": 3, + "maxlen": 120, + "multistr": true, + "predef": [ + "after", + "afterEach", + "before", + "beforeEach", + "describe", + "exports", + "it", + "module", + "require" + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 1b275d8e..8dbc5d61 100644 --- a/README.md +++ b/README.md @@ -20,12 +20,20 @@ npm install var BitcoinNode = require('bitcoind.js'); var configuration = { - directory: '~/.bitcoin', + datadir: '~/.bitcoin', testnet: true }; var node = new BitcoinNode(configuration); +node.on('ready', function() { + console.log('Bitcoin Node Ready'); +}); + +node.on('error', function(err) { + console.error(err); +}); + node.chain.on('addblock', function(block) { console.log('New Best Tip:', block.hash); }); diff --git a/benchmarks/index.js b/benchmarks/index.js index dbe0e980..574d512c 100644 --- a/benchmarks/index.js +++ b/benchmarks/index.js @@ -27,7 +27,7 @@ var fixtureData = { }; var bitcoind = require('../').daemon({ - directory: '~/.bitcoin', + datadir: process.env.BITCOINDJS_DIR || '~/.bitcoin', testnet: true }); diff --git a/example/node.js b/example/node.js index bafc2e37..7d50950d 100644 --- a/example/node.js +++ b/example/node.js @@ -6,32 +6,16 @@ var chainlib = require('chainlib'); var log = chainlib.log; //log.debug = function() {}; -var privkey = 'tprv8ZgxMBicQKsPdj1QowoT9z1tY5Et38qaMjCHZVoPdPFb6narfmYkqTygEVHfUmY78k3HcaEpkyNCAQDANaXtwNe1HLFvcA7nqYj1B7wTSTo'; - var configuration = { - db: { - xprivkey: privkey, - path: './bitcoind.db' - }, - p2p: { - addrs: [ - { - ip: { - v4: '127.0.0.1' - }, - port: 8333 - } - ], - dnsSeed: false - }, - testnet: false + datadir: process.env.BITCOINDJS_DIR || '~/.bitcoin', + testnet: true }; var node = new BitcoinNode(configuration); var startHeight; var count = 100; -var times = Array(count); +var times = new Array(count); node.on('ready', function() { times[node.chain.tip.__height % count] = Date.now(); @@ -52,4 +36,4 @@ node.chain.on('addblock', function(block) { } times[node.chain.tip.__height % count] = Date.now(); -}); \ No newline at end of file +}); diff --git a/lib/node.js b/lib/node.js index 833f4c4b..6c94173b 100644 --- a/lib/node.js +++ b/lib/node.js @@ -6,12 +6,14 @@ var Block = require('./block'); var DB = require('./db'); var chainlib = require('chainlib'); var P2P = chainlib.P2P; +var fs = require('fs'); var BaseNode = chainlib.Node; var util = require('util'); var log = chainlib.log; var bitcore = require('bitcore'); var Networks = bitcore.Networks; var _ = bitcore.deps._; +var $ = bitcore.util.preconditions; var genesis = require('./genesis.json'); var daemon = require('./daemon'); @@ -24,6 +26,7 @@ util.inherits(Node, BaseNode); Node.prototype._loadConfiguration = function(config) { var self = this; + this._loadBitcoinConf(config); this._loadBitcoind(config); Node.super_.prototype._loadConfiguration.call(self, config); }; @@ -47,13 +50,25 @@ Node.prototype.setSyncStrategy = function(strategy) { }; +Node.prototype._loadBitcoinConf = function(config) { + var datadir = config.datadir.replace(/^~/, process.env.HOME); + this.bitcoinConfiguration = {}; + var file = fs.readFileSync(datadir + '/bitcoin.conf'); + var unparsed = file.toString().split('\n'); + for(var i = 0; i < unparsed.length; i++) { + var line = unparsed[i]; + if (!line.match(/^\#/) && line.match(/\=/)) { + var option = line.split('='); + this.bitcoinConfiguration[option[0]] = option[1]; + } + } +}; + Node.prototype._loadBitcoind = function(config) { var bitcoindConfig = {}; - if (config.testnet) { - bitcoindConfig.directory = '~/.bitcoin/testnet3'; - } else { - bitcoindConfig.directory = '~/.bitcoin'; - } + $.checkArgument(config.datadir, 'Please specify "datadir" in configuration options'); + bitcoindConfig.datadir = config.datadir; + bitcoindConfig.testnet = config.testnet; // start the bitcoind daemon this.bitcoind = daemon(bitcoindConfig); @@ -104,6 +119,7 @@ Node.prototype._loadNetwork = function(config) { } else { this.network = Networks.get('livenet'); } + $.checkState(this.network, 'Unrecognized network'); }; Node.prototype._loadDB = function(config) { @@ -116,6 +132,14 @@ Node.prototype._loadDB = function(config) { config.db = {}; } + // Store the additional indexes in a new directory + // based on the network configuration and the datadir + var datadir = config.datadir.replace(/^~/, process.env.HOME); + if (this.network === Networks.testnet) { + config.db.path = datadir + '/testnet3/bitcoindjs.db'; + } else if (this.network === Networks.livenet) { + config.db.path = datadir + '/bitcoindjs.db'; + } config.db.network = this.network; this.db = new DB(config.db); @@ -127,6 +151,23 @@ Node.prototype._loadP2P = function(config) { } config.p2p.noListen = true; config.p2p.network = this.network; + + // We only want to directly connect via p2p to the trusted bitcoind daemon + var port = 8333; + if (this.bitcoinConfiguration.port) { + port = this.bitcoinConfiguration.port; + } else if (this.network === Networks.testnet) { + port = 18333; + } + config.p2p.addrs = [ + { + ip: { + v4: '127.0.0.1' + }, + port: port + } + ]; + config.p2p.dnsSeed = false; config.p2p.Transaction = this.db.Transaction; config.p2p.Block = this.Block; config.p2p.disableSync = true; // Disable p2p syncing and instead use bitcoind sync diff --git a/package.json b/package.json index b7cdd308..74b63809 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "scripts": { "preinstall": "./bin/build-libbitcoind", "install": "./bin/build-bindings", - "start": "export LD_LIBRARY_PATH=`./platform/os.sh osdir` && node example", + "start": "node example", "debug_install": "./bin/build-libbitcoind debug && ./bin/build-bindings debug", "test": "NODE_ENV=test mocha --recursive", "coverage": "istanbul cover _mocha -- --recursive" From 75058b26b9680e7c10a84283b33040d7c3220f4e Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 21 Jul 2015 11:52:08 -0400 Subject: [PATCH 2/3] Add and fix unit tests for configuration options. --- lib/node.js | 8 ++++++-- test/node.unit.js | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/lib/node.js b/lib/node.js index 6c94173b..07b19ca4 100644 --- a/lib/node.js +++ b/lib/node.js @@ -51,6 +51,7 @@ Node.prototype.setSyncStrategy = function(strategy) { }; Node.prototype._loadBitcoinConf = function(config) { + $.checkArgument(config.datadir, 'Please specify "datadir" in configuration options'); var datadir = config.datadir.replace(/^~/, process.env.HOME); this.bitcoinConfiguration = {}; var file = fs.readFileSync(datadir + '/bitcoin.conf'); @@ -66,7 +67,6 @@ Node.prototype._loadBitcoinConf = function(config) { Node.prototype._loadBitcoind = function(config) { var bitcoindConfig = {}; - $.checkArgument(config.datadir, 'Please specify "datadir" in configuration options'); bitcoindConfig.datadir = config.datadir; bitcoindConfig.testnet = config.testnet; @@ -134,11 +134,15 @@ Node.prototype._loadDB = function(config) { // Store the additional indexes in a new directory // based on the network configuration and the datadir + $.checkArgument(config.datadir, 'Please specify "datadir" in configuration options'); + $.checkState(this.network, 'Network property not defined'); var datadir = config.datadir.replace(/^~/, process.env.HOME); if (this.network === Networks.testnet) { config.db.path = datadir + '/testnet3/bitcoindjs.db'; } else if (this.network === Networks.livenet) { config.db.path = datadir + '/bitcoindjs.db'; + } else { + throw new Error('Unknown network: ' + this.network); } config.db.network = this.network; @@ -154,7 +158,7 @@ Node.prototype._loadP2P = function(config) { // We only want to directly connect via p2p to the trusted bitcoind daemon var port = 8333; - if (this.bitcoinConfiguration.port) { + if (this.bitcoinConfiguration && this.bitcoinConfiguration.port) { port = this.bitcoinConfiguration.port; } else if (this.network === Networks.testnet) { port = 18333; diff --git a/test/node.unit.js b/test/node.unit.js index 31345b17..4ad34c89 100644 --- a/test/node.unit.js +++ b/test/node.unit.js @@ -26,9 +26,11 @@ describe('Bitcoind Node', function() { describe('#_loadConfiguration', function() { it('should call the necessary methods', function() { var node = new Node({}); + node._loadBitcoinConf = sinon.spy(); node._loadBitcoind = sinon.spy(); node._loadConfiguration({}); node._loadBitcoind.called.should.equal(true); + node._loadBitcoinConf.called.should.equal(true); BaseNode.prototype._loadConfiguration.called.should.equal(true); }); }); @@ -182,15 +184,44 @@ describe('Bitcoind Node', function() { }); describe('#_loadDB', function() { it('should load the db', function() { - var DB = function() {}; + var DB = function(config) { + config.path.should.equal(process.env.HOME + '/.bitcoin/bitcoindjs.db'); + }; var config = { - DB: DB + DB: DB, + datadir: '~/.bitcoin' }; var node = new Node(config); + node.network = Networks.livenet; node._loadDB(config); node.db.should.be.instanceof(DB); }); + it('should load the db for testnet', function() { + var DB = function(config) { + config.path.should.equal(process.env.HOME + '/.bitcoin/testnet3/bitcoindjs.db'); + }; + var config = { + DB: DB, + datadir: '~/.bitcoin' + }; + + var node = new Node(config); + node.network = Networks.testnet; + node._loadDB(config); + node.db.should.be.instanceof(DB); + }); + it('error with unknown network', function() { + var config = { + datadir: '~/.bitcoin' + }; + + var node = new Node(config); + node.network = 'not a network'; + (function() { + node._loadDB(config); + }).should.throw('Unknown network'); + }); }); describe('#_loadP2P', function() { it('should load p2p', function() { From 4d784ba8f5ef695406e560937fb7354201c6f188 Mon Sep 17 00:00:00 2001 From: Braydon Fuller Date: Tue, 21 Jul 2015 12:17:28 -0400 Subject: [PATCH 3/3] Add test for loading bitcoin.conf --- lib/node.js | 8 +++++++- test/data/bitcoin.conf | 17 +++++++++++++++++ test/node.unit.js | 25 ++++++++++++++++++++++++- 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 test/data/bitcoin.conf diff --git a/lib/node.js b/lib/node.js index 07b19ca4..decc99e6 100644 --- a/lib/node.js +++ b/lib/node.js @@ -60,7 +60,13 @@ Node.prototype._loadBitcoinConf = function(config) { var line = unparsed[i]; if (!line.match(/^\#/) && line.match(/\=/)) { var option = line.split('='); - this.bitcoinConfiguration[option[0]] = option[1]; + var value; + if (!Number.isNaN(Number(option[1]))) { + value = Number(option[1]); + } else { + value = option[1]; + } + this.bitcoinConfiguration[option[0]] = value; } } }; diff --git a/test/data/bitcoin.conf b/test/data/bitcoin.conf new file mode 100644 index 00000000..475d225d --- /dev/null +++ b/test/data/bitcoin.conf @@ -0,0 +1,17 @@ +#testnet=1 +#irc=0 +#upnp=0 +server=1 + +whitelist=127.0.0.1 +txindex=1 + +# listen on different ports +port=20000 + +rpcallowip=127.0.0.1 + +rpcuser=bitcoin +rpcpassword=local321 + + diff --git a/test/node.unit.js b/test/node.unit.js index 4ad34c89..5d607681 100644 --- a/test/node.unit.js +++ b/test/node.unit.js @@ -11,6 +11,8 @@ var Block = require('../lib/block'); var proxyquire = require('proxyquire'); var chainlib = require('chainlib'); var OriginalNode = chainlib.Node; +var fs = require('fs'); +var bitcoinConfBuffer = fs.readFileSync('./test/data/bitcoin.conf'); var BaseNode = function() {}; util.inherits(BaseNode, EventEmitter); @@ -19,7 +21,12 @@ BaseNode.prototype._loadConfiguration = sinon.spy(); BaseNode.prototype._initialize = sinon.spy(); chainlib.Node = BaseNode; -var Node = proxyquire('../lib/node', {chainlib: chainlib}); +var Node = proxyquire('../lib/node', { + chainlib: chainlib, + fs: { + readFileSync: sinon.stub().returns(bitcoinConfBuffer) + } +}); chainlib.Node = OriginalNode; describe('Bitcoind Node', function() { @@ -58,6 +65,22 @@ describe('Bitcoind Node', function() { }).should.throw('Strategy "unknown" is unknown'); }); }); + describe('#_loadBitcoinConf', function() { + it('will parse a bitcoin.conf file', function() { + var node = new Node({}); + node._loadBitcoinConf({datadir: '~/.bitcoin'}); + should.exist(node.bitcoinConfiguration); + node.bitcoinConfiguration.should.deep.equal({ + server: 1, + whitelist: '127.0.0.1', + txindex: 1, + port: 20000, + rpcallowip: '127.0.0.1', + rpcuser: 'bitcoin', + rpcpassword: 'local321' + }); + }); + }); describe('#_loadBitcoind', function() { it('should initialize', function() { var node = new Node({});