Convert daemon into bitcoin module.

This commit is contained in:
Braydon Fuller 2015-08-31 09:00:00 -04:00
parent 95a65da87d
commit 96f6604222
17 changed files with 496 additions and 492 deletions

View File

@ -2,17 +2,21 @@
'use strict';
var chainlib = require('chainlib');
var log = chainlib.log;
var index = require('..');
var log = index.log;
process.title = 'libbitcoind';
/**
* daemon
*/
var daemon = require('../').daemon({
datadir: process.env.BITCORENODE_DIR || '~/.bitcoin',
network: process.env.BITCORENODE_NETWORK || 'livenet'
var daemon = require('../').modules.BitcoinModule({
node: {
datadir: process.env.BITCORENODE_DIR || process.env.HOME + '/.bitcoin',
network: {
name: process.env.BITCORENODE_NETWORK || 'livenet'
}
}
});
daemon.start(function() {
@ -54,4 +58,4 @@ function exitHandler(options, err) {
process.on('uncaughtException', exitHandler.bind(null, {exit:true}));
//catches ctrl+c event
process.on('SIGINT', exitHandler.bind(null, {sigint:true}));
process.on('SIGINT', exitHandler.bind(null, {sigint:true}));

View File

@ -1,7 +1,6 @@
'use strict';
module.exports = require('./lib');
module.exports.daemon = require('./lib/daemon');
module.exports.Node = require('./lib/node');
module.exports.Chain = require('./lib/chain');
module.exports.DB = require('./lib/db');
@ -11,6 +10,7 @@ module.exports.errors = require('./lib/errors');
module.exports.modules = {};
module.exports.modules.AddressModule = require('./lib/modules/address');
module.exports.modules.BitcoinModule = require('./lib/modules/bitcoind');
module.exports.scaffold = {};
module.exports.scaffold.create = require('./lib/scaffold/create');

View File

@ -23,7 +23,10 @@ var node;
var should = chai.should();
var BitcoinRPC = require('bitcoind-rpc');
var BitcoreNode = require('..').Node;
var index = require('..');
var BitcoreNode = index.Node;
var AddressModule = index.modules.AddressModule;
var BitcoinModule = index.modules.BitcoinModule;
var testWIF = 'cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG';
var testKey;
var client;
@ -60,7 +63,19 @@ describe('Node Functionality', function() {
var configuration = {
datadir: datadir,
network: 'regtest'
network: 'regtest',
modules: [
{
name: 'bitcoind',
module: BitcoinModule,
dependencies: BitcoinModule.dependencies
},
{
name: 'address',
module: AddressModule,
dependencies: AddressModule.dependencies
}
]
};
node = new BitcoreNode(configuration);
@ -102,7 +117,10 @@ describe('Node Functionality', function() {
after(function(done) {
this.timeout(20000);
node.bitcoind.stop(function(err, result) {
node.stop(function(err, result) {
if(err) {
throw err;
}
done();
});
});

View File

@ -61,9 +61,13 @@ describe('Daemon Binding Functionality', function() {
throw err;
}
bitcoind = require('../').daemon({
datadir: datadir,
network: 'regtest'
bitcoind = require('../').modules.BitcoinModule({
node: {
datadir: datadir,
network: {
name: 'regtest'
}
}
});
bitcoind.on('error', function(err) {

View File

@ -90,7 +90,7 @@ Chain.prototype._onInitialized = function() {
};
Chain.prototype.start = function(callback) {
this.genesis = Block.fromBuffer(this.node.bitcoind.genesisBuffer);
this.genesis = Block.fromBuffer(this.node.modules.bitcoind.genesisBuffer);
this.once('initialized', callback);
this.initialize();
};
@ -152,7 +152,7 @@ Chain.prototype.startBuilder = function() {
Chain.prototype.getWeight = function getWeight(blockHash, callback) {
var self = this;
var blockIndex = self.node.bitcoind.getBlockIndex(blockHash);
var blockIndex = self.node.modules.bitcoind.getBlockIndex(blockHash);
setImmediate(function() {
if (blockIndex) {

View File

@ -1,165 +0,0 @@
'use strict';
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var bitcoind = require('bindings')('bitcoind.node');
var index = require('./');
var log = index.log;
var bitcore = require('bitcore');
var $ = bitcore.util.preconditions;
function Daemon(options) {
var self = this;
if (!(this instanceof Daemon)) {
return new Daemon(options);
}
if (Object.keys(this.instances).length) {
throw new Error('Daemon cannot be instantiated more than once.');
}
EventEmitter.call(this);
$.checkArgument(options.datadir, 'Please specify a datadir');
this.options = options || {};
this.options.datadir = this.options.datadir.replace(/^~/, process.env.HOME);
this.datadir = this.options.datadir;
this.node = options.node;
this.config = this.datadir + '/bitcoin.conf';
Object.keys(exports).forEach(function(key) {
self[key] = exports[key];
});
}
util.inherits(Daemon, EventEmitter);
Daemon.instances = {};
Daemon.prototype.instances = Daemon.instances;
Daemon.__defineGetter__('global', function() {
return Daemon.instances[Object.keys(Daemon.instances)[0]];
});
Daemon.prototype.__defineGetter__('global', function() {
return Daemon.global;
});
Daemon.prototype.start = function(callback) {
var self = this;
if (this.instances[this.datadir]) {
return callback(new Error('Daemon already started'));
}
this.instances[this.datadir] = true;
bitcoind.start(this.options, function(err) {
if(err) {
return callback(err);
}
self._started = true;
bitcoind.onBlocksReady(function(err, result) {
function onTipUpdateListener(result) {
if (result) {
// Emit and event that the tip was updated
self.height = result;
self.emit('tip', result);
// Recursively wait until the next update
bitcoind.onTipUpdate(onTipUpdateListener);
}
}
bitcoind.onTipUpdate(onTipUpdateListener);
bitcoind.startTxMon(function(txs) {
for(var i = 0; i < txs.length; i++) {
self.emit('tx', txs[i]);
}
});
// Set the current chain height
var info = self.getInfo();
self.height = info.blocks;
// Get the genesis block
self.getBlock(0, function(err, block) {
self.genesisBuffer = block;
self.emit('ready', result);
setImmediate(callback);
});
});
});
};
Daemon.prototype.isSynced = function() {
return bitcoind.isSynced();
};
Daemon.prototype.syncPercentage = function() {
return bitcoind.syncPercentage();
};
Daemon.prototype.getBlock = function(blockhash, callback) {
return bitcoind.getBlock(blockhash, callback);
};
Daemon.prototype.isSpent = function(txid, outputIndex) {
return bitcoind.isSpent(txid, outputIndex);
};
Daemon.prototype.getBlockIndex = function(blockHash) {
return bitcoind.getBlockIndex(blockHash);
};
Daemon.prototype.estimateFee = function(blocks) {
return bitcoind.estimateFee(blocks);
};
Daemon.prototype.sendTransaction = function(transaction, allowAbsurdFees) {
return bitcoind.sendTransaction(transaction, allowAbsurdFees);
};
Daemon.prototype.getTransaction = function(txid, queryMempool, callback) {
return bitcoind.getTransaction(txid, queryMempool, callback);
};
Daemon.prototype.getTransactionWithBlockInfo = function(txid, queryMempool, callback) {
return bitcoind.getTransactionWithBlockInfo(txid, queryMempool, callback);
};
Daemon.prototype.getMempoolOutputs = function(address) {
return bitcoind.getMempoolOutputs(address);
};
Daemon.prototype.addMempoolUncheckedTransaction = function(txBuffer) {
return bitcoind.addMempoolUncheckedTransaction(txBuffer);
};
Daemon.prototype.getInfo = function() {
return bitcoind.getInfo();
};
Daemon.prototype.stop = function(callback) {
var self = this;
return bitcoind.stop(function(err, status) {
setImmediate(function() {
if (err) {
return callback(err);
} else {
log.info(status);
return callback();
}
});
});
};
module.exports = Daemon;

View File

@ -71,7 +71,7 @@ DB.prototype.initialize = function() {
};
DB.prototype.start = function(callback) {
this.node.bitcoind.on('tx', this.transactionHandler.bind(this));
this.node.modules.bitcoind.on('tx', this.transactionHandler.bind(this));
this.emit('ready');
setImmediate(callback);
};
@ -93,7 +93,7 @@ DB.prototype.getBlock = function(hash, callback) {
var self = this;
// get block from bitcoind
this.node.bitcoind.getBlock(hash, function(err, blockData) {
this.node.modules.bitcoind.getBlock(hash, function(err, blockData) {
if(err) {
return callback(err);
}
@ -102,7 +102,7 @@ DB.prototype.getBlock = function(hash, callback) {
};
DB.prototype.getPrevHash = function(blockHash, callback) {
var blockIndex = this.node.bitcoind.getBlockIndex(blockHash);
var blockIndex = this.node.modules.bitcoind.getBlockIndex(blockHash);
setImmediate(function() {
if (blockIndex) {
callback(null, blockIndex.prevHash);
@ -118,7 +118,7 @@ DB.prototype.putBlock = function(block, callback) {
};
DB.prototype.getTransaction = function(txid, queryMempool, callback) {
this.node.bitcoind.getTransaction(txid, queryMempool, function(err, txBuffer) {
this.node.modules.bitcoind.getTransaction(txid, queryMempool, function(err, txBuffer) {
if(err) {
return callback(err);
}
@ -131,7 +131,7 @@ DB.prototype.getTransaction = function(txid, queryMempool, callback) {
};
DB.prototype.getTransactionWithBlockInfo = function(txid, queryMempool, callback) {
this.node.bitcoind.getTransactionWithBlockInfo(txid, queryMempool, function(err, obj) {
this.node.modules.bitcoind.getTransactionWithBlockInfo(txid, queryMempool, function(err, obj) {
if(err) {
return callback(err);
}
@ -151,7 +151,7 @@ DB.prototype.sendTransaction = function(tx, callback) {
$.checkArgument(typeof tx === 'string', 'Argument must be a hex string or Transaction');
try {
var txid = this.node.bitcoind.sendTransaction(tx);
var txid = this.node.modules.bitcoind.sendTransaction(tx);
return callback(null, txid);
} catch(err) {
return callback(err);
@ -162,7 +162,7 @@ DB.prototype.estimateFee = function(blocks, callback) {
var self = this;
setImmediate(function() {
callback(null, self.node.bitcoind.estimateFee(blocks));
callback(null, self.node.modules.bitcoind.estimateFee(blocks));
});
};
@ -278,8 +278,9 @@ DB.prototype.blockHandler = function(block, add, callback) {
if(err) {
return next(err);
}
operations = operations.concat(ops);
if (ops) {
operations = operations.concat(ops);
}
next();
});
},

View File

@ -1,9 +1,16 @@
'use strict';
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var Module = function(options) {
EventEmitter.call(this);
this.node = options.node;
};
util.inherits(Module, EventEmitter);
/**
* Describes the dependencies that should be loaded before this module.
*/

View File

@ -21,7 +21,7 @@ var AddressModule = function(options) {
this.subscriptions['address/transaction'] = {};
this.subscriptions['address/balance'] = {};
this.node.bitcoind.on('tx', this.transactionHandler.bind(this));
this.node.modules.bitcoind.on('tx', this.transactionHandler.bind(this));
};
@ -368,7 +368,7 @@ AddressModule.prototype.getOutputs = function(addressStr, queryMempool, callback
}
if(queryMempool) {
outputs = outputs.concat(self.node.bitcoind.getMempoolOutputs(addressStr));
outputs = outputs.concat(self.node.modules.bitcoind.getMempoolOutputs(addressStr));
}
callback(null, outputs);
@ -435,7 +435,7 @@ AddressModule.prototype.isSpent = function(output, queryMempool, callback) {
var txid = output.prevTxId ? output.prevTxId.toString('hex') : output.txid;
setImmediate(function() {
callback(self.node.bitcoind.isSpent(txid, output.outputIndex));
callback(self.node.modules.bitcoind.isSpent(txid, output.outputIndex));
});
};

220
lib/modules/bitcoind.js Normal file
View File

@ -0,0 +1,220 @@
'use strict';
var util = require('util');
var Module = require('../module');
var bindings = require('bindings')('bitcoind.node');
var mkdirp = require('mkdirp');
var fs = require('fs');
var index = require('../');
var log = index.log;
var bitcore = require('bitcore');
var $ = bitcore.util.preconditions;
/**
* Provides an interface to native bindings to Bitcoin Core
* @param {Object} options
* @param {String} options.datadir - The bitcoin data directory
* @param {Node} options.node - A reference to the node
*/
function Bitcoin(options) {
if (!(this instanceof Bitcoin)) {
return new Bitcoin(options);
}
var self = this;
Module.call(this, options);
if (Object.keys(this.instances).length) {
throw new Error('Bitcoin cannot be instantiated more than once.');
}
$.checkState(this.node.datadir, 'Node is missing datadir property');
Object.keys(exports).forEach(function(key) {
self[key] = exports[key];
});
}
util.inherits(Bitcoin, Module);
Bitcoin.dependencies = [];
Bitcoin.instances = {};
Bitcoin.prototype.instances = Bitcoin.instances;
Bitcoin.__defineGetter__('global', function() {
return Bitcoin.instances[Object.keys(Bitcoin.instances)[0]];
});
Bitcoin.prototype.__defineGetter__('global', function() {
return Bitcoin.global;
});
Bitcoin.DEFAULT_CONFIG = 'whitelist=127.0.0.1\n' + 'txindex=1\n';
Bitcoin.prototype._loadConfiguration = function() {
/* jshint maxstatements: 25 */
$.checkArgument(this.node.datadir, 'Please specify "datadir" in configuration options');
var configPath = this.node.datadir + '/bitcoin.conf';
this.configuration = {};
if (!fs.existsSync(this.node.datadir)) {
mkdirp.sync(this.node.datadir);
}
if (!fs.existsSync(configPath)) {
fs.writeFileSync(configPath, Bitcoin.DEFAULT_CONFIG);
}
var file = fs.readFileSync(configPath);
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('=');
var value;
if (!Number.isNaN(Number(option[1]))) {
value = Number(option[1]);
} else {
value = option[1];
}
this.configuration[option[0]] = value;
}
}
$.checkState(
this.configuration.txindex && this.configuration.txindex === 1,
'Txindex option is required in order to use most of the features of bitcore-node. ' +
'Please add "txindex=1" to your configuration and reindex an existing database if ' +
'necessary with reindex=1'
);
};
Bitcoin.prototype.start = function(callback) {
var self = this;
this._loadConfiguration();
if (this.instances[this.datadir]) {
return callback(new Error('Bitcoin already started'));
}
this.instances[this.datadir] = true;
bindings.start({
datadir: this.node.datadir,
network: this.node.network.name
}, function(err) {
if(err) {
return callback(err);
}
self._started = true;
bindings.onBlocksReady(function(err, result) {
function onTipUpdateListener(result) {
if (result) {
// Emit and event that the tip was updated
self.height = result;
self.emit('tip', result);
// TODO stopping status
if(!self.stopping) {
var percentage = self.syncPercentage();
log.info('Bitcoin Core Daemon New Height:', self.height, 'Percentage:', percentage);
}
// Recursively wait until the next update
bindings.onTipUpdate(onTipUpdateListener);
}
}
bindings.onTipUpdate(onTipUpdateListener);
bindings.startTxMon(function(txs) {
for(var i = 0; i < txs.length; i++) {
self.emit('tx', txs[i]);
}
});
// Set the current chain height
var info = self.getInfo();
self.height = info.blocks;
// Get the genesis block
self.getBlock(0, function(err, block) {
self.genesisBuffer = block;
self.emit('ready', result);
log.info('Bitcoin Daemon Ready');
setImmediate(callback);
});
});
});
};
Bitcoin.prototype.isSynced = function() {
return bindings.isSynced();
};
Bitcoin.prototype.syncPercentage = function() {
return bindings.syncPercentage();
};
Bitcoin.prototype.getBlock = function(blockhash, callback) {
return bindings.getBlock(blockhash, callback);
};
Bitcoin.prototype.isSpent = function(txid, outputIndex) {
return bindings.isSpent(txid, outputIndex);
};
Bitcoin.prototype.getBlockIndex = function(blockHash) {
return bindings.getBlockIndex(blockHash);
};
Bitcoin.prototype.estimateFee = function(blocks) {
return bindings.estimateFee(blocks);
};
Bitcoin.prototype.sendTransaction = function(transaction, allowAbsurdFees) {
return bindings.sendTransaction(transaction, allowAbsurdFees);
};
Bitcoin.prototype.getTransaction = function(txid, queryMempool, callback) {
return bindings.getTransaction(txid, queryMempool, callback);
};
Bitcoin.prototype.getTransactionWithBlockInfo = function(txid, queryMempool, callback) {
return bindings.getTransactionWithBlockInfo(txid, queryMempool, callback);
};
Bitcoin.prototype.getMempoolOutputs = function(address) {
return bindings.getMempoolOutputs(address);
};
Bitcoin.prototype.addMempoolUncheckedTransaction = function(txBuffer) {
return bindings.addMempoolUncheckedTransaction(txBuffer);
};
Bitcoin.prototype.getInfo = function() {
return bindings.getInfo();
};
Bitcoin.prototype.stop = function(callback) {
return bindings.stop(function(err, status) {
setImmediate(function() {
if (err) {
return callback(err);
} else {
log.info(status);
return callback();
}
});
});
};
module.exports = Bitcoin;

View File

@ -15,7 +15,6 @@ var Chain = require('./chain');
var DB = require('./db');
var index = require('./');
var log = index.log;
var daemon = require('./daemon');
var Bus = require('./bus');
var BaseModule = require('./module');
@ -37,6 +36,9 @@ function Node(config) {
this._unloadedModules = config.modules;
}
$.checkState(config.datadir, 'Node config expects "datadir"');
this.datadir = config.datadir;
this._loadConfiguration(config);
this._initialize();
}
@ -97,61 +99,12 @@ Node.prototype.getAllPublishEvents = function() {
};
Node.prototype._loadConfiguration = function(config) {
this._loadBitcoinConf(config);
this._loadBitcoind(config);
this._loadNetwork(config);
this._loadDB(config);
this._loadAPI();
this._loadConsensus(config);
};
Node.DEFAULT_DAEMON_CONFIG = 'whitelist=127.0.0.1\n' + 'txindex=1\n';
Node.prototype._loadBitcoinConf = function(config) {
$.checkArgument(config.datadir, 'Please specify "datadir" in configuration options');
var configPath = config.datadir + '/bitcoin.conf';
this.bitcoinConfiguration = {};
if (!fs.existsSync(config.datadir)) {
mkdirp.sync(config.datadir);
}
if (!fs.existsSync(configPath)) {
fs.writeFileSync(configPath, Node.DEFAULT_DAEMON_CONFIG);
}
var file = fs.readFileSync(configPath);
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('=');
var value;
if (!Number.isNaN(Number(option[1]))) {
value = Number(option[1]);
} else {
value = option[1];
}
this.bitcoinConfiguration[option[0]] = value;
}
}
$.checkState((this.bitcoinConfiguration.txindex && this.bitcoinConfiguration.txindex == 1),
'Txindex option is required in order to use most of the features of bitcore-node. \
Please add "txindex=1" to your configuration and reindex an existing database if necessary with reindex=1');
};
Node.prototype._loadBitcoind = function(config) {
var bitcoindConfig = {};
bitcoindConfig.datadir = config.datadir;
bitcoindConfig.network = config.network;
bitcoindConfig.node = this;
// start the bitcoind daemon
this.bitcoind = daemon(bitcoindConfig);
};
/**
* This function will find the common ancestor between the current chain and a forked block,
* by moving backwards from the forked block until it meets the current chain.
@ -182,7 +135,7 @@ Node.prototype._syncBitcoindAncestor = function(block, done) {
// and thus don't need to find the entire chain of hashes.
while(ancestorHash && !currentHashesMap[ancestorHash]) {
var blockIndex = self.bitcoind.getBlockIndex(ancestorHash);
var blockIndex = self.modules.bitcoind.getBlockIndex(ancestorHash);
ancestorHash = blockIndex ? blockIndex.prevHash : null;
}
@ -276,9 +229,9 @@ Node.prototype._syncBitcoind = function() {
async.whilst(function() {
height = self.chain.tip.__height;
return height < self.bitcoind.height && !self.stopping;
return height < self.modules.bitcoind.height && !self.stopping;
}, function(done) {
self.bitcoind.getBlock(height + 1, function(err, blockBuffer) {
self.modules.bitcoind.getBlock(height + 1, function(err, blockBuffer) {
if (err) {
return done(err);
}
@ -340,7 +293,7 @@ Node.prototype._syncBitcoind = function() {
self.chain.lastSavedMetadataThreshold = 0;
// If bitcoind is completely synced
if (self.bitcoind.isSynced()) {
if (self.modules.bitcoind.isSynced()) {
self.emit('synced');
}
@ -433,7 +386,6 @@ Node.prototype._loadAPI = function() {
Node.prototype._initialize = function() {
var self = this;
this._initializeBitcoind();
this._initializeDatabase();
this._initializeChain();
@ -445,30 +397,6 @@ Node.prototype._initialize = function() {
});
};
Node.prototype._initializeBitcoind = function() {
var self = this;
// Notify that there is a new tip
this.bitcoind.on('ready', function() {
log.info('Bitcoin Daemon Ready');
});
// Notify that there is a new tip
this.bitcoind.on('tip', function(height) {
if(!self.stopping) {
var percentage = self.bitcoind.syncPercentage();
log.info('Bitcoin Core Daemon New Height:', height, 'Percentage:', percentage);
self._syncBitcoind();
}
});
this.bitcoind.on('error', function(err) {
Error.captureStackTrace(err);
self.emit('error', err);
});
};
Node.prototype._initializeDatabase = function() {
var self = this;
this.db.on('ready', function() {
@ -482,10 +410,20 @@ Node.prototype._initializeDatabase = function() {
};
Node.prototype._initializeChain = function() {
var self = this;
this.chain.on('ready', function() {
log.info('Bitcoin Chain Ready');
self._syncBitcoind();
// Notify that there is a new tip
self.modules.bitcoind.on('tip', function(height) {
if(!self.stopping) {
var percentage = self.modules.bitcoind.syncPercentage();
log.info('Bitcoin Core Daemon New Height:', height, 'Percentage:', percentage);
self._syncBitcoind();
}
});
});
this.chain.on('error', function(err) {
Error.captureStackTrace(err);
@ -495,10 +433,6 @@ Node.prototype._initializeChain = function() {
Node.prototype.getServices = function() {
var services = [
{
name: 'bitcoind',
dependencies: []
},
{
name: 'db',
dependencies: ['bitcoind'],
@ -535,6 +469,7 @@ Node.prototype.getServiceOrder = function() {
var name = names[i];
var service = servicesByName[name];
$.checkState(service, 'Required dependency "' + name + '" not available.');
// first add the dependencies
addToStack(service.dependencies);
@ -586,7 +521,6 @@ Node.prototype.stop = function(callback) {
services,
function(service, next) {
log.info('Stopping ' + service.name);
if (service.module) {
self.modules[service.name].stop(next);
} else {

View File

@ -13,7 +13,7 @@ function getDefaultConfig() {
datadir: process.env.BITCORENODE_DIR || path.resolve(process.env.HOME, '.bitcoin'),
network: process.env.BITCORENODE_NETWORK || 'livenet',
port: process.env.BITCORENODE_PORT || 3001,
modules: ['address']
modules: ['bitcoind', 'address']
}
};
}

View File

@ -30,8 +30,9 @@ describe('Bitcoin Chain', function() {
it('should call the callback when base chain is initialized', function(done) {
var chain = new Chain();
chain.node = {};
chain.node.bitcoind = {};
chain.node.bitcoind.genesisBuffer = new Buffer('0100000043497fd7f826957108f4a30fd9cec3aeba79972084e90ead01ea330900000000bac8b0fa927c0ac8234287e33c5f74d38d354820e24756ad709d7038fc5f31f020e7494dffff001d03e4b6720101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0420e7494d017f062f503253482fffffffff0100f2052a010000002321021aeaf2f8638a129a3156fbe7e5ef635226b0bafd495ff03afe2c843d7e3a4b51ac00000000', 'hex');
chain.node.modules = {};
chain.node.modules.bitcoind = {};
chain.node.modules.bitcoind.genesisBuffer = new Buffer('0100000043497fd7f826957108f4a30fd9cec3aeba79972084e90ead01ea330900000000bac8b0fa927c0ac8234287e33c5f74d38d354820e24756ad709d7038fc5f31f020e7494dffff001d03e4b6720101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0420e7494d017f062f503253482fffffffff0100f2052a010000002321021aeaf2f8638a129a3156fbe7e5ef635226b0bafd495ff03afe2c843d7e3a4b51ac00000000', 'hex');
chain.initialize = function() {
chain.emit('initialized');
};
@ -196,7 +197,8 @@ describe('Bitcoin Chain', function() {
var chain = new Chain();
chain.node = {};
chain.node.db = {};
chain.node.bitcoind = {
chain.node.modules = {};
chain.node.modules.bitcoind = {
getBlockIndex: sinon.stub().returns({
chainWork: work
})
@ -211,7 +213,7 @@ describe('Bitcoin Chain', function() {
});
it('should give an error if the weight is undefined', function(done) {
chain.node.bitcoind.getBlockIndex = sinon.stub().returns(undefined);
chain.node.modules.bitcoind.getBlockIndex = sinon.stub().returns(undefined);
chain.getWeight('hash2', function(err, weight) {
should.exist(err);
done();

View File

@ -10,8 +10,6 @@ var Block = bitcore.Block;
var transactionData = require('./data/bitcoin-transactions.json');
var errors = index.errors;
var memdown = require('memdown');
var inherits = require('util').inherits;
var BaseModule = require('../lib/module');
var bitcore = require('bitcore');
var Transaction = bitcore.Transaction;
@ -21,7 +19,8 @@ describe('Bitcoin DB', function() {
it('should emit ready', function(done) {
var db = new DB({store: memdown});
db.node = {};
db.node.bitcoind = {
db.node.modules = {};
db.node.modules.bitcoind = {
on: sinon.spy()
};
db.addModule = sinon.spy();
@ -51,7 +50,8 @@ describe('Bitcoin DB', function() {
it('will return a NotFound error', function(done) {
var db = new DB({store: memdown});
db.node = {};
db.node.bitcoind = {
db.node.modules = {};
db.node.modules.bitcoind = {
getTransaction: sinon.stub().callsArgWith(2, null, null)
};
var txid = '7426c707d0e9705bdd8158e60983e37d0f5d63529086d6672b07d9238d5aa623';
@ -63,7 +63,8 @@ describe('Bitcoin DB', function() {
it('will return an error from bitcoind', function(done) {
var db = new DB({store: memdown});
db.node = {};
db.node.bitcoind = {
db.node.modules = {};
db.node.modules.bitcoind = {
getTransaction: sinon.stub().callsArgWith(2, new Error('test error'))
};
var txid = '7426c707d0e9705bdd8158e60983e37d0f5d63529086d6672b07d9238d5aa623';
@ -75,7 +76,8 @@ describe('Bitcoin DB', function() {
it('will return an error from bitcoind', function(done) {
var db = new DB({store: memdown});
db.node = {};
db.node.bitcoind = {
db.node.modules = {};
db.node.modules.bitcoind = {
getTransaction: sinon.stub().callsArgWith(2, null, new Buffer(transactionData[0].hex, 'hex'))
};
var txid = '7426c707d0e9705bdd8158e60983e37d0f5d63529086d6672b07d9238d5aa623';
@ -94,7 +96,8 @@ describe('Bitcoin DB', function() {
var blockBuffer = new Buffer(blockData, 'hex');
var expectedBlock = Block.fromBuffer(blockBuffer);
db.node = {};
db.node.bitcoind = {
db.node.modules = {};
db.node.modules.bitcoind = {
getBlock: sinon.stub().callsArgWith(1, null, blockBuffer)
};
@ -107,8 +110,9 @@ describe('Bitcoin DB', function() {
});
it('should give an error when bitcoind.js gives an error', function(done) {
db.node = {};
db.node.bitcoind = {};
db.node.bitcoind.getBlock = sinon.stub().callsArgWith(1, new Error('error'));
db.node.modules = {};
db.node.modules.bitcoind = {};
db.node.modules.bitcoind.getBlock = sinon.stub().callsArgWith(1, new Error('error'));
db.getBlock('00000000000000000593b60d8b4f40fd1ec080bdb0817d475dae47b5f5b1f735', function(err, block) {
should.exist(err);
err.message.should.equal('error');
@ -131,7 +135,8 @@ describe('Bitcoin DB', function() {
it('should return prevHash from bitcoind', function(done) {
var db = new DB({store: memdown});
db.node = {};
db.node.bitcoind = {
db.node.modules = {};
db.node.modules.bitcoind = {
getBlockIndex: sinon.stub().returns({
prevHash: 'prevhash'
})
@ -147,7 +152,8 @@ describe('Bitcoin DB', function() {
it('should give an error if bitcoind could not find it', function(done) {
var db = new DB({store: memdown});
db.node = {};
db.node.bitcoind = {
db.node.modules = {};
db.node.modules.bitcoind = {
getBlockIndex: sinon.stub().returns(null)
};
@ -169,7 +175,8 @@ describe('Bitcoin DB', function() {
var db = new DB({store: memdown});
db.node = {};
db.node.bitcoind = {
db.node.modules = {};
db.node.modules.bitcoind = {
getTransactionWithBlockInfo: sinon.stub().callsArgWith(2, null, info)
};
@ -183,7 +190,8 @@ describe('Bitcoin DB', function() {
it('should give an error if one occurred', function(done) {
var db = new DB({store: memdown});
db.node = {};
db.node.bitcoind = {
db.node.modules = {};
db.node.modules.bitcoind = {
getTransactionWithBlockInfo: sinon.stub().callsArgWith(2, new Error('error'))
};
@ -198,7 +206,8 @@ describe('Bitcoin DB', function() {
it('should give the txid on success', function(done) {
var db = new DB({store: memdown});
db.node = {};
db.node.bitcoind = {
db.node.modules = {};
db.node.modules.bitcoind = {
sendTransaction: sinon.stub().returns('txid')
};
@ -212,7 +221,8 @@ describe('Bitcoin DB', function() {
it('should give an error if bitcoind threw an error', function(done) {
var db = new DB({store: memdown});
db.node = {};
db.node.bitcoind = {
db.node.modules = {};
db.node.modules.bitcoind = {
sendTransaction: sinon.stub().throws(new Error('error'))
};
@ -228,14 +238,15 @@ describe('Bitcoin DB', function() {
it('should pass along the fee from bitcoind', function(done) {
var db = new DB({store: memdown});
db.node = {};
db.node.bitcoind = {
db.node.modules = {};
db.node.modules.bitcoind = {
estimateFee: sinon.stub().returns(1000)
};
db.estimateFee(5, function(err, fee) {
should.not.exist(err);
fee.should.equal(1000);
db.node.bitcoind.estimateFee.args[0][0].should.equal(5);
db.node.modules.bitcoind.estimateFee.args[0][0].should.equal(5);
done();
});
});

View File

@ -11,15 +11,14 @@ var errors = bitcorenode.errors;
var levelup = require('levelup');
var mockdb = {
bitcoind: {
on: sinon.stub()
}
};
var mocknode = {
db: mockdb,
bitcoind: {
on: sinon.stub()
modules: {
bitcoind: {
on: sinon.stub()
}
}
};
@ -103,12 +102,6 @@ describe('AddressModule', function() {
describe('#blockHandler', function() {
var am;
var db = {
bitcoind: {
on: sinon.stub()
}
};
var testBlock = bitcore.Block.fromString(blockData);
var data = [
@ -212,12 +205,6 @@ describe('AddressModule', function() {
});
});
it('should continue if output script is null', function(done) {
var db = {
bitcoind: {
on: sinon.stub()
}
};
var am = new AddressModule({node: mocknode, network: 'livenet'});
var block = {
@ -247,15 +234,13 @@ describe('AddressModule', function() {
});
it('will call event handlers', function() {
var testBlock = bitcore.Block.fromString(blockData);
var db = {
bitcoind: {
on: sinon.stub()
}
};
var db = {};
var testnode = {
db: db,
bitcoind: {
on: sinon.stub()
modules: {
bitcoind: {
on: sinon.stub()
}
}
};
var am = new AddressModule({node: testnode, network: 'livenet'});
@ -444,8 +429,10 @@ describe('AddressModule', function() {
}
},
db: db,
bitcoind: {
on: sinon.stub()
modules: {
bitcoind: {
on: sinon.stub()
}
}
};
@ -467,7 +454,7 @@ describe('AddressModule', function() {
blockHeight: 352532
}
];
am.node.bitcoind = {
am.node.modules.bitcoind = {
getMempoolOutputs: sinon.stub().returns(mempoolOutputs)
};
@ -535,15 +522,13 @@ describe('AddressModule', function() {
'addr3': ['utxo3']
};
var db = {
bitcoind: {
on: sinon.spy()
}
};
var db = {};
var testnode = {
db: db,
bitcoind: {
on: sinon.stub()
modules: {
bitcoind: {
on: sinon.stub()
}
}
};
var am = new AddressModule({node: testnode});
@ -570,14 +555,18 @@ describe('AddressModule', function() {
};
var db = {
bitcoind: {
on: sinon.spy()
modules: {
bitcoind: {
on: sinon.spy()
}
}
};
var testnode = {
db: db,
bitcoind: {
on: sinon.stub()
modules: {
bitcoind: {
on: sinon.stub()
}
}
};
var am = new AddressModule({node: testnode});
@ -604,15 +593,13 @@ describe('AddressModule', function() {
'addr3': ['utxo3']
};
var db = {
bitcoind: {
on: sinon.spy()
}
};
var db = {};
var testnode = {
db: db,
bitcoind: {
on: sinon.stub()
modules: {
bitcoind: {
on: sinon.stub()
}
}
};
var am = new AddressModule({node: testnode});
@ -721,20 +708,18 @@ describe('AddressModule', function() {
describe('#isSpent', function() {
var am;
var db = {
bitcoind: {
on: sinon.stub()
}
};
var db = {};
var testnode = {
db: db,
bitcoind: {
on: sinon.stub()
modules: {
bitcoind: {
on: sinon.stub()
}
}
};
before(function() {
am = new AddressModule({node: testnode});
am.node.bitcoind = {
am.node.modules.bitcoind = {
isSpent: sinon.stub().returns(true),
on: sinon.stub()
};
@ -757,8 +742,10 @@ describe('AddressModule', function() {
};
var testnode = {
db: db,
bitcoind: {
on: sinon.stub()
modules: {
bitcoind: {
on: sinon.stub()
}
}
};
var am = new AddressModule({node: testnode});
@ -875,8 +862,10 @@ describe('AddressModule', function() {
}
},
db: db,
bitcoind: {
on: sinon.stub()
modules: {
bitcoind: {
on: sinon.stub()
}
}
};
var am = new AddressModule({node: testnode});

View File

@ -0,0 +1,50 @@
'use strict';
var should = require('chai').should();
var proxyquire = require('proxyquire');
var fs = require('fs');
var sinon = require('sinon');
var BitcoinModule = proxyquire('../../lib/modules/bitcoind', {
fs: {
readFileSync: sinon.stub().returns(fs.readFileSync(__dirname + '/../data/bitcoin.conf'))
}
});
var BadBitcoin = proxyquire('../../lib/modules/bitcoind', {
fs: {
readFileSync: sinon.stub().returns(fs.readFileSync(__dirname + '/../data/badbitcoin.conf'))
}
});
describe('Bitcoin Module', function() {
var baseConfig = {
node: {
datadir: 'testdir',
network: {
name: 'regtest'
}
}
};
describe('#_loadConfiguration', function() {
it('will parse a bitcoin.conf file', function() {
var bitcoind = new BitcoinModule(baseConfig);
bitcoind._loadConfiguration({datadir: process.env.HOME + '/.bitcoin'});
should.exist(bitcoind.configuration);
bitcoind.configuration.should.deep.equal({
server: 1,
whitelist: '127.0.0.1',
txindex: 1,
port: 20000,
rpcallowip: '127.0.0.1',
rpcuser: 'bitcoin',
rpcpassword: 'local321'
});
});
it('should throw an exception if txindex isn\'t enabled in the configuration', function() {
var bitcoind = new BadBitcoin(baseConfig);
(function() {
bitcoind._loadConfiguration({datadir: './test'});
}).should.throw('Txindex option');
});
});
});

View File

@ -11,15 +11,17 @@ var blockData = require('./data/livenet-345003.json');
var proxyquire = require('proxyquire');
var index = require('..');
var fs = require('fs');
var bitcoinConfBuffer = fs.readFileSync(__dirname + '/data/bitcoin.conf');
var chainHashes = require('./data/hashes.json');
var util = require('util');
var BaseModule = require('../lib/module');
describe('Bitcore Node', function() {
var baseConfig = {
datadir: 'testdir'
};
var Node;
var BadNode;
function hexlebuf(hexString){
return BufferUtil.reverse(new Buffer(hexString, 'hex'));
@ -30,23 +32,9 @@ describe('Bitcore Node', function() {
}
before(function() {
BadNode = proxyquire('../lib/node', {
fs: {
readFileSync: sinon.stub().returns(fs.readFileSync(__dirname + '/data/badbitcoin.conf'))
}
});
BadNode.prototype._loadConfiguration = sinon.spy();
BadNode.prototype._initialize = sinon.spy();
Node = proxyquire('../lib/node', {
fs: {
readFileSync: sinon.stub().returns(bitcoinConfBuffer)
}
});
Node = proxyquire('../lib/node', {});
Node.prototype._loadConfiguration = sinon.spy();
Node.prototype._initialize = sinon.spy();
});
describe('@constructor', function() {
@ -60,6 +48,7 @@ describe('Bitcore Node', function() {
];
};
var config = {
datadir: 'testdir',
modules: [
{
name: 'test1',
@ -81,7 +70,7 @@ describe('Bitcore Node', function() {
describe('#openBus', function() {
it('will create a new bus', function() {
var node = new Node({});
var node = new Node(baseConfig);
var bus = node.openBus();
bus.node.should.equal(node);
});
@ -89,7 +78,7 @@ describe('Bitcore Node', function() {
describe('#addModule', function() {
it('will instantiate an instance and load api methods', function() {
var node = new Node({});
var node = new Node(baseConfig);
function TestModule() {}
util.inherits(TestModule, BaseModule);
TestModule.prototype.getData = function() {};
@ -110,7 +99,7 @@ describe('Bitcore Node', function() {
describe('#getAllAPIMethods', function() {
it('should return db methods and modules methods', function() {
var node = new Node({});
var node = new Node(baseConfig);
node.modules = {
module1: {
getAPIMethods: sinon.stub().returns(['mda1', 'mda2'])
@ -130,7 +119,7 @@ describe('Bitcore Node', function() {
});
describe('#getAllPublishEvents', function() {
it('should return modules publish events', function() {
var node = new Node({});
var node = new Node(baseConfig);
node.modules = {
module1: {
getPublishEvents: sinon.stub().returns(['mda1', 'mda2'])
@ -150,62 +139,20 @@ describe('Bitcore Node', function() {
});
describe('#_loadConfiguration', function() {
it('should call the necessary methods', function() {
var TestNode = proxyquire('../lib/node', {
fs: {
readFileSync: sinon.stub().returns(bitcoinConfBuffer)
}
});
var TestNode = proxyquire('../lib/node', {});
TestNode.prototype._initialize = sinon.spy();
TestNode.prototype._loadBitcoinConf = sinon.spy();
TestNode.prototype._loadBitcoind = sinon.spy();
TestNode.prototype._loadDB = sinon.spy();
TestNode.prototype._loadAPI = sinon.spy();
TestNode.prototype._loadConsensus = sinon.spy();
var node = new TestNode({});
node._loadBitcoind.callCount.should.equal(1);
node._loadBitcoinConf.callCount.should.equal(1);
var node = new TestNode(baseConfig);
node._loadDB.callCount.should.equal(1);
node._loadAPI.callCount.should.equal(1);
node._loadConsensus.callCount.should.equal(1);
});
});
describe('#_loadBitcoinConf', function() {
it('will parse a bitcoin.conf file', function() {
var node = new Node({});
node._loadBitcoinConf({datadir: process.env.HOME + '/.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({});
node._loadBitcoind({datadir: './test'});
should.exist(node.bitcoind);
});
it('should initialize with testnet', function() {
var node = new Node({});
node._loadBitcoind({datadir: './test', testnet: true});
should.exist(node.bitcoind);
});
it('should throw an exception if txindex isn\'t enabled in the configuration', function() {
var node = new BadNode({});
(function() {
node._loadBitcoinConf({datadir: './test'});
}).should.throw('Txindex option');
});
});
describe('#_syncBitcoindAncestor', function() {
it('will find an ancestor 6 deep', function() {
var node = new Node({});
var node = new Node(baseConfig);
node.chain = {
getHashes: function(tipHash, callback) {
callback(null, chainHashes);
@ -248,7 +195,8 @@ describe('Bitcore Node', function() {
}
},
};
node.bitcoind = {
node.modules = {};
node.modules.bitcoind = {
getBlockIndex: function(hash) {
var block = forkedBlocks[hash];
return {
@ -267,7 +215,7 @@ describe('Bitcore Node', function() {
});
describe('#_syncBitcoindRewind', function() {
it('will undo blocks 6 deep', function() {
var node = new Node({});
var node = new Node(baseConfig);
var ancestorHash = chainHashes[chainHashes.length - 6];
node.chain = {
tip: {
@ -317,10 +265,11 @@ describe('Bitcore Node', function() {
});
describe('#_syncBitcoind', function() {
it('will get and add block up to the tip height', function(done) {
var node = new Node({});
var node = new Node(baseConfig);
var blockBuffer = new Buffer(blockData, 'hex');
var block = Block.fromBuffer(blockBuffer);
node.bitcoind = {
node.modules = {};
node.modules.bitcoind = {
getBlock: sinon.stub().callsArgWith(1, null, blockBuffer),
isSynced: sinon.stub().returns(true),
height: 1
@ -349,8 +298,9 @@ describe('Bitcore Node', function() {
node._syncBitcoind();
});
it('will exit and emit error with error from bitcoind.getBlock', function(done) {
var node = new Node({});
node.bitcoind = {
var node = new Node(baseConfig);
node.modules = {};
node.modules.bitcoind = {
getBlock: sinon.stub().callsArgWith(1, new Error('test error')),
height: 1
};
@ -366,10 +316,11 @@ describe('Bitcore Node', function() {
node._syncBitcoind();
});
it('will stop syncing when the node is stopping', function(done) {
var node = new Node({});
var node = new Node(baseConfig);
var blockBuffer = new Buffer(blockData, 'hex');
var block = Block.fromBuffer(blockBuffer);
node.bitcoind = {
node.modules = {};
node.modules.bitcoind = {
getBlock: sinon.stub().callsArgWith(1, null, blockBuffer),
isSynced: sinon.stub().returns(true),
height: 1
@ -411,6 +362,7 @@ describe('Bitcore Node', function() {
describe('#_loadNetwork', function() {
it('should use the testnet network if testnet is specified', function() {
var config = {
datadir: 'testdir',
network: 'testnet'
};
var node = new Node(config);
@ -419,6 +371,7 @@ describe('Bitcore Node', function() {
});
it('should use the regtest network if regtest is specified', function() {
var config = {
datadir: 'testdir',
network: 'regtest'
};
var node = new Node(config);
@ -426,7 +379,9 @@ describe('Bitcore Node', function() {
node.network.name.should.equal('regtest');
});
it('should use the livenet network if nothing is specified', function() {
var config = {};
var config = {
datadir: 'testdir'
};
var node = new Node(config);
node._loadNetwork(config);
node.network.name.should.equal('livenet');
@ -526,7 +481,7 @@ describe('Bitcore Node', function() {
var node;
before(function() {
node = new Node({});
node = new Node(baseConfig);
});
it('will set properties', function() {
@ -541,11 +496,7 @@ describe('Bitcore Node', function() {
var node;
before(function() {
var TestNode = proxyquire('../lib/node', {
fs: {
readFileSync: sinon.stub().returns(bitcoinConfBuffer)
}
});
var TestNode = proxyquire('../lib/node', {});
TestNode.prototype._loadConfiguration = sinon.spy();
TestNode.prototype._initializeBitcoind = sinon.spy();
TestNode.prototype._initializeDatabase = sinon.spy();
@ -555,7 +506,7 @@ describe('Bitcore Node', function() {
var _initialize = TestNode.prototype._initialize;
TestNode.prototype._initialize = sinon.spy();
node = new TestNode({});
node = new TestNode(baseConfig);
node.chain = {
on: sinon.spy()
};
@ -581,7 +532,6 @@ describe('Bitcore Node', function() {
node._initialize();
// event handlers
node._initializeBitcoind.callCount.should.equal(1);
node._initializeDatabase.callCount.should.equal(1);
node._initializeChain.callCount.should.equal(1);
@ -599,51 +549,9 @@ describe('Bitcore Node', function() {
});
describe('#_initalizeBitcoind', function() {
it('will call emit an error from libbitcoind', function(done) {
var node = new Node({});
node.bitcoind = new EventEmitter();
node.on('error', function(err) {
should.exist(err);
err.message.should.equal('test error');
done();
});
node._initializeBitcoind();
node.bitcoind.emit('error', new Error('test error'));
});
it('will call sync when there is a new tip', function(done) {
var node = new Node({});
node.bitcoind = new EventEmitter();
node.bitcoind.syncPercentage = sinon.spy();
node._syncBitcoind = function() {
node.bitcoind.syncPercentage.callCount.should.equal(1);
done();
};
node._initializeBitcoind();
node.bitcoind.emit('tip', 10);
});
it('will not call sync when there is a new tip and shutting down', function(done) {
var node = new Node({});
node.bitcoind = new EventEmitter();
node._syncBitcoind = sinon.spy();
node.bitcoind.syncPercentage = sinon.spy();
node.stopping = true;
node.bitcoind.on('tip', function() {
setImmediate(function() {
node.bitcoind.syncPercentage.callCount.should.equal(0);
node._syncBitcoind.callCount.should.equal(0);
done();
});
});
node._initializeBitcoind();
node.bitcoind.emit('tip', 10);
});
});
describe('#_initializeDatabase', function() {
it('will log on ready event', function(done) {
var node = new Node({});
var node = new Node(baseConfig);
node.db = new EventEmitter();
sinon.stub(index.log, 'info');
node.db.on('ready', function() {
@ -657,7 +565,7 @@ describe('Bitcore Node', function() {
node.db.emit('ready');
});
it('will call emit an error from db', function(done) {
var node = new Node({});
var node = new Node(baseConfig);
node.db = new EventEmitter();
node.on('error', function(err) {
should.exist(err);
@ -670,21 +578,42 @@ describe('Bitcore Node', function() {
});
describe('#_initializeChain', function() {
it('will call _syncBitcoind on ready', function(done) {
var node = new Node({});
node._syncBitcoind = sinon.spy();
it('will call sync when there is a new tip', function(done) {
var node = new Node(baseConfig);
node.chain = new EventEmitter();
node.chain.on('ready', function(err) {
node.modules = {};
node.modules.bitcoind = new EventEmitter();
node.modules.bitcoind.syncPercentage = sinon.spy();
node._syncBitcoind = function() {
node.modules.bitcoind.syncPercentage.callCount.should.equal(1);
done();
};
node._initializeChain();
node.chain.emit('ready');
node.modules.bitcoind.emit('tip', 10);
});
it('will not call sync when there is a new tip and shutting down', function(done) {
var node = new Node(baseConfig);
node.chain = new EventEmitter();
node.modules = {};
node.modules.bitcoind = new EventEmitter();
node._syncBitcoind = sinon.spy();
node.modules.bitcoind.syncPercentage = sinon.spy();
node.stopping = true;
node.modules.bitcoind.on('tip', function() {
setImmediate(function() {
node._syncBitcoind.callCount.should.equal(1);
node.modules.bitcoind.syncPercentage.callCount.should.equal(0);
node._syncBitcoind.callCount.should.equal(0);
done();
});
});
node._initializeChain();
node.chain.emit('ready');
node.modules.bitcoind.emit('tip', 10);
});
it('will emit an error from the chain', function(done) {
var node = new Node({});
var node = new Node(baseConfig);
node.chain = new EventEmitter();
node.on('error', function(err) {
should.exist(err);
@ -698,7 +627,7 @@ describe('Bitcore Node', function() {
describe('#getServiceOrder', function() {
it('should return the services in the correct order', function() {
var node = new Node({});
var node = new Node(baseConfig);
node.getServices = function() {
return [
{
@ -729,7 +658,7 @@ describe('Bitcore Node', function() {
describe('#start', function() {
it('will call start for each module', function(done) {
var node = new Node({});
var node = new Node(baseConfig);
function TestModule() {}
util.inherits(TestModule, BaseModule);
TestModule.prototype.start = sinon.stub().callsArg(0);
@ -760,7 +689,7 @@ describe('Bitcore Node', function() {
describe('#stop', function() {
it('will call stop for each module', function(done) {
var node = new Node({});
var node = new Node(baseConfig);
function TestModule() {}
util.inherits(TestModule, BaseModule);
TestModule.prototype.stop = sinon.stub().callsArg(0);