Convert daemon into bitcoin module.
This commit is contained in:
parent
95a65da87d
commit
96f6604222
|
@ -2,17 +2,21 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var chainlib = require('chainlib');
|
var index = require('..');
|
||||||
var log = chainlib.log;
|
var log = index.log;
|
||||||
|
|
||||||
process.title = 'libbitcoind';
|
process.title = 'libbitcoind';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* daemon
|
* daemon
|
||||||
*/
|
*/
|
||||||
var daemon = require('../').daemon({
|
var daemon = require('../').modules.BitcoinModule({
|
||||||
datadir: process.env.BITCORENODE_DIR || '~/.bitcoin',
|
node: {
|
||||||
network: process.env.BITCORENODE_NETWORK || 'livenet'
|
datadir: process.env.BITCORENODE_DIR || process.env.HOME + '/.bitcoin',
|
||||||
|
network: {
|
||||||
|
name: process.env.BITCORENODE_NETWORK || 'livenet'
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
daemon.start(function() {
|
daemon.start(function() {
|
||||||
|
|
2
index.js
2
index.js
|
@ -1,7 +1,6 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
module.exports = require('./lib');
|
module.exports = require('./lib');
|
||||||
module.exports.daemon = require('./lib/daemon');
|
|
||||||
module.exports.Node = require('./lib/node');
|
module.exports.Node = require('./lib/node');
|
||||||
module.exports.Chain = require('./lib/chain');
|
module.exports.Chain = require('./lib/chain');
|
||||||
module.exports.DB = require('./lib/db');
|
module.exports.DB = require('./lib/db');
|
||||||
|
@ -11,6 +10,7 @@ module.exports.errors = require('./lib/errors');
|
||||||
|
|
||||||
module.exports.modules = {};
|
module.exports.modules = {};
|
||||||
module.exports.modules.AddressModule = require('./lib/modules/address');
|
module.exports.modules.AddressModule = require('./lib/modules/address');
|
||||||
|
module.exports.modules.BitcoinModule = require('./lib/modules/bitcoind');
|
||||||
|
|
||||||
module.exports.scaffold = {};
|
module.exports.scaffold = {};
|
||||||
module.exports.scaffold.create = require('./lib/scaffold/create');
|
module.exports.scaffold.create = require('./lib/scaffold/create');
|
||||||
|
|
|
@ -23,7 +23,10 @@ var node;
|
||||||
var should = chai.should();
|
var should = chai.should();
|
||||||
|
|
||||||
var BitcoinRPC = require('bitcoind-rpc');
|
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 testWIF = 'cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG';
|
||||||
var testKey;
|
var testKey;
|
||||||
var client;
|
var client;
|
||||||
|
@ -60,7 +63,19 @@ describe('Node Functionality', function() {
|
||||||
|
|
||||||
var configuration = {
|
var configuration = {
|
||||||
datadir: datadir,
|
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);
|
node = new BitcoreNode(configuration);
|
||||||
|
@ -102,7 +117,10 @@ describe('Node Functionality', function() {
|
||||||
|
|
||||||
after(function(done) {
|
after(function(done) {
|
||||||
this.timeout(20000);
|
this.timeout(20000);
|
||||||
node.bitcoind.stop(function(err, result) {
|
node.stop(function(err, result) {
|
||||||
|
if(err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -61,9 +61,13 @@ describe('Daemon Binding Functionality', function() {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
bitcoind = require('../').daemon({
|
bitcoind = require('../').modules.BitcoinModule({
|
||||||
datadir: datadir,
|
node: {
|
||||||
network: 'regtest'
|
datadir: datadir,
|
||||||
|
network: {
|
||||||
|
name: 'regtest'
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
bitcoind.on('error', function(err) {
|
bitcoind.on('error', function(err) {
|
||||||
|
|
|
@ -90,7 +90,7 @@ Chain.prototype._onInitialized = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
Chain.prototype.start = function(callback) {
|
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.once('initialized', callback);
|
||||||
this.initialize();
|
this.initialize();
|
||||||
};
|
};
|
||||||
|
@ -152,7 +152,7 @@ Chain.prototype.startBuilder = function() {
|
||||||
|
|
||||||
Chain.prototype.getWeight = function getWeight(blockHash, callback) {
|
Chain.prototype.getWeight = function getWeight(blockHash, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var blockIndex = self.node.bitcoind.getBlockIndex(blockHash);
|
var blockIndex = self.node.modules.bitcoind.getBlockIndex(blockHash);
|
||||||
|
|
||||||
setImmediate(function() {
|
setImmediate(function() {
|
||||||
if (blockIndex) {
|
if (blockIndex) {
|
||||||
|
|
165
lib/daemon.js
165
lib/daemon.js
|
@ -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;
|
|
19
lib/db.js
19
lib/db.js
|
@ -71,7 +71,7 @@ DB.prototype.initialize = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
DB.prototype.start = function(callback) {
|
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');
|
this.emit('ready');
|
||||||
setImmediate(callback);
|
setImmediate(callback);
|
||||||
};
|
};
|
||||||
|
@ -93,7 +93,7 @@ DB.prototype.getBlock = function(hash, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
// get block from bitcoind
|
// get block from bitcoind
|
||||||
this.node.bitcoind.getBlock(hash, function(err, blockData) {
|
this.node.modules.bitcoind.getBlock(hash, function(err, blockData) {
|
||||||
if(err) {
|
if(err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ DB.prototype.getBlock = function(hash, callback) {
|
||||||
};
|
};
|
||||||
|
|
||||||
DB.prototype.getPrevHash = function(blockHash, callback) {
|
DB.prototype.getPrevHash = function(blockHash, callback) {
|
||||||
var blockIndex = this.node.bitcoind.getBlockIndex(blockHash);
|
var blockIndex = this.node.modules.bitcoind.getBlockIndex(blockHash);
|
||||||
setImmediate(function() {
|
setImmediate(function() {
|
||||||
if (blockIndex) {
|
if (blockIndex) {
|
||||||
callback(null, blockIndex.prevHash);
|
callback(null, blockIndex.prevHash);
|
||||||
|
@ -118,7 +118,7 @@ DB.prototype.putBlock = function(block, callback) {
|
||||||
};
|
};
|
||||||
|
|
||||||
DB.prototype.getTransaction = function(txid, queryMempool, 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) {
|
if(err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
@ -131,7 +131,7 @@ DB.prototype.getTransaction = function(txid, queryMempool, callback) {
|
||||||
};
|
};
|
||||||
|
|
||||||
DB.prototype.getTransactionWithBlockInfo = 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) {
|
if(err) {
|
||||||
return callback(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');
|
$.checkArgument(typeof tx === 'string', 'Argument must be a hex string or Transaction');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var txid = this.node.bitcoind.sendTransaction(tx);
|
var txid = this.node.modules.bitcoind.sendTransaction(tx);
|
||||||
return callback(null, txid);
|
return callback(null, txid);
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
|
@ -162,7 +162,7 @@ DB.prototype.estimateFee = function(blocks, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
setImmediate(function() {
|
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) {
|
if(err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
if (ops) {
|
||||||
operations = operations.concat(ops);
|
operations = operations.concat(ops);
|
||||||
|
}
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
var util = require('util');
|
||||||
|
var EventEmitter = require('events').EventEmitter;
|
||||||
|
|
||||||
var Module = function(options) {
|
var Module = function(options) {
|
||||||
|
EventEmitter.call(this);
|
||||||
|
|
||||||
this.node = options.node;
|
this.node = options.node;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
util.inherits(Module, EventEmitter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes the dependencies that should be loaded before this module.
|
* Describes the dependencies that should be loaded before this module.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -21,7 +21,7 @@ var AddressModule = function(options) {
|
||||||
this.subscriptions['address/transaction'] = {};
|
this.subscriptions['address/transaction'] = {};
|
||||||
this.subscriptions['address/balance'] = {};
|
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) {
|
if(queryMempool) {
|
||||||
outputs = outputs.concat(self.node.bitcoind.getMempoolOutputs(addressStr));
|
outputs = outputs.concat(self.node.modules.bitcoind.getMempoolOutputs(addressStr));
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(null, outputs);
|
callback(null, outputs);
|
||||||
|
@ -435,7 +435,7 @@ AddressModule.prototype.isSpent = function(output, queryMempool, callback) {
|
||||||
var txid = output.prevTxId ? output.prevTxId.toString('hex') : output.txid;
|
var txid = output.prevTxId ? output.prevTxId.toString('hex') : output.txid;
|
||||||
|
|
||||||
setImmediate(function() {
|
setImmediate(function() {
|
||||||
callback(self.node.bitcoind.isSpent(txid, output.outputIndex));
|
callback(self.node.modules.bitcoind.isSpent(txid, output.outputIndex));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
104
lib/node.js
104
lib/node.js
|
@ -15,7 +15,6 @@ var Chain = require('./chain');
|
||||||
var DB = require('./db');
|
var DB = require('./db');
|
||||||
var index = require('./');
|
var index = require('./');
|
||||||
var log = index.log;
|
var log = index.log;
|
||||||
var daemon = require('./daemon');
|
|
||||||
var Bus = require('./bus');
|
var Bus = require('./bus');
|
||||||
var BaseModule = require('./module');
|
var BaseModule = require('./module');
|
||||||
|
|
||||||
|
@ -37,6 +36,9 @@ function Node(config) {
|
||||||
this._unloadedModules = config.modules;
|
this._unloadedModules = config.modules;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$.checkState(config.datadir, 'Node config expects "datadir"');
|
||||||
|
this.datadir = config.datadir;
|
||||||
|
|
||||||
this._loadConfiguration(config);
|
this._loadConfiguration(config);
|
||||||
this._initialize();
|
this._initialize();
|
||||||
}
|
}
|
||||||
|
@ -97,61 +99,12 @@ Node.prototype.getAllPublishEvents = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
Node.prototype._loadConfiguration = function(config) {
|
Node.prototype._loadConfiguration = function(config) {
|
||||||
this._loadBitcoinConf(config);
|
|
||||||
this._loadBitcoind(config);
|
|
||||||
this._loadNetwork(config);
|
this._loadNetwork(config);
|
||||||
this._loadDB(config);
|
this._loadDB(config);
|
||||||
this._loadAPI();
|
this._loadAPI();
|
||||||
this._loadConsensus(config);
|
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,
|
* 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.
|
* 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.
|
// and thus don't need to find the entire chain of hashes.
|
||||||
|
|
||||||
while(ancestorHash && !currentHashesMap[ancestorHash]) {
|
while(ancestorHash && !currentHashesMap[ancestorHash]) {
|
||||||
var blockIndex = self.bitcoind.getBlockIndex(ancestorHash);
|
var blockIndex = self.modules.bitcoind.getBlockIndex(ancestorHash);
|
||||||
ancestorHash = blockIndex ? blockIndex.prevHash : null;
|
ancestorHash = blockIndex ? blockIndex.prevHash : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,9 +229,9 @@ Node.prototype._syncBitcoind = function() {
|
||||||
|
|
||||||
async.whilst(function() {
|
async.whilst(function() {
|
||||||
height = self.chain.tip.__height;
|
height = self.chain.tip.__height;
|
||||||
return height < self.bitcoind.height && !self.stopping;
|
return height < self.modules.bitcoind.height && !self.stopping;
|
||||||
}, function(done) {
|
}, function(done) {
|
||||||
self.bitcoind.getBlock(height + 1, function(err, blockBuffer) {
|
self.modules.bitcoind.getBlock(height + 1, function(err, blockBuffer) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return done(err);
|
return done(err);
|
||||||
}
|
}
|
||||||
|
@ -340,7 +293,7 @@ Node.prototype._syncBitcoind = function() {
|
||||||
self.chain.lastSavedMetadataThreshold = 0;
|
self.chain.lastSavedMetadataThreshold = 0;
|
||||||
|
|
||||||
// If bitcoind is completely synced
|
// If bitcoind is completely synced
|
||||||
if (self.bitcoind.isSynced()) {
|
if (self.modules.bitcoind.isSynced()) {
|
||||||
self.emit('synced');
|
self.emit('synced');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,7 +386,6 @@ Node.prototype._loadAPI = function() {
|
||||||
Node.prototype._initialize = function() {
|
Node.prototype._initialize = function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this._initializeBitcoind();
|
|
||||||
this._initializeDatabase();
|
this._initializeDatabase();
|
||||||
this._initializeChain();
|
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() {
|
Node.prototype._initializeDatabase = function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.db.on('ready', function() {
|
this.db.on('ready', function() {
|
||||||
|
@ -482,10 +410,20 @@ Node.prototype._initializeDatabase = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
Node.prototype._initializeChain = function() {
|
Node.prototype._initializeChain = function() {
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
this.chain.on('ready', function() {
|
this.chain.on('ready', function() {
|
||||||
log.info('Bitcoin Chain Ready');
|
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) {
|
this.chain.on('error', function(err) {
|
||||||
Error.captureStackTrace(err);
|
Error.captureStackTrace(err);
|
||||||
|
@ -495,10 +433,6 @@ Node.prototype._initializeChain = function() {
|
||||||
|
|
||||||
Node.prototype.getServices = function() {
|
Node.prototype.getServices = function() {
|
||||||
var services = [
|
var services = [
|
||||||
{
|
|
||||||
name: 'bitcoind',
|
|
||||||
dependencies: []
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'db',
|
name: 'db',
|
||||||
dependencies: ['bitcoind'],
|
dependencies: ['bitcoind'],
|
||||||
|
@ -535,6 +469,7 @@ Node.prototype.getServiceOrder = function() {
|
||||||
|
|
||||||
var name = names[i];
|
var name = names[i];
|
||||||
var service = servicesByName[name];
|
var service = servicesByName[name];
|
||||||
|
$.checkState(service, 'Required dependency "' + name + '" not available.');
|
||||||
|
|
||||||
// first add the dependencies
|
// first add the dependencies
|
||||||
addToStack(service.dependencies);
|
addToStack(service.dependencies);
|
||||||
|
@ -586,7 +521,6 @@ Node.prototype.stop = function(callback) {
|
||||||
services,
|
services,
|
||||||
function(service, next) {
|
function(service, next) {
|
||||||
log.info('Stopping ' + service.name);
|
log.info('Stopping ' + service.name);
|
||||||
|
|
||||||
if (service.module) {
|
if (service.module) {
|
||||||
self.modules[service.name].stop(next);
|
self.modules[service.name].stop(next);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -13,7 +13,7 @@ function getDefaultConfig() {
|
||||||
datadir: process.env.BITCORENODE_DIR || path.resolve(process.env.HOME, '.bitcoin'),
|
datadir: process.env.BITCORENODE_DIR || path.resolve(process.env.HOME, '.bitcoin'),
|
||||||
network: process.env.BITCORENODE_NETWORK || 'livenet',
|
network: process.env.BITCORENODE_NETWORK || 'livenet',
|
||||||
port: process.env.BITCORENODE_PORT || 3001,
|
port: process.env.BITCORENODE_PORT || 3001,
|
||||||
modules: ['address']
|
modules: ['bitcoind', 'address']
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,8 +30,9 @@ describe('Bitcoin Chain', function() {
|
||||||
it('should call the callback when base chain is initialized', function(done) {
|
it('should call the callback when base chain is initialized', function(done) {
|
||||||
var chain = new Chain();
|
var chain = new Chain();
|
||||||
chain.node = {};
|
chain.node = {};
|
||||||
chain.node.bitcoind = {};
|
chain.node.modules = {};
|
||||||
chain.node.bitcoind.genesisBuffer = new Buffer('0100000043497fd7f826957108f4a30fd9cec3aeba79972084e90ead01ea330900000000bac8b0fa927c0ac8234287e33c5f74d38d354820e24756ad709d7038fc5f31f020e7494dffff001d03e4b6720101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0420e7494d017f062f503253482fffffffff0100f2052a010000002321021aeaf2f8638a129a3156fbe7e5ef635226b0bafd495ff03afe2c843d7e3a4b51ac00000000', 'hex');
|
chain.node.modules.bitcoind = {};
|
||||||
|
chain.node.modules.bitcoind.genesisBuffer = new Buffer('0100000043497fd7f826957108f4a30fd9cec3aeba79972084e90ead01ea330900000000bac8b0fa927c0ac8234287e33c5f74d38d354820e24756ad709d7038fc5f31f020e7494dffff001d03e4b6720101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0420e7494d017f062f503253482fffffffff0100f2052a010000002321021aeaf2f8638a129a3156fbe7e5ef635226b0bafd495ff03afe2c843d7e3a4b51ac00000000', 'hex');
|
||||||
chain.initialize = function() {
|
chain.initialize = function() {
|
||||||
chain.emit('initialized');
|
chain.emit('initialized');
|
||||||
};
|
};
|
||||||
|
@ -196,7 +197,8 @@ describe('Bitcoin Chain', function() {
|
||||||
var chain = new Chain();
|
var chain = new Chain();
|
||||||
chain.node = {};
|
chain.node = {};
|
||||||
chain.node.db = {};
|
chain.node.db = {};
|
||||||
chain.node.bitcoind = {
|
chain.node.modules = {};
|
||||||
|
chain.node.modules.bitcoind = {
|
||||||
getBlockIndex: sinon.stub().returns({
|
getBlockIndex: sinon.stub().returns({
|
||||||
chainWork: work
|
chainWork: work
|
||||||
})
|
})
|
||||||
|
@ -211,7 +213,7 @@ describe('Bitcoin Chain', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should give an error if the weight is undefined', function(done) {
|
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) {
|
chain.getWeight('hash2', function(err, weight) {
|
||||||
should.exist(err);
|
should.exist(err);
|
||||||
done();
|
done();
|
||||||
|
|
|
@ -10,8 +10,6 @@ var Block = bitcore.Block;
|
||||||
var transactionData = require('./data/bitcoin-transactions.json');
|
var transactionData = require('./data/bitcoin-transactions.json');
|
||||||
var errors = index.errors;
|
var errors = index.errors;
|
||||||
var memdown = require('memdown');
|
var memdown = require('memdown');
|
||||||
var inherits = require('util').inherits;
|
|
||||||
var BaseModule = require('../lib/module');
|
|
||||||
var bitcore = require('bitcore');
|
var bitcore = require('bitcore');
|
||||||
var Transaction = bitcore.Transaction;
|
var Transaction = bitcore.Transaction;
|
||||||
|
|
||||||
|
@ -21,7 +19,8 @@ describe('Bitcoin DB', function() {
|
||||||
it('should emit ready', function(done) {
|
it('should emit ready', function(done) {
|
||||||
var db = new DB({store: memdown});
|
var db = new DB({store: memdown});
|
||||||
db.node = {};
|
db.node = {};
|
||||||
db.node.bitcoind = {
|
db.node.modules = {};
|
||||||
|
db.node.modules.bitcoind = {
|
||||||
on: sinon.spy()
|
on: sinon.spy()
|
||||||
};
|
};
|
||||||
db.addModule = sinon.spy();
|
db.addModule = sinon.spy();
|
||||||
|
@ -51,7 +50,8 @@ describe('Bitcoin DB', function() {
|
||||||
it('will return a NotFound error', function(done) {
|
it('will return a NotFound error', function(done) {
|
||||||
var db = new DB({store: memdown});
|
var db = new DB({store: memdown});
|
||||||
db.node = {};
|
db.node = {};
|
||||||
db.node.bitcoind = {
|
db.node.modules = {};
|
||||||
|
db.node.modules.bitcoind = {
|
||||||
getTransaction: sinon.stub().callsArgWith(2, null, null)
|
getTransaction: sinon.stub().callsArgWith(2, null, null)
|
||||||
};
|
};
|
||||||
var txid = '7426c707d0e9705bdd8158e60983e37d0f5d63529086d6672b07d9238d5aa623';
|
var txid = '7426c707d0e9705bdd8158e60983e37d0f5d63529086d6672b07d9238d5aa623';
|
||||||
|
@ -63,7 +63,8 @@ describe('Bitcoin DB', function() {
|
||||||
it('will return an error from bitcoind', function(done) {
|
it('will return an error from bitcoind', function(done) {
|
||||||
var db = new DB({store: memdown});
|
var db = new DB({store: memdown});
|
||||||
db.node = {};
|
db.node = {};
|
||||||
db.node.bitcoind = {
|
db.node.modules = {};
|
||||||
|
db.node.modules.bitcoind = {
|
||||||
getTransaction: sinon.stub().callsArgWith(2, new Error('test error'))
|
getTransaction: sinon.stub().callsArgWith(2, new Error('test error'))
|
||||||
};
|
};
|
||||||
var txid = '7426c707d0e9705bdd8158e60983e37d0f5d63529086d6672b07d9238d5aa623';
|
var txid = '7426c707d0e9705bdd8158e60983e37d0f5d63529086d6672b07d9238d5aa623';
|
||||||
|
@ -75,7 +76,8 @@ describe('Bitcoin DB', function() {
|
||||||
it('will return an error from bitcoind', function(done) {
|
it('will return an error from bitcoind', function(done) {
|
||||||
var db = new DB({store: memdown});
|
var db = new DB({store: memdown});
|
||||||
db.node = {};
|
db.node = {};
|
||||||
db.node.bitcoind = {
|
db.node.modules = {};
|
||||||
|
db.node.modules.bitcoind = {
|
||||||
getTransaction: sinon.stub().callsArgWith(2, null, new Buffer(transactionData[0].hex, 'hex'))
|
getTransaction: sinon.stub().callsArgWith(2, null, new Buffer(transactionData[0].hex, 'hex'))
|
||||||
};
|
};
|
||||||
var txid = '7426c707d0e9705bdd8158e60983e37d0f5d63529086d6672b07d9238d5aa623';
|
var txid = '7426c707d0e9705bdd8158e60983e37d0f5d63529086d6672b07d9238d5aa623';
|
||||||
|
@ -94,7 +96,8 @@ describe('Bitcoin DB', function() {
|
||||||
var blockBuffer = new Buffer(blockData, 'hex');
|
var blockBuffer = new Buffer(blockData, 'hex');
|
||||||
var expectedBlock = Block.fromBuffer(blockBuffer);
|
var expectedBlock = Block.fromBuffer(blockBuffer);
|
||||||
db.node = {};
|
db.node = {};
|
||||||
db.node.bitcoind = {
|
db.node.modules = {};
|
||||||
|
db.node.modules.bitcoind = {
|
||||||
getBlock: sinon.stub().callsArgWith(1, null, blockBuffer)
|
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) {
|
it('should give an error when bitcoind.js gives an error', function(done) {
|
||||||
db.node = {};
|
db.node = {};
|
||||||
db.node.bitcoind = {};
|
db.node.modules = {};
|
||||||
db.node.bitcoind.getBlock = sinon.stub().callsArgWith(1, new Error('error'));
|
db.node.modules.bitcoind = {};
|
||||||
|
db.node.modules.bitcoind.getBlock = sinon.stub().callsArgWith(1, new Error('error'));
|
||||||
db.getBlock('00000000000000000593b60d8b4f40fd1ec080bdb0817d475dae47b5f5b1f735', function(err, block) {
|
db.getBlock('00000000000000000593b60d8b4f40fd1ec080bdb0817d475dae47b5f5b1f735', function(err, block) {
|
||||||
should.exist(err);
|
should.exist(err);
|
||||||
err.message.should.equal('error');
|
err.message.should.equal('error');
|
||||||
|
@ -131,7 +135,8 @@ describe('Bitcoin DB', function() {
|
||||||
it('should return prevHash from bitcoind', function(done) {
|
it('should return prevHash from bitcoind', function(done) {
|
||||||
var db = new DB({store: memdown});
|
var db = new DB({store: memdown});
|
||||||
db.node = {};
|
db.node = {};
|
||||||
db.node.bitcoind = {
|
db.node.modules = {};
|
||||||
|
db.node.modules.bitcoind = {
|
||||||
getBlockIndex: sinon.stub().returns({
|
getBlockIndex: sinon.stub().returns({
|
||||||
prevHash: 'prevhash'
|
prevHash: 'prevhash'
|
||||||
})
|
})
|
||||||
|
@ -147,7 +152,8 @@ describe('Bitcoin DB', function() {
|
||||||
it('should give an error if bitcoind could not find it', function(done) {
|
it('should give an error if bitcoind could not find it', function(done) {
|
||||||
var db = new DB({store: memdown});
|
var db = new DB({store: memdown});
|
||||||
db.node = {};
|
db.node = {};
|
||||||
db.node.bitcoind = {
|
db.node.modules = {};
|
||||||
|
db.node.modules.bitcoind = {
|
||||||
getBlockIndex: sinon.stub().returns(null)
|
getBlockIndex: sinon.stub().returns(null)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -169,7 +175,8 @@ describe('Bitcoin DB', function() {
|
||||||
|
|
||||||
var db = new DB({store: memdown});
|
var db = new DB({store: memdown});
|
||||||
db.node = {};
|
db.node = {};
|
||||||
db.node.bitcoind = {
|
db.node.modules = {};
|
||||||
|
db.node.modules.bitcoind = {
|
||||||
getTransactionWithBlockInfo: sinon.stub().callsArgWith(2, null, info)
|
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) {
|
it('should give an error if one occurred', function(done) {
|
||||||
var db = new DB({store: memdown});
|
var db = new DB({store: memdown});
|
||||||
db.node = {};
|
db.node = {};
|
||||||
db.node.bitcoind = {
|
db.node.modules = {};
|
||||||
|
db.node.modules.bitcoind = {
|
||||||
getTransactionWithBlockInfo: sinon.stub().callsArgWith(2, new Error('error'))
|
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) {
|
it('should give the txid on success', function(done) {
|
||||||
var db = new DB({store: memdown});
|
var db = new DB({store: memdown});
|
||||||
db.node = {};
|
db.node = {};
|
||||||
db.node.bitcoind = {
|
db.node.modules = {};
|
||||||
|
db.node.modules.bitcoind = {
|
||||||
sendTransaction: sinon.stub().returns('txid')
|
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) {
|
it('should give an error if bitcoind threw an error', function(done) {
|
||||||
var db = new DB({store: memdown});
|
var db = new DB({store: memdown});
|
||||||
db.node = {};
|
db.node = {};
|
||||||
db.node.bitcoind = {
|
db.node.modules = {};
|
||||||
|
db.node.modules.bitcoind = {
|
||||||
sendTransaction: sinon.stub().throws(new Error('error'))
|
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) {
|
it('should pass along the fee from bitcoind', function(done) {
|
||||||
var db = new DB({store: memdown});
|
var db = new DB({store: memdown});
|
||||||
db.node = {};
|
db.node = {};
|
||||||
db.node.bitcoind = {
|
db.node.modules = {};
|
||||||
|
db.node.modules.bitcoind = {
|
||||||
estimateFee: sinon.stub().returns(1000)
|
estimateFee: sinon.stub().returns(1000)
|
||||||
};
|
};
|
||||||
|
|
||||||
db.estimateFee(5, function(err, fee) {
|
db.estimateFee(5, function(err, fee) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
fee.should.equal(1000);
|
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();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,15 +11,14 @@ var errors = bitcorenode.errors;
|
||||||
var levelup = require('levelup');
|
var levelup = require('levelup');
|
||||||
|
|
||||||
var mockdb = {
|
var mockdb = {
|
||||||
bitcoind: {
|
|
||||||
on: sinon.stub()
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var mocknode = {
|
var mocknode = {
|
||||||
db: mockdb,
|
db: mockdb,
|
||||||
bitcoind: {
|
modules: {
|
||||||
on: sinon.stub()
|
bitcoind: {
|
||||||
|
on: sinon.stub()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -103,12 +102,6 @@ describe('AddressModule', function() {
|
||||||
|
|
||||||
describe('#blockHandler', function() {
|
describe('#blockHandler', function() {
|
||||||
var am;
|
var am;
|
||||||
var db = {
|
|
||||||
bitcoind: {
|
|
||||||
on: sinon.stub()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var testBlock = bitcore.Block.fromString(blockData);
|
var testBlock = bitcore.Block.fromString(blockData);
|
||||||
|
|
||||||
var data = [
|
var data = [
|
||||||
|
@ -212,12 +205,6 @@ describe('AddressModule', function() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
it('should continue if output script is null', function(done) {
|
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 am = new AddressModule({node: mocknode, network: 'livenet'});
|
||||||
|
|
||||||
var block = {
|
var block = {
|
||||||
|
@ -247,15 +234,13 @@ describe('AddressModule', function() {
|
||||||
});
|
});
|
||||||
it('will call event handlers', function() {
|
it('will call event handlers', function() {
|
||||||
var testBlock = bitcore.Block.fromString(blockData);
|
var testBlock = bitcore.Block.fromString(blockData);
|
||||||
var db = {
|
var db = {};
|
||||||
bitcoind: {
|
|
||||||
on: sinon.stub()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var testnode = {
|
var testnode = {
|
||||||
db: db,
|
db: db,
|
||||||
bitcoind: {
|
modules: {
|
||||||
on: sinon.stub()
|
bitcoind: {
|
||||||
|
on: sinon.stub()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var am = new AddressModule({node: testnode, network: 'livenet'});
|
var am = new AddressModule({node: testnode, network: 'livenet'});
|
||||||
|
@ -444,8 +429,10 @@ describe('AddressModule', function() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
db: db,
|
db: db,
|
||||||
bitcoind: {
|
modules: {
|
||||||
on: sinon.stub()
|
bitcoind: {
|
||||||
|
on: sinon.stub()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -467,7 +454,7 @@ describe('AddressModule', function() {
|
||||||
blockHeight: 352532
|
blockHeight: 352532
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
am.node.bitcoind = {
|
am.node.modules.bitcoind = {
|
||||||
getMempoolOutputs: sinon.stub().returns(mempoolOutputs)
|
getMempoolOutputs: sinon.stub().returns(mempoolOutputs)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -535,15 +522,13 @@ describe('AddressModule', function() {
|
||||||
'addr3': ['utxo3']
|
'addr3': ['utxo3']
|
||||||
};
|
};
|
||||||
|
|
||||||
var db = {
|
var db = {};
|
||||||
bitcoind: {
|
|
||||||
on: sinon.spy()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var testnode = {
|
var testnode = {
|
||||||
db: db,
|
db: db,
|
||||||
bitcoind: {
|
modules: {
|
||||||
on: sinon.stub()
|
bitcoind: {
|
||||||
|
on: sinon.stub()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var am = new AddressModule({node: testnode});
|
var am = new AddressModule({node: testnode});
|
||||||
|
@ -570,14 +555,18 @@ describe('AddressModule', function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
var db = {
|
var db = {
|
||||||
bitcoind: {
|
modules: {
|
||||||
on: sinon.spy()
|
bitcoind: {
|
||||||
|
on: sinon.spy()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var testnode = {
|
var testnode = {
|
||||||
db: db,
|
db: db,
|
||||||
bitcoind: {
|
modules: {
|
||||||
on: sinon.stub()
|
bitcoind: {
|
||||||
|
on: sinon.stub()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var am = new AddressModule({node: testnode});
|
var am = new AddressModule({node: testnode});
|
||||||
|
@ -604,15 +593,13 @@ describe('AddressModule', function() {
|
||||||
'addr3': ['utxo3']
|
'addr3': ['utxo3']
|
||||||
};
|
};
|
||||||
|
|
||||||
var db = {
|
var db = {};
|
||||||
bitcoind: {
|
|
||||||
on: sinon.spy()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var testnode = {
|
var testnode = {
|
||||||
db: db,
|
db: db,
|
||||||
bitcoind: {
|
modules: {
|
||||||
on: sinon.stub()
|
bitcoind: {
|
||||||
|
on: sinon.stub()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var am = new AddressModule({node: testnode});
|
var am = new AddressModule({node: testnode});
|
||||||
|
@ -721,20 +708,18 @@ describe('AddressModule', function() {
|
||||||
|
|
||||||
describe('#isSpent', function() {
|
describe('#isSpent', function() {
|
||||||
var am;
|
var am;
|
||||||
var db = {
|
var db = {};
|
||||||
bitcoind: {
|
|
||||||
on: sinon.stub()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var testnode = {
|
var testnode = {
|
||||||
db: db,
|
db: db,
|
||||||
bitcoind: {
|
modules: {
|
||||||
on: sinon.stub()
|
bitcoind: {
|
||||||
|
on: sinon.stub()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
before(function() {
|
before(function() {
|
||||||
am = new AddressModule({node: testnode});
|
am = new AddressModule({node: testnode});
|
||||||
am.node.bitcoind = {
|
am.node.modules.bitcoind = {
|
||||||
isSpent: sinon.stub().returns(true),
|
isSpent: sinon.stub().returns(true),
|
||||||
on: sinon.stub()
|
on: sinon.stub()
|
||||||
};
|
};
|
||||||
|
@ -757,8 +742,10 @@ describe('AddressModule', function() {
|
||||||
};
|
};
|
||||||
var testnode = {
|
var testnode = {
|
||||||
db: db,
|
db: db,
|
||||||
bitcoind: {
|
modules: {
|
||||||
on: sinon.stub()
|
bitcoind: {
|
||||||
|
on: sinon.stub()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var am = new AddressModule({node: testnode});
|
var am = new AddressModule({node: testnode});
|
||||||
|
@ -875,8 +862,10 @@ describe('AddressModule', function() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
db: db,
|
db: db,
|
||||||
bitcoind: {
|
modules: {
|
||||||
on: sinon.stub()
|
bitcoind: {
|
||||||
|
on: sinon.stub()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var am = new AddressModule({node: testnode});
|
var am = new AddressModule({node: testnode});
|
||||||
|
|
|
@ -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');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -11,15 +11,17 @@ var blockData = require('./data/livenet-345003.json');
|
||||||
var proxyquire = require('proxyquire');
|
var proxyquire = require('proxyquire');
|
||||||
var index = require('..');
|
var index = require('..');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var bitcoinConfBuffer = fs.readFileSync(__dirname + '/data/bitcoin.conf');
|
|
||||||
var chainHashes = require('./data/hashes.json');
|
var chainHashes = require('./data/hashes.json');
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
var BaseModule = require('../lib/module');
|
var BaseModule = require('../lib/module');
|
||||||
|
|
||||||
describe('Bitcore Node', function() {
|
describe('Bitcore Node', function() {
|
||||||
|
|
||||||
|
var baseConfig = {
|
||||||
|
datadir: 'testdir'
|
||||||
|
};
|
||||||
|
|
||||||
var Node;
|
var Node;
|
||||||
var BadNode;
|
|
||||||
|
|
||||||
function hexlebuf(hexString){
|
function hexlebuf(hexString){
|
||||||
return BufferUtil.reverse(new Buffer(hexString, 'hex'));
|
return BufferUtil.reverse(new Buffer(hexString, 'hex'));
|
||||||
|
@ -30,23 +32,9 @@ describe('Bitcore Node', function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
|
Node = proxyquire('../lib/node', {});
|
||||||
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.prototype._loadConfiguration = sinon.spy();
|
Node.prototype._loadConfiguration = sinon.spy();
|
||||||
Node.prototype._initialize = sinon.spy();
|
Node.prototype._initialize = sinon.spy();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('@constructor', function() {
|
describe('@constructor', function() {
|
||||||
|
@ -60,6 +48,7 @@ describe('Bitcore Node', function() {
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
var config = {
|
var config = {
|
||||||
|
datadir: 'testdir',
|
||||||
modules: [
|
modules: [
|
||||||
{
|
{
|
||||||
name: 'test1',
|
name: 'test1',
|
||||||
|
@ -81,7 +70,7 @@ describe('Bitcore Node', function() {
|
||||||
|
|
||||||
describe('#openBus', function() {
|
describe('#openBus', function() {
|
||||||
it('will create a new bus', function() {
|
it('will create a new bus', function() {
|
||||||
var node = new Node({});
|
var node = new Node(baseConfig);
|
||||||
var bus = node.openBus();
|
var bus = node.openBus();
|
||||||
bus.node.should.equal(node);
|
bus.node.should.equal(node);
|
||||||
});
|
});
|
||||||
|
@ -89,7 +78,7 @@ describe('Bitcore Node', function() {
|
||||||
|
|
||||||
describe('#addModule', function() {
|
describe('#addModule', function() {
|
||||||
it('will instantiate an instance and load api methods', function() {
|
it('will instantiate an instance and load api methods', function() {
|
||||||
var node = new Node({});
|
var node = new Node(baseConfig);
|
||||||
function TestModule() {}
|
function TestModule() {}
|
||||||
util.inherits(TestModule, BaseModule);
|
util.inherits(TestModule, BaseModule);
|
||||||
TestModule.prototype.getData = function() {};
|
TestModule.prototype.getData = function() {};
|
||||||
|
@ -110,7 +99,7 @@ describe('Bitcore Node', function() {
|
||||||
|
|
||||||
describe('#getAllAPIMethods', function() {
|
describe('#getAllAPIMethods', function() {
|
||||||
it('should return db methods and modules methods', function() {
|
it('should return db methods and modules methods', function() {
|
||||||
var node = new Node({});
|
var node = new Node(baseConfig);
|
||||||
node.modules = {
|
node.modules = {
|
||||||
module1: {
|
module1: {
|
||||||
getAPIMethods: sinon.stub().returns(['mda1', 'mda2'])
|
getAPIMethods: sinon.stub().returns(['mda1', 'mda2'])
|
||||||
|
@ -130,7 +119,7 @@ describe('Bitcore Node', function() {
|
||||||
});
|
});
|
||||||
describe('#getAllPublishEvents', function() {
|
describe('#getAllPublishEvents', function() {
|
||||||
it('should return modules publish events', function() {
|
it('should return modules publish events', function() {
|
||||||
var node = new Node({});
|
var node = new Node(baseConfig);
|
||||||
node.modules = {
|
node.modules = {
|
||||||
module1: {
|
module1: {
|
||||||
getPublishEvents: sinon.stub().returns(['mda1', 'mda2'])
|
getPublishEvents: sinon.stub().returns(['mda1', 'mda2'])
|
||||||
|
@ -150,62 +139,20 @@ describe('Bitcore Node', function() {
|
||||||
});
|
});
|
||||||
describe('#_loadConfiguration', function() {
|
describe('#_loadConfiguration', function() {
|
||||||
it('should call the necessary methods', function() {
|
it('should call the necessary methods', function() {
|
||||||
var TestNode = proxyquire('../lib/node', {
|
var TestNode = proxyquire('../lib/node', {});
|
||||||
fs: {
|
|
||||||
readFileSync: sinon.stub().returns(bitcoinConfBuffer)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
TestNode.prototype._initialize = sinon.spy();
|
TestNode.prototype._initialize = sinon.spy();
|
||||||
TestNode.prototype._loadBitcoinConf = sinon.spy();
|
|
||||||
TestNode.prototype._loadBitcoind = sinon.spy();
|
|
||||||
TestNode.prototype._loadDB = sinon.spy();
|
TestNode.prototype._loadDB = sinon.spy();
|
||||||
TestNode.prototype._loadAPI = sinon.spy();
|
TestNode.prototype._loadAPI = sinon.spy();
|
||||||
TestNode.prototype._loadConsensus = sinon.spy();
|
TestNode.prototype._loadConsensus = sinon.spy();
|
||||||
var node = new TestNode({});
|
var node = new TestNode(baseConfig);
|
||||||
node._loadBitcoind.callCount.should.equal(1);
|
|
||||||
node._loadBitcoinConf.callCount.should.equal(1);
|
|
||||||
node._loadDB.callCount.should.equal(1);
|
node._loadDB.callCount.should.equal(1);
|
||||||
node._loadAPI.callCount.should.equal(1);
|
node._loadAPI.callCount.should.equal(1);
|
||||||
node._loadConsensus.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() {
|
describe('#_syncBitcoindAncestor', function() {
|
||||||
it('will find an ancestor 6 deep', function() {
|
it('will find an ancestor 6 deep', function() {
|
||||||
var node = new Node({});
|
var node = new Node(baseConfig);
|
||||||
node.chain = {
|
node.chain = {
|
||||||
getHashes: function(tipHash, callback) {
|
getHashes: function(tipHash, callback) {
|
||||||
callback(null, chainHashes);
|
callback(null, chainHashes);
|
||||||
|
@ -248,7 +195,8 @@ describe('Bitcore Node', function() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
node.bitcoind = {
|
node.modules = {};
|
||||||
|
node.modules.bitcoind = {
|
||||||
getBlockIndex: function(hash) {
|
getBlockIndex: function(hash) {
|
||||||
var block = forkedBlocks[hash];
|
var block = forkedBlocks[hash];
|
||||||
return {
|
return {
|
||||||
|
@ -267,7 +215,7 @@ describe('Bitcore Node', function() {
|
||||||
});
|
});
|
||||||
describe('#_syncBitcoindRewind', function() {
|
describe('#_syncBitcoindRewind', function() {
|
||||||
it('will undo blocks 6 deep', function() {
|
it('will undo blocks 6 deep', function() {
|
||||||
var node = new Node({});
|
var node = new Node(baseConfig);
|
||||||
var ancestorHash = chainHashes[chainHashes.length - 6];
|
var ancestorHash = chainHashes[chainHashes.length - 6];
|
||||||
node.chain = {
|
node.chain = {
|
||||||
tip: {
|
tip: {
|
||||||
|
@ -317,10 +265,11 @@ describe('Bitcore Node', function() {
|
||||||
});
|
});
|
||||||
describe('#_syncBitcoind', function() {
|
describe('#_syncBitcoind', function() {
|
||||||
it('will get and add block up to the tip height', function(done) {
|
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 blockBuffer = new Buffer(blockData, 'hex');
|
||||||
var block = Block.fromBuffer(blockBuffer);
|
var block = Block.fromBuffer(blockBuffer);
|
||||||
node.bitcoind = {
|
node.modules = {};
|
||||||
|
node.modules.bitcoind = {
|
||||||
getBlock: sinon.stub().callsArgWith(1, null, blockBuffer),
|
getBlock: sinon.stub().callsArgWith(1, null, blockBuffer),
|
||||||
isSynced: sinon.stub().returns(true),
|
isSynced: sinon.stub().returns(true),
|
||||||
height: 1
|
height: 1
|
||||||
|
@ -349,8 +298,9 @@ describe('Bitcore Node', function() {
|
||||||
node._syncBitcoind();
|
node._syncBitcoind();
|
||||||
});
|
});
|
||||||
it('will exit and emit error with error from bitcoind.getBlock', function(done) {
|
it('will exit and emit error with error from bitcoind.getBlock', function(done) {
|
||||||
var node = new Node({});
|
var node = new Node(baseConfig);
|
||||||
node.bitcoind = {
|
node.modules = {};
|
||||||
|
node.modules.bitcoind = {
|
||||||
getBlock: sinon.stub().callsArgWith(1, new Error('test error')),
|
getBlock: sinon.stub().callsArgWith(1, new Error('test error')),
|
||||||
height: 1
|
height: 1
|
||||||
};
|
};
|
||||||
|
@ -366,10 +316,11 @@ describe('Bitcore Node', function() {
|
||||||
node._syncBitcoind();
|
node._syncBitcoind();
|
||||||
});
|
});
|
||||||
it('will stop syncing when the node is stopping', function(done) {
|
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 blockBuffer = new Buffer(blockData, 'hex');
|
||||||
var block = Block.fromBuffer(blockBuffer);
|
var block = Block.fromBuffer(blockBuffer);
|
||||||
node.bitcoind = {
|
node.modules = {};
|
||||||
|
node.modules.bitcoind = {
|
||||||
getBlock: sinon.stub().callsArgWith(1, null, blockBuffer),
|
getBlock: sinon.stub().callsArgWith(1, null, blockBuffer),
|
||||||
isSynced: sinon.stub().returns(true),
|
isSynced: sinon.stub().returns(true),
|
||||||
height: 1
|
height: 1
|
||||||
|
@ -411,6 +362,7 @@ describe('Bitcore Node', function() {
|
||||||
describe('#_loadNetwork', function() {
|
describe('#_loadNetwork', function() {
|
||||||
it('should use the testnet network if testnet is specified', function() {
|
it('should use the testnet network if testnet is specified', function() {
|
||||||
var config = {
|
var config = {
|
||||||
|
datadir: 'testdir',
|
||||||
network: 'testnet'
|
network: 'testnet'
|
||||||
};
|
};
|
||||||
var node = new Node(config);
|
var node = new Node(config);
|
||||||
|
@ -419,6 +371,7 @@ describe('Bitcore Node', function() {
|
||||||
});
|
});
|
||||||
it('should use the regtest network if regtest is specified', function() {
|
it('should use the regtest network if regtest is specified', function() {
|
||||||
var config = {
|
var config = {
|
||||||
|
datadir: 'testdir',
|
||||||
network: 'regtest'
|
network: 'regtest'
|
||||||
};
|
};
|
||||||
var node = new Node(config);
|
var node = new Node(config);
|
||||||
|
@ -426,7 +379,9 @@ describe('Bitcore Node', function() {
|
||||||
node.network.name.should.equal('regtest');
|
node.network.name.should.equal('regtest');
|
||||||
});
|
});
|
||||||
it('should use the livenet network if nothing is specified', function() {
|
it('should use the livenet network if nothing is specified', function() {
|
||||||
var config = {};
|
var config = {
|
||||||
|
datadir: 'testdir'
|
||||||
|
};
|
||||||
var node = new Node(config);
|
var node = new Node(config);
|
||||||
node._loadNetwork(config);
|
node._loadNetwork(config);
|
||||||
node.network.name.should.equal('livenet');
|
node.network.name.should.equal('livenet');
|
||||||
|
@ -526,7 +481,7 @@ describe('Bitcore Node', function() {
|
||||||
var node;
|
var node;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
node = new Node({});
|
node = new Node(baseConfig);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('will set properties', function() {
|
it('will set properties', function() {
|
||||||
|
@ -541,11 +496,7 @@ describe('Bitcore Node', function() {
|
||||||
var node;
|
var node;
|
||||||
|
|
||||||
before(function() {
|
before(function() {
|
||||||
var TestNode = proxyquire('../lib/node', {
|
var TestNode = proxyquire('../lib/node', {});
|
||||||
fs: {
|
|
||||||
readFileSync: sinon.stub().returns(bitcoinConfBuffer)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
TestNode.prototype._loadConfiguration = sinon.spy();
|
TestNode.prototype._loadConfiguration = sinon.spy();
|
||||||
TestNode.prototype._initializeBitcoind = sinon.spy();
|
TestNode.prototype._initializeBitcoind = sinon.spy();
|
||||||
TestNode.prototype._initializeDatabase = sinon.spy();
|
TestNode.prototype._initializeDatabase = sinon.spy();
|
||||||
|
@ -555,7 +506,7 @@ describe('Bitcore Node', function() {
|
||||||
var _initialize = TestNode.prototype._initialize;
|
var _initialize = TestNode.prototype._initialize;
|
||||||
TestNode.prototype._initialize = sinon.spy();
|
TestNode.prototype._initialize = sinon.spy();
|
||||||
|
|
||||||
node = new TestNode({});
|
node = new TestNode(baseConfig);
|
||||||
node.chain = {
|
node.chain = {
|
||||||
on: sinon.spy()
|
on: sinon.spy()
|
||||||
};
|
};
|
||||||
|
@ -581,7 +532,6 @@ describe('Bitcore Node', function() {
|
||||||
node._initialize();
|
node._initialize();
|
||||||
|
|
||||||
// event handlers
|
// event handlers
|
||||||
node._initializeBitcoind.callCount.should.equal(1);
|
|
||||||
node._initializeDatabase.callCount.should.equal(1);
|
node._initializeDatabase.callCount.should.equal(1);
|
||||||
node._initializeChain.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() {
|
describe('#_initializeDatabase', function() {
|
||||||
it('will log on ready event', function(done) {
|
it('will log on ready event', function(done) {
|
||||||
var node = new Node({});
|
var node = new Node(baseConfig);
|
||||||
node.db = new EventEmitter();
|
node.db = new EventEmitter();
|
||||||
sinon.stub(index.log, 'info');
|
sinon.stub(index.log, 'info');
|
||||||
node.db.on('ready', function() {
|
node.db.on('ready', function() {
|
||||||
|
@ -657,7 +565,7 @@ describe('Bitcore Node', function() {
|
||||||
node.db.emit('ready');
|
node.db.emit('ready');
|
||||||
});
|
});
|
||||||
it('will call emit an error from db', function(done) {
|
it('will call emit an error from db', function(done) {
|
||||||
var node = new Node({});
|
var node = new Node(baseConfig);
|
||||||
node.db = new EventEmitter();
|
node.db = new EventEmitter();
|
||||||
node.on('error', function(err) {
|
node.on('error', function(err) {
|
||||||
should.exist(err);
|
should.exist(err);
|
||||||
|
@ -670,21 +578,42 @@ describe('Bitcore Node', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#_initializeChain', function() {
|
describe('#_initializeChain', function() {
|
||||||
it('will call _syncBitcoind on ready', function(done) {
|
|
||||||
var node = new Node({});
|
it('will call sync when there is a new tip', function(done) {
|
||||||
node._syncBitcoind = sinon.spy();
|
var node = new Node(baseConfig);
|
||||||
node.chain = new EventEmitter();
|
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() {
|
setImmediate(function() {
|
||||||
node._syncBitcoind.callCount.should.equal(1);
|
node.modules.bitcoind.syncPercentage.callCount.should.equal(0);
|
||||||
|
node._syncBitcoind.callCount.should.equal(0);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
node._initializeChain();
|
node._initializeChain();
|
||||||
node.chain.emit('ready');
|
node.chain.emit('ready');
|
||||||
|
node.modules.bitcoind.emit('tip', 10);
|
||||||
});
|
});
|
||||||
it('will emit an error from the chain', function(done) {
|
it('will emit an error from the chain', function(done) {
|
||||||
var node = new Node({});
|
var node = new Node(baseConfig);
|
||||||
node.chain = new EventEmitter();
|
node.chain = new EventEmitter();
|
||||||
node.on('error', function(err) {
|
node.on('error', function(err) {
|
||||||
should.exist(err);
|
should.exist(err);
|
||||||
|
@ -698,7 +627,7 @@ describe('Bitcore Node', function() {
|
||||||
|
|
||||||
describe('#getServiceOrder', function() {
|
describe('#getServiceOrder', function() {
|
||||||
it('should return the services in the correct order', function() {
|
it('should return the services in the correct order', function() {
|
||||||
var node = new Node({});
|
var node = new Node(baseConfig);
|
||||||
node.getServices = function() {
|
node.getServices = function() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
@ -729,7 +658,7 @@ describe('Bitcore Node', function() {
|
||||||
|
|
||||||
describe('#start', function() {
|
describe('#start', function() {
|
||||||
it('will call start for each module', function(done) {
|
it('will call start for each module', function(done) {
|
||||||
var node = new Node({});
|
var node = new Node(baseConfig);
|
||||||
function TestModule() {}
|
function TestModule() {}
|
||||||
util.inherits(TestModule, BaseModule);
|
util.inherits(TestModule, BaseModule);
|
||||||
TestModule.prototype.start = sinon.stub().callsArg(0);
|
TestModule.prototype.start = sinon.stub().callsArg(0);
|
||||||
|
@ -760,7 +689,7 @@ describe('Bitcore Node', function() {
|
||||||
|
|
||||||
describe('#stop', function() {
|
describe('#stop', function() {
|
||||||
it('will call stop for each module', function(done) {
|
it('will call stop for each module', function(done) {
|
||||||
var node = new Node({});
|
var node = new Node(baseConfig);
|
||||||
function TestModule() {}
|
function TestModule() {}
|
||||||
util.inherits(TestModule, BaseModule);
|
util.inherits(TestModule, BaseModule);
|
||||||
TestModule.prototype.stop = sinon.stub().callsArg(0);
|
TestModule.prototype.stop = sinon.stub().callsArg(0);
|
||||||
|
|
Loading…
Reference in New Issue