diff --git a/index.js b/index.js index 7233605e..1d07625d 100644 --- a/index.js +++ b/index.js @@ -3,7 +3,6 @@ module.exports = require('./lib'); module.exports.Node = require('./lib/node'); module.exports.Chain = require('./lib/chain'); -module.exports.DB = require('./lib/db'); module.exports.Transaction = require('./lib/transaction'); module.exports.Module = require('./lib/module'); module.exports.errors = require('./lib/errors'); @@ -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.modules.DBModule = require('./lib/modules/db'); module.exports.scaffold = {}; module.exports.scaffold.create = require('./lib/scaffold/create'); diff --git a/integration/regtest-node.js b/integration/regtest-node.js index ef2bcaa1..398704e9 100644 --- a/integration/regtest-node.js +++ b/integration/regtest-node.js @@ -27,6 +27,7 @@ var index = require('..'); var BitcoreNode = index.Node; var AddressModule = index.modules.AddressModule; var BitcoinModule = index.modules.BitcoinModule; +var DBModule = index.modules.DBModule; var testWIF = 'cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG'; var testKey; var client; @@ -65,6 +66,11 @@ describe('Node Functionality', function() { datadir: datadir, network: 'regtest', modules: [ + { + name: 'db', + module: DBModule, + dependencies: DBModule.dependencies + }, { name: 'bitcoind', module: BitcoinModule, diff --git a/lib/chain.js b/lib/chain.js index ceb54e66..81690a81 100644 --- a/lib/chain.js +++ b/lib/chain.js @@ -99,30 +99,25 @@ Chain.prototype.initialize = function() { var self = this; // Does our database already have a tip? - self.node.db.getMetadata(function getMetadataCallback(err, metadata) { + self.node.modules.db.getMetadata(function getMetadataCallback(err, metadata) { if(err) { return self.emit('error', err); } else if(!metadata || !metadata.tip) { self.tip = self.genesis; self.tip.__height = 0; self.tip.__weight = self.genesisWeight; - self.node.db.putBlock(self.genesis, function putBlockCallback(err) { + self.node.modules.db.connectBlock(self.genesis, function(err) { if(err) { return self.emit('error', err); } - self.node.db._onChainAddBlock(self.genesis, function(err) { - if(err) { - return self.emit('error', err); - } - self.emit('addblock', self.genesis); - self.saveMetadata(); - self.emit('initialized'); - }); + self.emit('addblock', self.genesis); + self.saveMetadata(); + self.emit('initialized'); }); } else { metadata.tip = metadata.tip; - self.node.db.getBlock(metadata.tip, function getBlockCallback(err, tip) { + self.node.modules.db.getBlock(metadata.tip, function getBlockCallback(err, tip) { if(err) { return self.emit('error', err); } @@ -215,7 +210,7 @@ Chain.prototype.getHashes = function getHashes(tipHash, callback) { } } else { // do a db call if we don't have it - self.node.db.getPrevHash(hash, function(err, prevHash) { + self.node.modules.db.getPrevHash(hash, function(err, prevHash) { if(err) { return callback(err); } @@ -246,7 +241,7 @@ Chain.prototype.saveMetadata = function saveMetadata(callback) { self.lastSavedMetadata = new Date(); - self.node.db.putMetadata(metadata, callback); + self.node.modules.db.putMetadata(metadata, callback); }; module.exports = Chain; diff --git a/lib/modules/address.js b/lib/modules/address.js index 36e0f738..ba47848f 100644 --- a/lib/modules/address.js +++ b/lib/modules/address.js @@ -82,10 +82,10 @@ AddressModule.prototype.transactionOutputHandler = function(messages, tx, output } // Find the address for the output - var address = script.toAddress(this.node.db.network); + var address = script.toAddress(this.node.network); if (!address && script.isPublicKeyOut()) { var pubkey = script.chunks[0].buf; - address = Address.fromPublicKey(new PublicKey(pubkey), this.node.db.network); + address = Address.fromPublicKey(new PublicKey(pubkey), this.node.network); } else if (!address){ return; } @@ -162,10 +162,10 @@ AddressModule.prototype.blockHandler = function(block, addOutput, callback) { continue; } - var address = script.toAddress(this.node.db.network); + var address = script.toAddress(this.node.network); if (!address && script.isPublicKeyOut()) { var pubkey = script.chunks[0].buf; - address = Address.fromPublicKey(new PublicKey(pubkey), this.node.db.network); + address = Address.fromPublicKey(new PublicKey(pubkey), this.node.network); } else if (!address){ continue; } @@ -329,7 +329,7 @@ AddressModule.prototype.getOutputs = function(addressStr, queryMempool, callback var outputs = []; var key = [AddressModule.PREFIXES.OUTPUTS, addressStr].join('-'); - var stream = this.node.db.store.createReadStream({ + var stream = this.node.modules.db.store.createReadStream({ start: key, end: key + '~' }); @@ -443,7 +443,7 @@ AddressModule.prototype.getSpendInfoForOutput = function(txid, outputIndex, call var self = this; var key = [AddressModule.PREFIXES.SPENTS, txid, outputIndex].join('-'); - this.node.db.store.get(key, function(err, value) { + this.node.modules.db.store.get(key, function(err, value) { if(err) { return callback(err); } @@ -492,12 +492,12 @@ AddressModule.prototype.getAddressHistoryForAddress = function(address, queryMem return callback(null, txinfos[txid]); } - self.node.db.getTransactionWithBlockInfo(txid, queryMempool, function(err, transaction) { + self.node.modules.db.getTransactionWithBlockInfo(txid, queryMempool, function(err, transaction) { if(err) { return callback(err); } - transaction.populateInputs(self.node.db, [], function(err) { + transaction.populateInputs(self.node.modules.db, [], function(err) { if(err) { return callback(err); } diff --git a/lib/modules/bitcoind.js b/lib/modules/bitcoind.js index 433c8910..96c791cd 100644 --- a/lib/modules/bitcoind.js +++ b/lib/modules/bitcoind.js @@ -1,14 +1,15 @@ '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; +var index = require('../'); +var log = index.log; +var Module = require('../module'); + /** * Provides an interface to native bindings to Bitcoin Core diff --git a/lib/db.js b/lib/modules/db.js similarity index 61% rename from lib/db.js rename to lib/modules/db.js index b6f3d3a2..b5b5ff7f 100644 --- a/lib/db.js +++ b/lib/modules/db.js @@ -1,78 +1,81 @@ 'use strict'; -var EventEmitter = require('events').EventEmitter; var util = require('util'); +var fs = require('fs'); var async = require('async'); var levelup = require('levelup'); var leveldown = require('leveldown'); +var mkdirp = require('mkdirp'); var bitcore = require('bitcore'); +var Networks = bitcore.Networks; var Block = bitcore.Block; var $ = bitcore.util.preconditions; -var index = require('./'); +var index = require('../'); var errors = index.errors; var log = index.log; -var Transaction = require('./transaction'); +var Transaction = require('../transaction'); +var Module = require('../module'); +/** + * Represents the current state of the bitcoin blockchain transaction data. Other modules + * can extend the data that is indexed by implementing a `blockHandler` method. + * + * @param {Object} options + * @param {String} options.datadir - The bitcoin data directory + * @param {Node} options.node - A reference to the node + */ function DB(options) { - /* jshint maxstatements: 30 */ - /* jshint maxcomplexity: 20 */ - if (!(this instanceof DB)) { return new DB(options); } - if(!options) { + if (!options) { options = {}; } - this.coinbaseAmount = options.coinbaseAmount || 50 * 1e8; + Module.call(this, options); - var levelupStore = leveldown; + $.checkState(this.node.network, 'Node is expected to have a "network" property'); + this.network = this.node.network; - if(options.store) { - levelupStore = options.store; - } else if(!options.path) { - throw new Error('Please include database path in options'); + this._setDataPath(); + + this.levelupStore = leveldown; + if (options.store) { + this.levelupStore = options.store; } - this.store = levelup(options.path, { db: levelupStore }); - this.txPrefix = options.txPrefix || DB.PREFIXES.TX; - this.prevHashPrefix = options.prevHashPrefix || DB.PREFIXES.PREV_HASH; - this.blockPrefix = options.blockPrefix || DB.PREFIXES.BLOCK; - this.dataPrefix = options.dataPrefix || DB.PREFIXES.DATA; - this.weightPrefix = options.weightPrefix || DB.PREFIXES.WEIGHT; - this.Transaction = Transaction; - - this.coinbaseAddress = options.coinbaseAddress; - this.coinbaseAmount = options.coinbaseAmount || 50 * 1e8; - this.Transaction = Transaction; - - this.network = bitcore.Networks.get(options.network) || bitcore.Networks.testnet; - - this.node = options.node; - this.subscriptions = { transaction: [], block: [] }; } -DB.PREFIXES = { - TX: 'tx', - PREV_HASH: 'ph', - BLOCK: 'blk', - DATA: 'data', - WEIGHT: 'wt' -}; +util.inherits(DB, Module); -util.inherits(DB, EventEmitter); +DB.dependencies = ['bitcoind']; -DB.prototype.initialize = function() { - this.emit('ready'); +DB.prototype._setDataPath = function() { + $.checkState(this.node.datadir, 'Node is expected to have a "datadir" property'); + var regtest = Networks.get('regtest'); + if (this.node.network === Networks.livenet) { + this.dataPath = this.node.datadir + '/bitcore-node.db'; + } else if (this.node.network === Networks.testnet) { + this.dataPath = this.node.datadir + '/testnet3/bitcore-node.db'; + } else if (this.node.network === regtest) { + this.dataPath = this.node.datadir + '/regtest/bitcore-node.db'; + } else { + throw new Error('Unknown network: ' + this.network); + } }; DB.prototype.start = function(callback) { + if (!fs.existsSync(this.dataPath)) { + mkdirp.sync(this.dataPath); + } + this.store = levelup(this.dataPath, { db: this.levelupStore }); this.node.modules.bitcoind.on('tx', this.transactionHandler.bind(this)); this.emit('ready'); + log.info('Bitcoin Database Ready'); setImmediate(callback); }; @@ -89,40 +92,50 @@ DB.prototype.getInfo = function(callback) { }); }; -DB.prototype.getBlock = function(hash, callback) { - var self = this; +DB.prototype.transactionHandler = function(txInfo) { + var tx = Transaction().fromBuffer(txInfo.buffer); + for (var i = 0; i < this.subscriptions.transaction.length; i++) { + this.subscriptions.transaction[i].emit('transaction', { + rejected: !txInfo.mempool, + tx: tx + }); + } +}; - // get block from bitcoind +/** + * Closes the underlying store database + * @param {Function} callback - A function that accepts: Error + */ +DB.prototype.close = function(callback) { + this.store.close(callback); +}; + +DB.prototype.getAPIMethods = function() { + var methods = [ + ['getBlock', this, this.getBlock, 1], + ['getTransaction', this, this.getTransaction, 2], + ['getTransactionWithBlockInfo', this, this.getTransactionWithBlockInfo, 2], + ['sendTransaction', this, this.sendTransaction, 1], + ['estimateFee', this, this.estimateFee, 1] + ]; + return methods; +}; + +DB.prototype.getBlock = function(hash, callback) { this.node.modules.bitcoind.getBlock(hash, function(err, blockData) { - if(err) { + if (err) { return callback(err); } callback(null, Block.fromBuffer(blockData)); }); }; -DB.prototype.getPrevHash = function(blockHash, callback) { - var blockIndex = this.node.modules.bitcoind.getBlockIndex(blockHash); - setImmediate(function() { - if (blockIndex) { - callback(null, blockIndex.prevHash); - } else { - callback(new Error('Could not get prevHash, block not found')); - } - }); -}; - -DB.prototype.putBlock = function(block, callback) { - // block is already stored in bitcoind - setImmediate(callback); -}; - DB.prototype.getTransaction = function(txid, queryMempool, callback) { this.node.modules.bitcoind.getTransaction(txid, queryMempool, function(err, txBuffer) { - if(err) { + if (err) { return callback(err); } - if(!txBuffer) { + if (!txBuffer) { return callback(new errors.Transaction.NotFound()); } @@ -132,7 +145,7 @@ DB.prototype.getTransaction = function(txid, queryMempool, callback) { DB.prototype.getTransactionWithBlockInfo = function(txid, queryMempool, callback) { this.node.modules.bitcoind.getTransactionWithBlockInfo(txid, queryMempool, function(err, obj) { - if(err) { + if (err) { return callback(err); } @@ -145,7 +158,7 @@ DB.prototype.getTransactionWithBlockInfo = function(txid, queryMempool, callback }; DB.prototype.sendTransaction = function(tx, callback) { - if(tx instanceof this.Transaction) { + if (tx instanceof Transaction) { tx = tx.toString(); } $.checkArgument(typeof tx === 'string', 'Argument must be a hex string or Transaction'); @@ -160,153 +173,11 @@ DB.prototype.sendTransaction = function(tx, callback) { DB.prototype.estimateFee = function(blocks, callback) { var self = this; - setImmediate(function() { callback(null, self.node.modules.bitcoind.estimateFee(blocks)); }); }; -DB.prototype.validateBlockData = function(block, callback) { - // bitcoind does the validation - setImmediate(callback); -}; - -DB.prototype._updatePrevHashIndex = function(block, callback) { - // bitcoind has the previous hash for each block - setImmediate(callback); -}; - -DB.prototype._updateWeight = function(hash, weight, callback) { - // bitcoind has all work for each block - setImmediate(callback); -}; - -/** - * Saves metadata to the database - * @param {Object} metadata - The metadata - * @param {Function} callback - A function that accepts: Error - */ -DB.prototype.putMetadata = function(metadata, callback) { - this.store.put('metadata', JSON.stringify(metadata), {}, callback); -}; - -/** - * Retrieves metadata from the database - * @param {Function} callback - A function that accepts: Error and Object - */ -DB.prototype.getMetadata = function(callback) { - var self = this; - - self.store.get('metadata', {}, function(err, data) { - if(err instanceof levelup.errors.NotFoundError) { - return callback(null, {}); - } else if(err) { - return callback(err); - } - - var metadata; - try { - metadata = JSON.parse(data); - } catch(e) { - return callback(new Error('Could not parse metadata')); - } - - callback(null, metadata); - }); -}; - -/** - * Closes the underlying store database - * @param {Function} callback - A function that accepts: Error - */ -DB.prototype.close = function(callback) { - this.store.close(callback); -}; - -DB.prototype.getOutputTotal = function(transactions, excludeCoinbase) { - var totals = transactions.map(function(tx) { - if(tx.isCoinbase() && excludeCoinbase) { - return 0; - } else { - return tx._getOutputAmount(); - } - }); - var grandTotal = totals.reduce(function(previousValue, currentValue) { - return previousValue + currentValue; - }); - return grandTotal; -}; - -DB.prototype.getInputTotal = function(transactions) { - var totals = transactions.map(function(tx) { - if(tx.isCoinbase()) { - return 0; - } else { - return tx._getInputAmount(); - } - }); - var grandTotal = totals.reduce(function(previousValue, currentValue) { - return previousValue + currentValue; - }); - return grandTotal; -}; - -DB.prototype._onChainAddBlock = function(block, callback) { - log.debug('DB handling new chain block'); - - this.blockHandler(block, true, callback); -}; - -DB.prototype._onChainRemoveBlock = function(block, callback) { - log.debug('DB removing chain block'); - this.blockHandler(block, false, callback); -}; - -DB.prototype.blockHandler = function(block, add, callback) { - var self = this; - var operations = []; - - // Notify block subscribers - for(var i = 0; i < this.subscriptions.block.length; i++) { - this.subscriptions.block[i].emit('block', block.hash); - } - - async.eachSeries( - this.node.modules, - function(bitcoreNodeModule, next) { - bitcoreNodeModule.blockHandler.call(bitcoreNodeModule, block, add, function(err, ops) { - if(err) { - return next(err); - } - if (ops) { - operations = operations.concat(ops); - } - next(); - }); - }, - function(err) { - if (err) { - return callback(err); - } - - log.debug('Updating the database with operations', operations); - - self.store.batch(operations, callback); - } - ); -}; - -DB.prototype.getAPIMethods = function() { - var methods = [ - ['getInfo', this, this.getInfo, 0], - ['getBlock', this, this.getBlock, 1], - ['getTransaction', this, this.getTransaction, 2], - ['sendTransaction', this, this.sendTransaction, 1], - ['estimateFee', this, this.estimateFee, 1] - ]; - return methods; -}; - DB.prototype.getPublishEvents = function() { return [ { @@ -330,19 +201,120 @@ DB.prototype.subscribe = function(name, emitter) { DB.prototype.unsubscribe = function(name, emitter) { var index = this.subscriptions[name].indexOf(emitter); - if(index > -1) { + if (index > -1) { this.subscriptions[name].splice(index, 1); } }; -DB.prototype.transactionHandler = function(txInfo) { - var tx = bitcore.Transaction().fromBuffer(txInfo.buffer); - for(var i = 0; i < this.subscriptions.transaction.length; i++) { - this.subscriptions.transaction[i].emit('transaction', { - rejected: !txInfo.mempool, - tx: tx - }); +/** + * Will give the previous hash for a block. + * @param {String} blockHash + * @param {Function} callback + */ +DB.prototype.getPrevHash = function(blockHash, callback) { + var blockIndex = this.node.modules.bitcoind.getBlockIndex(blockHash); + setImmediate(function() { + if (blockIndex) { + callback(null, blockIndex.prevHash); + } else { + callback(new Error('Could not get prevHash, block not found')); + } + }); +}; + +/** + * Saves metadata to the database + * @param {Object} metadata - The metadata + * @param {Function} callback - A function that accepts: Error + */ +DB.prototype.putMetadata = function(metadata, callback) { + this.store.put('metadata', JSON.stringify(metadata), {}, callback); +}; + +/** + * Retrieves metadata from the database + * @param {Function} callback - A function that accepts: Error and Object + */ +DB.prototype.getMetadata = function(callback) { + var self = this; + + self.store.get('metadata', {}, function(err, data) { + if (err instanceof levelup.errors.NotFoundError) { + return callback(null, {}); + } else if (err) { + return callback(err); + } + + var metadata; + try { + metadata = JSON.parse(data); + } catch(e) { + return callback(new Error('Could not parse metadata')); + } + + callback(null, metadata); + }); +}; + +/** + * Connects a block to the database and add indexes + * @param {Block} block - The bitcore block + * @param {Function} callback + */ +DB.prototype.connectBlock = function(block, callback) { + log.debug('DB handling new chain block'); + this.runAllBlockHandlers(block, true, callback); +}; + +/** + * Disconnects a block from the database and removes indexes + * @param {Block} block - The bitcore block + * @param {Function} callback + */ +DB.prototype.disconnectBlock = function(block, callback) { + log.debug('DB removing chain block'); + this.runAllBlockHandlers(block, false, callback); +}; + +/** + * Will collect all database operations for a block from other modules + * and save to the database. + * @param {Block} block - The bitcore block + * @param {Boolean} add - If the block is being added/connected or removed/disconnected + * @param {Function} callback + */ +DB.prototype.runAllBlockHandlers = function(block, add, callback) { + var self = this; + var operations = []; + + // Notify block subscribers + for (var i = 0; i < this.subscriptions.block.length; i++) { + this.subscriptions.block[i].emit('block', block.hash); } + + async.eachSeries( + this.node.modules, + function(mod, next) { + mod.blockHandler.call(mod, block, add, function(err, ops) { + if (err) { + return next(err); + } + if (ops) { + operations = operations.concat(ops); + } + next(); + }); + }, + function(err) { + if (err) { + return callback(err); + } + + log.debug('Updating the database with operations', operations); + + self.store.batch(operations, callback); + } + ); }; module.exports = DB; diff --git a/lib/node.js b/lib/node.js index 1bba402d..e71cd39c 100644 --- a/lib/node.js +++ b/lib/node.js @@ -1,10 +1,8 @@ 'use strict'; -var fs = require('fs'); var util = require('util'); var EventEmitter = require('events').EventEmitter; var async = require('async'); -var mkdirp = require('mkdirp'); var bitcore = require('bitcore'); var BufferUtil = bitcore.util.buffer; var Networks = bitcore.Networks; @@ -12,7 +10,6 @@ var _ = bitcore.deps._; var $ = bitcore.util.preconditions; var Block = bitcore.Block; var Chain = require('./chain'); -var DB = require('./db'); var index = require('./'); var log = index.log; var Bus = require('./bus'); @@ -23,7 +20,6 @@ function Node(config) { return new Node(config); } - this.db = null; this.chain = null; this.network = null; @@ -81,7 +77,7 @@ Node.prototype.addModule = function(service) { }; Node.prototype.getAllAPIMethods = function() { - var methods = this.db.getAPIMethods(); + var methods = []; for(var i in this.modules) { var mod = this.modules[i]; methods = methods.concat(mod.getAPIMethods()); @@ -90,7 +86,7 @@ Node.prototype.getAllAPIMethods = function() { }; Node.prototype.getAllPublishEvents = function() { - var events = this.db.getPublishEvents(); + var events = []; for (var i in this.modules) { var mod = this.modules[i]; events = events.concat(mod.getPublishEvents()); @@ -100,8 +96,6 @@ Node.prototype.getAllPublishEvents = function() { Node.prototype._loadConfiguration = function(config) { this._loadNetwork(config); - this._loadDB(config); - this._loadAPI(); this._loadConsensus(config); }; @@ -185,7 +179,7 @@ Node.prototype._syncBitcoindRewind = function(block, done) { } // Undo the related indexes for this block - self.db._onChainRemoveBlock(tip, function(err) { + self.modules.db.disconnectBlock(tip, function(err) { if (err) { return removeDone(err); } @@ -258,7 +252,7 @@ Node.prototype._syncBitcoind = function() { return done(err); } // Create indexes - self.db._onChainAddBlock(block, function(err) { + self.modules.db.connectBlock(block, function(err) { if (err) { return done(err); } @@ -325,39 +319,6 @@ Node.prototype._loadNetwork = function(config) { $.checkState(this.network, 'Unrecognized network'); }; -Node.prototype._loadDB = function(config) { - var options = _.clone(config.db || {}); - - if (config.DB) { - // Other modules can inherit from our DB and replace it with their own - DB = config.DB; - } - - // Store the additional indexes in a new directory - // based on the network configuration and the datadir - $.checkArgument(config.datadir, 'Please specify "datadir" in configuration options'); - $.checkState(this.network, 'Network property not defined'); - var regtest = Networks.get('regtest'); - if (this.network === Networks.livenet) { - options.path = config.datadir + '/bitcore-node.db'; - } else if (this.network === Networks.testnet) { - options.path = config.datadir + '/testnet3/bitcore-node.db'; - } else if (this.network === regtest) { - options.path = config.datadir + '/regtest/bitcore-node.db'; - } else { - throw new Error('Unknown network: ' + this.network); - } - options.network = this.network; - - if (!fs.existsSync(options.path)) { - mkdirp.sync(options.path); - } - - options.node = this; - - this.db = new DB(options); -}; - Node.prototype._loadConsensus = function(config) { var options; if (!config) { @@ -369,24 +330,9 @@ Node.prototype._loadConsensus = function(config) { this.chain = new Chain(options); }; -Node.prototype._loadAPI = function() { - var self = this; - var methodData = self.db.getAPIMethods(); - methodData.forEach(function(data) { - var name = data[0]; - var instance = data[1]; - var method = data[2]; - - self[name] = function() { - return method.apply(instance, arguments); - }; - }); -}; - Node.prototype._initialize = function() { var self = this; - this._initializeDatabase(); this._initializeChain(); this.start(function(err) { @@ -397,18 +343,6 @@ Node.prototype._initialize = function() { }); }; -Node.prototype._initializeDatabase = function() { - var self = this; - this.db.on('ready', function() { - log.info('Bitcoin Database Ready'); - }); - - this.db.on('error', function(err) { - Error.captureStackTrace(err); - self.emit('error', err); - }); -}; - Node.prototype._initializeChain = function() { var self = this; @@ -433,10 +367,6 @@ Node.prototype._initializeChain = function() { Node.prototype.getServices = function() { var services = [ - { - name: 'db', - dependencies: ['bitcoind'], - }, { name: 'chain', dependencies: ['db'] diff --git a/lib/scaffold/default-config.js b/lib/scaffold/default-config.js index 59a5e48e..bb849e77 100644 --- a/lib/scaffold/default-config.js +++ b/lib/scaffold/default-config.js @@ -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: ['bitcoind', 'address'] + modules: ['bitcoind', 'db', 'address'] } }; } diff --git a/test/chain.unit.js b/test/chain.unit.js index 185aaa66..3413c1c5 100644 --- a/test/chain.unit.js +++ b/test/chain.unit.js @@ -46,21 +46,21 @@ describe('Bitcoin Chain', function() { it('should initialize the chain with the genesis block if no metadata is found in the db', function(done) { var db = {}; db.getMetadata = sinon.stub().callsArgWith(0, null, {}); - db.putBlock = sinon.stub().callsArg(1); db.putMetadata = sinon.stub().callsArg(1); db.getTransactionsFromBlock = sinon.stub(); - db._onChainAddBlock = sinon.stub().callsArg(1); + db.connectBlock = sinon.stub().callsArg(1); db.mempool = { on: sinon.spy() }; var node = { - db: db + modules: { + db: db + } }; var chain = new Chain({node: node, genesis: {hash: 'genesis'}}); chain.on('ready', function() { should.exist(chain.tip); - db.putBlock.callCount.should.equal(1); chain.tip.hash.should.equal('genesis'); Number(chain.tip.__weight.toString(10)).should.equal(0); done(); @@ -76,7 +76,6 @@ describe('Bitcoin Chain', function() { it('should initialize the chain with the metadata from the database if it exists', function(done) { var db = {}; db.getMetadata = sinon.stub().callsArgWith(0, null, {tip: 'block2', tipWeight: 2}); - db.putBlock = sinon.stub().callsArg(1); db.putMetadata = sinon.stub().callsArg(1); db.getBlock = sinon.stub().callsArgWith(1, null, {hash: 'block2', prevHash: 'block1'}); db.getTransactionsFromBlock = sinon.stub(); @@ -84,14 +83,15 @@ describe('Bitcoin Chain', function() { on: sinon.spy() }; var node = { - db: db + modules: { + db: db + } }; var chain = new Chain({node: node, genesis: {hash: 'genesis'}}); chain.getHeightForBlock = sinon.stub().callsArgWith(1, null, 10); chain.getWeight = sinon.stub().callsArgWith(1, null, new BN(50)); chain.on('ready', function() { should.exist(chain.tip); - db.putBlock.callCount.should.equal(0); chain.tip.hash.should.equal('block2'); done(); }); @@ -113,7 +113,9 @@ describe('Bitcoin Chain', function() { on: sinon.spy() }; var node = { - db: db + modules: { + db: db + } }; var chain = new Chain({node: node, genesis: {hash: 'genesis'}}); chain.on('error', function(error) { @@ -124,31 +126,6 @@ describe('Bitcoin Chain', function() { chain.initialize(); }); - it('emit error from putBlock', function(done) { - var db = { - getMetadata: function(cb) { - cb(null, null); - }, - putBlock: function(block, cb) { - cb(new Error('putBlockError')); - } - }; - db.getTransactionsFromBlock = sinon.stub(); - db.mempool = { - on: sinon.spy() - }; - var node = { - db: db - }; - var chain = new Chain({node: node, genesis: {hash: 'genesis'}}); - chain.on('error', function(error) { - should.exist(error); - error.message.should.equal('putBlockError'); - done(); - }); - chain.initialize(); - }); - it('emit error from getBlock', function(done) { var db = { getMetadata: function(cb) { @@ -163,7 +140,9 @@ describe('Bitcoin Chain', function() { on: sinon.spy() }; var node = { - db: db + modules: { + db: db + } }; var chain = new Chain({node: node, genesis: {hash: 'genesis'}}); chain.on('error', function(error) { @@ -196,8 +175,8 @@ describe('Bitcoin Chain', function() { var work = '000000000000000000000000000000000000000000005a7b3c42ea8b844374e9'; var chain = new Chain(); chain.node = {}; - chain.node.db = {}; chain.node.modules = {}; + chain.node.modules.db = {}; chain.node.modules.bitcoind = { getBlockIndex: sinon.stub().returns({ chainWork: work @@ -233,7 +212,7 @@ describe('Bitcoin Chain', function() { blocks[block1.hash] = block1; blocks[block2.hash] = block2; - var db = new DB({store: memdown}); + var db = {}; db.getPrevHash = function(blockHash, cb) { // TODO: expose prevHash as a string from bitcore var prevHash = BufferUtil.reverse(blocks[blockHash].header.prevHash).toString('hex'); @@ -241,7 +220,9 @@ describe('Bitcoin Chain', function() { }; var node = { - db: db + modules: { + db: db + } }; var chain = new Chain({ diff --git a/test/modules/address.unit.js b/test/modules/address.unit.js index b8ae8d33..5332afd3 100644 --- a/test/modules/address.unit.js +++ b/test/modules/address.unit.js @@ -6,6 +6,7 @@ var bitcorenode = require('../../'); var AddressModule = bitcorenode.modules.AddressModule; var blockData = require('../data/livenet-345003.json'); var bitcore = require('bitcore'); +var Networks = bitcore.Networks; var EventEmitter = require('events').EventEmitter; var errors = bitcorenode.errors; var levelup = require('levelup'); @@ -71,6 +72,7 @@ describe('AddressModule', function() { var txBuf = new Buffer('01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000', 'hex'); var tx = bitcore.Transaction().fromBuffer(txBuf); var am = new AddressModule({node: mocknode}); + am.node.network = Networks.livenet; var address = '12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX'; var messages = {}; am.transactionOutputHandler(messages, tx, 0, true); @@ -151,7 +153,8 @@ describe('AddressModule', function() { var value64 = data[2].value; before(function() { - am = new AddressModule({node: mocknode, network: 'livenet'}); + am = new AddressModule({node: mocknode}); + am.node.network = Networks.livenet; }); it('should create the correct operations when updating/adding outputs', function(done) { @@ -428,8 +431,8 @@ describe('AddressModule', function() { __height: 1 } }, - db: db, modules: { + db: db, bitcoind: { on: sinon.stub() } @@ -442,7 +445,7 @@ describe('AddressModule', function() { it('should get outputs for an address', function(done) { var readStream1 = new EventEmitter(); - am.node.db.store = { + am.node.modules.db.store = { createReadStream: sinon.stub().returns(readStream1) }; var mempoolOutputs = [ @@ -497,7 +500,7 @@ describe('AddressModule', function() { it('should give an error if the readstream has an error', function(done) { var readStream2 = new EventEmitter(); - am.node.db.store = { + am.node.modules.db.store = { createReadStream: sinon.stub().returns(readStream2) }; @@ -524,8 +527,8 @@ describe('AddressModule', function() { var db = {}; var testnode = { - db: db, modules: { + db: db, bitcoind: { on: sinon.stub() } @@ -554,13 +557,7 @@ describe('AddressModule', function() { 'addr3': ['utxo3'] }; - var db = { - modules: { - bitcoind: { - on: sinon.spy() - } - } - }; + var db = {}; var testnode = { db: db, modules: { @@ -741,8 +738,8 @@ describe('AddressModule', function() { } }; var testnode = { - db: db, modules: { + db: db, bitcoind: { on: sinon.stub() } @@ -861,8 +858,8 @@ describe('AddressModule', function() { __height: 1 } }, - db: db, modules: { + db: db, bitcoind: { on: sinon.stub() } diff --git a/test/db.unit.js b/test/modules/db.unit.js similarity index 70% rename from test/db.unit.js rename to test/modules/db.unit.js index 7d2a5b5b..32bafcbc 100644 --- a/test/db.unit.js +++ b/test/modules/db.unit.js @@ -2,22 +2,113 @@ var should = require('chai').should(); var sinon = require('sinon'); -var index = require('../'); -var DB = index.DB; -var blockData = require('./data/livenet-345003.json'); +var index = require('../../'); +var DB = index.modules.DBModule; +var blockData = require('../data/livenet-345003.json'); var bitcore = require('bitcore'); +var Networks = bitcore.Networks; var Block = bitcore.Block; -var transactionData = require('./data/bitcoin-transactions.json'); +var transactionData = require('../data/bitcoin-transactions.json'); var errors = index.errors; var memdown = require('memdown'); var bitcore = require('bitcore'); var Transaction = bitcore.Transaction; -describe('Bitcoin DB', function() { +describe('DB Module', function() { + + var baseConfig = { + node: { + network: Networks.testnet, + datadir: 'testdir' + }, + store: memdown + }; + + describe('#_setDataPath', function() { + it('should set the database path', function() { + var config = { + node: { + network: Networks.livenet, + datadir: process.env.HOME + '/.bitcoin' + }, + store: memdown + }; + var db = new DB(config); + db.dataPath.should.equal(process.env.HOME + '/.bitcoin/bitcore-node.db'); + }); + it('should load the db for testnet', function() { + var config = { + node: { + network: Networks.testnet, + datadir: process.env.HOME + '/.bitcoin' + }, + store: memdown + }; + var db = new DB(config); + db.dataPath.should.equal(process.env.HOME + '/.bitcoin/testnet3/bitcore-node.db'); + }); + it('error with unknown network', function() { + var config = { + node: { + network: 'unknown', + datadir: process.env.HOME + '/.bitcoin' + }, + store: memdown + }; + (function() { + var db = new DB(config); + }).should.throw('Unknown network'); + }); + it('should load the db with regtest', function() { + // Switch to use regtest + Networks.remove(Networks.testnet); + Networks.add({ + name: 'regtest', + alias: 'regtest', + pubkeyhash: 0x6f, + privatekey: 0xef, + scripthash: 0xc4, + xpubkey: 0x043587cf, + xprivkey: 0x04358394, + networkMagic: 0xfabfb5da, + port: 18444, + dnsSeeds: [ ] + }); + var regtest = Networks.get('regtest'); + var config = { + node: { + network: regtest, + datadir: process.env.HOME + '/.bitcoin' + }, + store: memdown + }; + var db = new DB(config); + db.dataPath.should.equal(process.env.HOME + '/.bitcoin/regtest/bitcore-node.db'); + Networks.remove(regtest); + // Add testnet back + Networks.add({ + name: 'testnet', + alias: 'testnet', + pubkeyhash: 0x6f, + privatekey: 0xef, + scripthash: 0xc4, + xpubkey: 0x043587cf, + xprivkey: 0x04358394, + networkMagic: 0x0b110907, + port: 18333, + dnsSeeds: [ + 'testnet-seed.bitcoin.petertodd.org', + 'testnet-seed.bluematt.me', + 'testnet-seed.alexykot.me', + 'testnet-seed.bitcoin.schildbach.de' + ] + }); + }); + }); describe('#start', function() { it('should emit ready', function(done) { - var db = new DB({store: memdown}); + var db = new DB(baseConfig); db.node = {}; db.node.modules = {}; db.node.modules.bitcoind = { @@ -37,7 +128,7 @@ describe('Bitcoin DB', function() { describe('#stop', function() { it('should immediately call the callback', function(done) { - var db = new DB({store: memdown}); + var db = new DB(baseConfig); db.stop(function(err) { should.not.exist(err); @@ -48,7 +139,7 @@ describe('Bitcoin DB', function() { describe('#getTransaction', function() { it('will return a NotFound error', function(done) { - var db = new DB({store: memdown}); + var db = new DB(baseConfig); db.node = {}; db.node.modules = {}; db.node.modules.bitcoind = { @@ -61,7 +152,7 @@ describe('Bitcoin DB', function() { }); }); it('will return an error from bitcoind', function(done) { - var db = new DB({store: memdown}); + var db = new DB(baseConfig); db.node = {}; db.node.modules = {}; db.node.modules.bitcoind = { @@ -74,7 +165,7 @@ describe('Bitcoin DB', function() { }); }); it('will return an error from bitcoind', function(done) { - var db = new DB({store: memdown}); + var db = new DB(baseConfig); db.node = {}; db.node.modules = {}; db.node.modules.bitcoind = { @@ -92,7 +183,7 @@ describe('Bitcoin DB', function() { }); describe('#getBlock', function() { - var db = new DB({store: memdown}); + var db = new DB(baseConfig); var blockBuffer = new Buffer(blockData, 'hex'); var expectedBlock = Block.fromBuffer(blockBuffer); db.node = {}; @@ -121,19 +212,9 @@ describe('Bitcoin DB', function() { }); }); - describe('#putBlock', function() { - it('should call callback', function(done) { - var db = new DB({store: memdown}); - db.putBlock('block', function(err) { - should.not.exist(err); - done(); - }); - }); - }); - describe('#getPrevHash', function() { it('should return prevHash from bitcoind', function(done) { - var db = new DB({store: memdown}); + var db = new DB(baseConfig); db.node = {}; db.node.modules = {}; db.node.modules.bitcoind = { @@ -150,7 +231,7 @@ describe('Bitcoin DB', function() { }); it('should give an error if bitcoind could not find it', function(done) { - var db = new DB({store: memdown}); + var db = new DB(baseConfig); db.node = {}; db.node.modules = {}; db.node.modules.bitcoind = { @@ -173,7 +254,7 @@ describe('Bitcoin DB', function() { buffer: txBuffer }; - var db = new DB({store: memdown}); + var db = new DB(baseConfig); db.node = {}; db.node.modules = {}; db.node.modules.bitcoind = { @@ -188,7 +269,7 @@ describe('Bitcoin DB', function() { }); }); it('should give an error if one occurred', function(done) { - var db = new DB({store: memdown}); + var db = new DB(baseConfig); db.node = {}; db.node.modules = {}; db.node.modules.bitcoind = { @@ -204,7 +285,7 @@ describe('Bitcoin DB', function() { describe('#sendTransaction', function() { it('should give the txid on success', function(done) { - var db = new DB({store: memdown}); + var db = new DB(baseConfig); db.node = {}; db.node.modules = {}; db.node.modules.bitcoind = { @@ -219,7 +300,7 @@ describe('Bitcoin DB', function() { }); }); it('should give an error if bitcoind threw an error', function(done) { - var db = new DB({store: memdown}); + var db = new DB(baseConfig); db.node = {}; db.node.modules = {}; db.node.modules.bitcoind = { @@ -236,7 +317,7 @@ describe('Bitcoin DB', function() { describe("#estimateFee", function() { it('should pass along the fee from bitcoind', function(done) { - var db = new DB({store: memdown}); + var db = new DB(baseConfig); db.node = {}; db.node.modules = {}; db.node.modules.bitcoind = { @@ -252,95 +333,35 @@ describe('Bitcoin DB', function() { }); }); - describe('#getOutputTotal', function() { - it('should return the correct value including the coinbase', function() { - var totals = [10, 20, 30]; - var db = new DB({path: 'path', store: memdown}); - var transactions = totals.map(function(total) { - return { - _getOutputAmount: function() { - return total; - }, - isCoinbase: function() { - return total === 10 ? true : false; - } - }; - }); - var grandTotal = db.getOutputTotal(transactions); - grandTotal.should.equal(60); - }); - it('should return the correct value excluding the coinbase', function() { - var totals = [10, 20, 30]; - var db = new DB({path: 'path', store: memdown}); - var transactions = totals.map(function(total) { - return { - _getOutputAmount: function() { - return total; - }, - isCoinbase: function() { - return total === 10 ? true : false; - } - }; - }); - var grandTotal = db.getOutputTotal(transactions, true); - grandTotal.should.equal(50); - }); - }); - - describe('#getInputTotal', function() { - it('should return the correct value', function() { - var totals = [10, 20, 30]; - var db = new DB({path: 'path', store: memdown}); - var transactions = totals.map(function(total) { - return { - _getInputAmount: function() { - return total; - }, - isCoinbase: sinon.stub().returns(false) - }; - }); - var grandTotal = db.getInputTotal(transactions); - grandTotal.should.equal(60); - }); - it('should return 0 if the tx is a coinbase', function() { - var db = new DB({store: memdown}); - var tx = { - isCoinbase: sinon.stub().returns(true) - }; - var total = db.getInputTotal([tx]); - total.should.equal(0); - }); - }); - - describe('#_onChainAddBlock', function() { + describe('#connectBlock', function() { it('should remove block from mempool and call blockHandler with true', function(done) { - var db = new DB({store: memdown}); + var db = new DB(baseConfig); db.mempool = { removeBlock: sinon.stub() }; - db.blockHandler = sinon.stub().callsArg(2); - db._onChainAddBlock({hash: 'hash'}, function(err) { + db.runAllBlockHandlers = sinon.stub().callsArg(2); + db.connectBlock({hash: 'hash'}, function(err) { should.not.exist(err); - db.blockHandler.args[0][1].should.equal(true); + db.runAllBlockHandlers.args[0][1].should.equal(true); done(); }); }); }); - describe('#_onChainRemoveBlock', function() { + describe('#disconnectBlock', function() { it('should call blockHandler with false', function(done) { - var db = new DB({store: memdown}); - db.blockHandler = sinon.stub().callsArg(2); - db._onChainRemoveBlock({hash: 'hash'}, function(err) { + var db = new DB(baseConfig); + db.runAllBlockHandlers = sinon.stub().callsArg(2); + db.disconnectBlock({hash: 'hash'}, function(err) { should.not.exist(err); - db.blockHandler.args[0][1].should.equal(false); + db.runAllBlockHandlers.args[0][1].should.equal(false); done(); }); }); }); - describe('#blockHandler', function() { - var db = new DB({store: memdown}); + describe('#runAllBlockHandlers', function() { + var db = new DB(baseConfig); var Module1 = function() {}; Module1.prototype.blockHandler = sinon.stub().callsArgWith(2, null, ['op1', 'op2', 'op3']); var Module2 = function() {}; @@ -355,7 +376,7 @@ describe('Bitcoin DB', function() { }; it('should call blockHandler in all modules and perform operations', function(done) { - db.blockHandler('block', true, function(err) { + db.runAllBlockHandlers('block', true, function(err) { should.not.exist(err); db.store.batch.args[0][0].should.deep.equal(['op1', 'op2', 'op3', 'op4', 'op5']); done(); @@ -367,7 +388,7 @@ describe('Bitcoin DB', function() { Module3.prototype.blockHandler = sinon.stub().callsArgWith(2, new Error('error')); db.node.modules.module3 = new Module3(); - db.blockHandler('block', true, function(err) { + db.runAllBlockHandlers('block', true, function(err) { should.exist(err); done(); }); @@ -376,12 +397,11 @@ describe('Bitcoin DB', function() { describe('#getAPIMethods', function() { it('should return the correct db methods', function() { - var db = new DB({store: memdown}); + var db = new DB(baseConfig); db.node = {}; db.node.modules = {}; var methods = db.getAPIMethods(); methods.length.should.equal(5); }); }); - }); diff --git a/test/node.unit.js b/test/node.unit.js index 78672ae6..59313f80 100644 --- a/test/node.unit.js +++ b/test/node.unit.js @@ -101,6 +101,9 @@ describe('Bitcore Node', function() { it('should return db methods and modules methods', function() { var node = new Node(baseConfig); node.modules = { + db: { + getAPIMethods: sinon.stub().returns(['db1', 'db2']), + }, module1: { getAPIMethods: sinon.stub().returns(['mda1', 'mda2']) }, @@ -108,10 +111,6 @@ describe('Bitcore Node', function() { getAPIMethods: sinon.stub().returns(['mdb1', 'mdb2']) } }; - var db = { - getAPIMethods: sinon.stub().returns(['db1', 'db2']), - }; - node.db = db; var methods = node.getAllAPIMethods(); methods.should.deep.equal(['db1', 'db2', 'mda1', 'mda2', 'mdb1', 'mdb2']); @@ -121,6 +120,9 @@ describe('Bitcore Node', function() { it('should return modules publish events', function() { var node = new Node(baseConfig); node.modules = { + db: { + getPublishEvents: sinon.stub().returns(['db1', 'db2']), + }, module1: { getPublishEvents: sinon.stub().returns(['mda1', 'mda2']) }, @@ -128,11 +130,6 @@ describe('Bitcore Node', function() { getPublishEvents: sinon.stub().returns(['mdb1', 'mdb2']) } }; - var db = { - getPublishEvents: sinon.stub().returns(['db1', 'db2']), - }; - node.db = db; - var events = node.getAllPublishEvents(); events.should.deep.equal(['db1', 'db2', 'mda1', 'mda2', 'mdb1', 'mdb2']); }); @@ -141,12 +138,8 @@ describe('Bitcore Node', function() { it('should call the necessary methods', function() { var TestNode = proxyquire('../lib/node', {}); TestNode.prototype._initialize = sinon.spy(); - TestNode.prototype._loadDB = sinon.spy(); - TestNode.prototype._loadAPI = sinon.spy(); TestNode.prototype._loadConsensus = sinon.spy(); var node = new TestNode(baseConfig); - node._loadDB.callCount.should.equal(1); - node._loadAPI.callCount.should.equal(1); node._loadConsensus.callCount.should.equal(1); }); }); @@ -243,8 +236,9 @@ describe('Bitcore Node', function() { } }); }; - node.db = { - _onChainRemoveBlock: function(block, callback) { + node.modules = {}; + node.modules.db = { + disconnectBlock: function(block, callback) { setImmediate(callback); } }; @@ -286,8 +280,8 @@ describe('Bitcore Node', function() { hashes: {} } }; - node.db = { - _onChainAddBlock: function(block, callback) { + node.modules.db = { + connectBlock: function(block, callback) { node.chain.tip.__height += 1; callback(); } @@ -336,8 +330,8 @@ describe('Bitcore Node', function() { hashes: {} } }; - node.db = { - _onChainAddBlock: function(block, callback) { + node.modules.db = { + connectBlock: function(block, callback) { node.chain.tip.__height += 1; callback(); } @@ -387,119 +381,21 @@ describe('Bitcore Node', function() { node.network.name.should.equal('livenet'); }); }); - describe('#_loadDB', function() { - it('should load the db', function() { - var DB = function(config) { - config.path.should.equal(process.env.HOME + '/.bitcoin/bitcore-node.db'); - }; - var config = { - DB: DB, - datadir: process.env.HOME + '/.bitcoin' - }; - - var node = new Node(config); - node.network = Networks.livenet; - node._loadDB(config); - node.db.should.be.instanceof(DB); - }); - it('should load the db for testnet', function() { - var DB = function(config) { - config.path.should.equal(process.env.HOME + '/.bitcoin/testnet3/bitcore-node.db'); - }; - var config = { - DB: DB, - datadir: process.env.HOME + '/.bitcoin' - }; - - var node = new Node(config); - node.network = Networks.testnet; - node._loadDB(config); - node.db.should.be.instanceof(DB); - }); - it('error with unknown network', function() { - var config = { - datadir: process.env.HOME + '/.bitcoin' - }; - - var node = new Node(config); - node.network = 'not a network'; - (function() { - node._loadDB(config); - }).should.throw('Unknown network'); - }); - it('should load the db with regtest', function() { - var DB = function(config) { - config.path.should.equal(process.env.HOME + '/.bitcoin/regtest/bitcore-node.db'); - }; - var config = { - DB: DB, - datadir: process.env.HOME + '/.bitcoin' - }; - - var node = new Node(config); - // Switch to use regtest - Networks.remove(Networks.testnet); - Networks.add({ - name: 'regtest', - alias: 'regtest', - pubkeyhash: 0x6f, - privatekey: 0xef, - scripthash: 0xc4, - xpubkey: 0x043587cf, - xprivkey: 0x04358394, - networkMagic: 0xfabfb5da, - port: 18444, - dnsSeeds: [ ] - }); - var regtest = Networks.get('regtest'); - node.network = regtest; - node._loadDB(config); - node.db.should.be.instanceof(DB); - Networks.remove(regtest); - // Add testnet back - Networks.add({ - name: 'testnet', - alias: 'testnet', - pubkeyhash: 0x6f, - privatekey: 0xef, - scripthash: 0xc4, - xpubkey: 0x043587cf, - xprivkey: 0x04358394, - networkMagic: 0x0b110907, - port: 18333, - dnsSeeds: [ - 'testnet-seed.bitcoin.petertodd.org', - 'testnet-seed.bluematt.me', - 'testnet-seed.alexykot.me', - 'testnet-seed.bitcoin.schildbach.de' - ] - }); - }); - }); describe('#_loadConsensus', function() { - var node; - before(function() { node = new Node(baseConfig); }); - it('will set properties', function() { node._loadConsensus(); should.exist(node.chain); }); - }); - describe('#_initialize', function() { - var node; - before(function() { var TestNode = proxyquire('../lib/node', {}); TestNode.prototype._loadConfiguration = sinon.spy(); - TestNode.prototype._initializeBitcoind = sinon.spy(); - TestNode.prototype._initializeDatabase = sinon.spy(); TestNode.prototype._initializeChain = sinon.spy(); // mock the _initialize during construction @@ -510,14 +406,13 @@ describe('Bitcore Node', function() { node.chain = { on: sinon.spy() }; - node.Block = 'Block'; - node.bitcoind = { + node.modules = {}; + node.modules.bitcoind = { on: sinon.spy() }; - node.db = { + node.modules.db = { on: sinon.spy() }; - // restore the original method node._initialize = _initialize; }); @@ -526,15 +421,9 @@ describe('Bitcore Node', function() { node.once('ready', function() { done(); }); - node.start = sinon.stub().callsArg(0); - node._initialize(); - - // event handlers - node._initializeDatabase.callCount.should.equal(1); node._initializeChain.callCount.should.equal(1); - }); it('should emit an error if an error occurred starting services', function(done) { @@ -549,34 +438,6 @@ describe('Bitcore Node', function() { }); - describe('#_initializeDatabase', function() { - it('will log on ready event', function(done) { - var node = new Node(baseConfig); - node.db = new EventEmitter(); - sinon.stub(index.log, 'info'); - node.db.on('ready', function() { - setImmediate(function() { - index.log.info.callCount.should.equal(1); - index.log.info.restore(); - done(); - }); - }); - node._initializeDatabase(); - node.db.emit('ready'); - }); - it('will call emit an error from db', function(done) { - var node = new Node(baseConfig); - node.db = new EventEmitter(); - node.on('error', function(err) { - should.exist(err); - err.message.should.equal('test error'); - done(); - }); - node._initializeDatabase(); - node.db.emit('error', new Error('test error')); - }); - }); - describe('#_initializeChain', function() { it('will call sync when there is a new tip', function(done) { diff --git a/test/transaction.unit.js b/test/transaction.unit.js index 62bf9449..eee529a4 100644 --- a/test/transaction.unit.js +++ b/test/transaction.unit.js @@ -4,10 +4,6 @@ var should = require('chai').should(); var sinon = require('sinon'); var bitcoinlib = require('../'); var Transaction = bitcoinlib.Transaction; -var transactionData = require('./data/bitcoin-transactions.json'); -var memdown = require('memdown'); -var DB = bitcoinlib.DB; -var db = new DB({store: memdown}); var levelup = require('levelup'); describe('Bitcoin Transaction', function() {