Use node as a reference in modules, db and chain.

This commit is contained in:
Braydon Fuller 2015-08-27 13:02:01 -04:00
parent ccab818d33
commit 5361183a19
11 changed files with 180 additions and 119 deletions

View File

@ -353,7 +353,7 @@ MyModule.prototype.subscribeCustom = function(emitter, param) {
MyModule.prototype.getData = function(arg1, callback) { MyModule.prototype.getData = function(arg1, callback) {
// You can query the data by reading from the leveldb store on db // You can query the data by reading from the leveldb store on db
this.db.store.get(arg1, callback); this.node.db.store.get(arg1, callback);
}; };
module.exports = MyModule; module.exports = MyModule;

View File

@ -101,7 +101,7 @@ describe('Node Functionality', function() {
after(function(done) { after(function(done) {
this.timeout(20000); this.timeout(20000);
node.db.bitcoind.stop(function(err, result) { node.bitcoind.stop(function(err, result) {
done(); done();
}); });
}); });

View File

@ -34,9 +34,6 @@ function Chain(opts) {
opts = {}; opts = {};
} }
this.db = opts.db;
this.p2p = opts.p2p;
this.genesis = opts.genesis; this.genesis = opts.genesis;
this.genesisOptions = opts.genesisOptions; this.genesisOptions = opts.genesisOptions;
this.genesisWeight = new BN(0); this.genesisWeight = new BN(0);
@ -102,18 +99,18 @@ Chain.prototype.initialize = function() {
var self = this; var self = this;
// Does our database already have a tip? // Does our database already have a tip?
self.db.getMetadata(function getMetadataCallback(err, metadata) { self.node.db.getMetadata(function getMetadataCallback(err, metadata) {
if(err) { if(err) {
return self.emit('error', err); return self.emit('error', err);
} else if(!metadata || !metadata.tip) { } else if(!metadata || !metadata.tip) {
self.tip = self.genesis; self.tip = self.genesis;
self.tip.__height = 0; self.tip.__height = 0;
self.tip.__weight = self.genesisWeight; self.tip.__weight = self.genesisWeight;
self.db.putBlock(self.genesis, function putBlockCallback(err) { self.node.db.putBlock(self.genesis, function putBlockCallback(err) {
if(err) { if(err) {
return self.emit('error', err); return self.emit('error', err);
} }
self.db._onChainAddBlock(self.genesis, function(err) { self.node.db._onChainAddBlock(self.genesis, function(err) {
if(err) { if(err) {
return self.emit('error', err); return self.emit('error', err);
} }
@ -125,7 +122,7 @@ Chain.prototype.initialize = function() {
}); });
} else { } else {
metadata.tip = metadata.tip; metadata.tip = metadata.tip;
self.db.getBlock(metadata.tip, function getBlockCallback(err, tip) { self.node.db.getBlock(metadata.tip, function getBlockCallback(err, tip) {
if(err) { if(err) {
return self.emit('error', err); return self.emit('error', err);
} }
@ -155,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.db.bitcoind.getBlockIndex(blockHash); var blockIndex = self.node.bitcoind.getBlockIndex(blockHash);
setImmediate(function() { setImmediate(function() {
if (blockIndex) { if (blockIndex) {
@ -218,7 +215,7 @@ Chain.prototype.getHashes = function getHashes(tipHash, callback) {
} }
} else { } else {
// do a db call if we don't have it // do a db call if we don't have it
self.db.getPrevHash(hash, function(err, prevHash) { self.node.db.getPrevHash(hash, function(err, prevHash) {
if(err) { if(err) {
return callback(err); return callback(err);
} }
@ -249,7 +246,7 @@ Chain.prototype.saveMetadata = function saveMetadata(callback) {
self.lastSavedMetadata = new Date(); self.lastSavedMetadata = new Date();
self.db.putMetadata(metadata, callback); self.node.db.putMetadata(metadata, callback);
}; };
module.exports = Chain; module.exports = Chain;

View File

@ -8,8 +8,6 @@ var leveldown = require('leveldown');
var bitcore = require('bitcore'); var bitcore = require('bitcore');
var Block = bitcore.Block; var Block = bitcore.Block;
var $ = bitcore.util.preconditions; var $ = bitcore.util.preconditions;
var BufferReader = bitcore.encoding.BufferReader;
var BufferWriter = bitcore.encoding.BufferWriter;
var index = require('./'); var index = require('./');
var errors = index.errors; var errors = index.errors;
var log = index.log; var log = index.log;
@ -39,7 +37,6 @@ function DB(options) {
} }
this.store = levelup(options.path, { db: levelupStore }); this.store = levelup(options.path, { db: levelupStore });
this.chain = options.chain;
this.txPrefix = options.txPrefix || DB.PREFIXES.TX; this.txPrefix = options.txPrefix || DB.PREFIXES.TX;
this.prevHashPrefix = options.prevHashPrefix || DB.PREFIXES.PREV_HASH; this.prevHashPrefix = options.prevHashPrefix || DB.PREFIXES.PREV_HASH;
this.blockPrefix = options.blockPrefix || DB.PREFIXES.BLOCK; this.blockPrefix = options.blockPrefix || DB.PREFIXES.BLOCK;
@ -88,7 +85,7 @@ DB.prototype.start = function(callback) {
this.addModule(this._modules[i]); this.addModule(this._modules[i]);
} }
} }
this.bitcoind.on('tx', this.transactionHandler.bind(this)); this.node.bitcoind.on('tx', this.transactionHandler.bind(this));
this.emit('ready'); this.emit('ready');
setImmediate(callback); setImmediate(callback);
}; };
@ -102,7 +99,7 @@ DB.prototype.getBlock = function(hash, callback) {
var self = this; var self = this;
// get block from bitcoind // get block from bitcoind
this.bitcoind.getBlock(hash, function(err, blockData) { this.node.bitcoind.getBlock(hash, function(err, blockData) {
if(err) { if(err) {
return callback(err); return callback(err);
} }
@ -111,7 +108,7 @@ DB.prototype.getBlock = function(hash, callback) {
}; };
DB.prototype.getPrevHash = function(blockHash, callback) { DB.prototype.getPrevHash = function(blockHash, callback) {
var blockIndex = this.bitcoind.getBlockIndex(blockHash); var blockIndex = this.node.bitcoind.getBlockIndex(blockHash);
setImmediate(function() { setImmediate(function() {
if (blockIndex) { if (blockIndex) {
callback(null, blockIndex.prevHash); callback(null, blockIndex.prevHash);
@ -127,7 +124,7 @@ DB.prototype.putBlock = function(block, callback) {
}; };
DB.prototype.getTransaction = function(txid, queryMempool, callback) { DB.prototype.getTransaction = function(txid, queryMempool, callback) {
this.bitcoind.getTransaction(txid, queryMempool, function(err, txBuffer) { this.node.bitcoind.getTransaction(txid, queryMempool, function(err, txBuffer) {
if(err) { if(err) {
return callback(err); return callback(err);
} }
@ -140,7 +137,7 @@ DB.prototype.getTransaction = function(txid, queryMempool, callback) {
}; };
DB.prototype.getTransactionWithBlockInfo = function(txid, queryMempool, callback) { DB.prototype.getTransactionWithBlockInfo = function(txid, queryMempool, callback) {
this.bitcoind.getTransactionWithBlockInfo(txid, queryMempool, function(err, obj) { this.node.bitcoind.getTransactionWithBlockInfo(txid, queryMempool, function(err, obj) {
if(err) { if(err) {
return callback(err); return callback(err);
} }
@ -160,7 +157,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.bitcoind.sendTransaction(tx); var txid = this.node.bitcoind.sendTransaction(tx);
return callback(null, txid); return callback(null, txid);
} catch(err) { } catch(err) {
return callback(err); return callback(err);
@ -171,7 +168,7 @@ DB.prototype.estimateFee = function(blocks, callback) {
var self = this; var self = this;
setImmediate(function() { setImmediate(function() {
callback(null, self.bitcoind.estimateFee(blocks)); callback(null, self.node.bitcoind.estimateFee(blocks));
}); });
}; };
@ -338,7 +335,7 @@ DB.prototype.getPublishEvents = function() {
DB.prototype.addModule = function(Module) { DB.prototype.addModule = function(Module) {
var module = new Module({ var module = new Module({
db: this node: this.node
}); });
$.checkArgumentType(module, BaseModule); $.checkArgumentType(module, BaseModule);
this.modules.push(module); this.modules.push(module);

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var Module = function(options) { var Module = function(options) {
this.db = options.db; this.node = options.node;
}; };
/** /**

View File

@ -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.db.bitcoind.on('tx', this.transactionHandler.bind(this)); this.node.bitcoind.on('tx', this.transactionHandler.bind(this));
}; };
@ -77,10 +77,10 @@ AddressModule.prototype.transactionOutputHandler = function(messages, tx, output
} }
// Find the address for the output // Find the address for the output
var address = script.toAddress(this.db.network); var address = script.toAddress(this.node.db.network);
if (!address && script.isPublicKeyOut()) { if (!address && script.isPublicKeyOut()) {
var pubkey = script.chunks[0].buf; var pubkey = script.chunks[0].buf;
address = Address.fromPublicKey(new PublicKey(pubkey), this.db.network); address = Address.fromPublicKey(new PublicKey(pubkey), this.node.db.network);
} else if (!address){ } else if (!address){
return; return;
} }
@ -157,10 +157,10 @@ AddressModule.prototype.blockHandler = function(block, addOutput, callback) {
continue; continue;
} }
var address = script.toAddress(this.db.network); var address = script.toAddress(this.node.db.network);
if (!address && script.isPublicKeyOut()) { if (!address && script.isPublicKeyOut()) {
var pubkey = script.chunks[0].buf; var pubkey = script.chunks[0].buf;
address = Address.fromPublicKey(new PublicKey(pubkey), this.db.network); address = Address.fromPublicKey(new PublicKey(pubkey), this.node.db.network);
} else if (!address){ } else if (!address){
continue; continue;
} }
@ -324,7 +324,7 @@ AddressModule.prototype.getOutputs = function(addressStr, queryMempool, callback
var outputs = []; var outputs = [];
var key = [AddressModule.PREFIXES.OUTPUTS, addressStr].join('-'); var key = [AddressModule.PREFIXES.OUTPUTS, addressStr].join('-');
var stream = this.db.store.createReadStream({ var stream = this.node.db.store.createReadStream({
start: key, start: key,
end: key + '~' end: key + '~'
}); });
@ -342,7 +342,7 @@ AddressModule.prototype.getOutputs = function(addressStr, queryMempool, callback
satoshis: Number(value[0]), satoshis: Number(value[0]),
script: value[1], script: value[1],
blockHeight: Number(value[2]), blockHeight: Number(value[2]),
confirmations: self.db.chain.tip.__height - Number(value[2]) + 1 confirmations: self.node.chain.tip.__height - Number(value[2]) + 1
}; };
outputs.push(output); outputs.push(output);
@ -363,7 +363,7 @@ AddressModule.prototype.getOutputs = function(addressStr, queryMempool, callback
} }
if(queryMempool) { if(queryMempool) {
outputs = outputs.concat(self.db.bitcoind.getMempoolOutputs(addressStr)); outputs = outputs.concat(self.node.bitcoind.getMempoolOutputs(addressStr));
} }
callback(null, outputs); callback(null, outputs);
@ -430,7 +430,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.db.bitcoind.isSpent(txid, output.outputIndex)); callback(self.node.bitcoind.isSpent(txid, output.outputIndex));
}); });
}; };
@ -438,7 +438,7 @@ AddressModule.prototype.getSpendInfoForOutput = function(txid, outputIndex, call
var self = this; var self = this;
var key = [AddressModule.PREFIXES.SPENTS, txid, outputIndex].join('-'); var key = [AddressModule.PREFIXES.SPENTS, txid, outputIndex].join('-');
this.db.store.get(key, function(err, value) { this.node.db.store.get(key, function(err, value) {
if(err) { if(err) {
return callback(err); return callback(err);
} }
@ -487,19 +487,19 @@ AddressModule.prototype.getAddressHistoryForAddress = function(address, queryMem
return callback(null, txinfos[txid]); return callback(null, txinfos[txid]);
} }
self.db.getTransactionWithBlockInfo(txid, queryMempool, function(err, transaction) { self.node.db.getTransactionWithBlockInfo(txid, queryMempool, function(err, transaction) {
if(err) { if(err) {
return callback(err); return callback(err);
} }
transaction.populateInputs(self.db, [], function(err) { transaction.populateInputs(self.node.db, [], function(err) {
if(err) { if(err) {
return callback(err); return callback(err);
} }
var confirmations = 0; var confirmations = 0;
if(transaction.__height >= 0) { if(transaction.__height >= 0) {
confirmations = self.db.chain.tip.__height - transaction.__height; confirmations = self.node.chain.tip.__height - transaction.__height;
} }
txinfos[transaction.hash] = { txinfos[transaction.hash] = {

View File

@ -25,7 +25,6 @@ function Node(config) {
this.db = null; this.db = null;
this.chain = null; this.chain = null;
this.p2p = null;
this.network = null; this.network = null;
this._loadConfiguration(config); this._loadConfiguration(config);
@ -396,13 +395,6 @@ Node.prototype._loadAPI = function() {
Node.prototype._initialize = function() { Node.prototype._initialize = function() {
var self = this; var self = this;
// DB References
this.db.chain = this.chain;
this.db.bitcoind = this.bitcoind;
// Chain References
this.chain.db = this.db;
this._initializeBitcoind(); this._initializeBitcoind();
this._initializeDatabase(); this._initializeDatabase();
this._initializeChain(); this._initializeChain();

View File

@ -52,7 +52,10 @@ describe('Bitcoin Chain', function() {
db.mempool = { db.mempool = {
on: sinon.spy() on: sinon.spy()
}; };
var chain = new Chain({db: db, genesis: {hash: 'genesis'}}); var node = {
db: db
};
var chain = new Chain({node: node, genesis: {hash: 'genesis'}});
chain.on('ready', function() { chain.on('ready', function() {
should.exist(chain.tip); should.exist(chain.tip);
@ -79,7 +82,10 @@ describe('Bitcoin Chain', function() {
db.mempool = { db.mempool = {
on: sinon.spy() on: sinon.spy()
}; };
var chain = new Chain({db: db, genesis: {hash: 'genesis'}}); var node = {
db: db
};
var chain = new Chain({node: node, genesis: {hash: 'genesis'}});
chain.getHeightForBlock = sinon.stub().callsArgWith(1, null, 10); chain.getHeightForBlock = sinon.stub().callsArgWith(1, null, 10);
chain.getWeight = sinon.stub().callsArgWith(1, null, new BN(50)); chain.getWeight = sinon.stub().callsArgWith(1, null, new BN(50));
chain.on('ready', function() { chain.on('ready', function() {
@ -105,7 +111,10 @@ describe('Bitcoin Chain', function() {
db.mempool = { db.mempool = {
on: sinon.spy() on: sinon.spy()
}; };
var chain = new Chain({db: db, genesis: {hash: 'genesis'}}); var node = {
db: db
};
var chain = new Chain({node: node, genesis: {hash: 'genesis'}});
chain.on('error', function(error) { chain.on('error', function(error) {
should.exist(error); should.exist(error);
error.message.should.equal('getMetadataError'); error.message.should.equal('getMetadataError');
@ -127,7 +136,10 @@ describe('Bitcoin Chain', function() {
db.mempool = { db.mempool = {
on: sinon.spy() on: sinon.spy()
}; };
var chain = new Chain({db: db, genesis: {hash: 'genesis'}}); var node = {
db: db
};
var chain = new Chain({node: node, genesis: {hash: 'genesis'}});
chain.on('error', function(error) { chain.on('error', function(error) {
should.exist(error); should.exist(error);
error.message.should.equal('putBlockError'); error.message.should.equal('putBlockError');
@ -149,7 +161,10 @@ describe('Bitcoin Chain', function() {
db.mempool = { db.mempool = {
on: sinon.spy() on: sinon.spy()
}; };
var chain = new Chain({db: db, genesis: {hash: 'genesis'}}); var node = {
db: db
};
var chain = new Chain({node: node, genesis: {hash: 'genesis'}});
chain.on('error', function(error) { chain.on('error', function(error) {
should.exist(error); should.exist(error);
error.message.should.equal('getBlockError'); error.message.should.equal('getBlockError');
@ -179,12 +194,12 @@ describe('Bitcoin Chain', function() {
describe('#getWeight', function() { describe('#getWeight', function() {
var work = '000000000000000000000000000000000000000000005a7b3c42ea8b844374e9'; var work = '000000000000000000000000000000000000000000005a7b3c42ea8b844374e9';
var chain = new Chain(); var chain = new Chain();
chain.db = { chain.node = {};
bitcoind: { chain.node.db = {};
chain.node.bitcoind = {
getBlockIndex: sinon.stub().returns({ getBlockIndex: sinon.stub().returns({
chainWork: work chainWork: work
}) })
}
}; };
it('should give the weight as a BN', function(done) { it('should give the weight as a BN', function(done) {
@ -196,7 +211,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.db.bitcoind.getBlockIndex = sinon.stub().returns(undefined); chain.node.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();
@ -223,8 +238,12 @@ describe('Bitcoin Chain', function() {
cb(null, prevHash); cb(null, prevHash);
}; };
var node = {
db: db
};
var chain = new Chain({ var chain = new Chain({
db: db, node: node,
genesis: genesisBlock genesis: genesisBlock
}); });

View File

@ -22,7 +22,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._modules = ['mod1', 'mod2']; db._modules = ['mod1', 'mod2'];
db.bitcoind = { db.node = {};
db.node.bitcoind = {
on: sinon.spy() on: sinon.spy()
}; };
db.addModule = sinon.spy(); db.addModule = sinon.spy();
@ -51,7 +52,8 @@ describe('Bitcoin DB', function() {
describe('#getTransaction', function() { describe('#getTransaction', 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.bitcoind = { db.node = {};
db.node.bitcoind = {
getTransaction: sinon.stub().callsArgWith(2, null, null) getTransaction: sinon.stub().callsArgWith(2, null, null)
}; };
var txid = '7426c707d0e9705bdd8158e60983e37d0f5d63529086d6672b07d9238d5aa623'; var txid = '7426c707d0e9705bdd8158e60983e37d0f5d63529086d6672b07d9238d5aa623';
@ -62,7 +64,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.bitcoind = { db.node = {};
db.node.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';
@ -73,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.bitcoind = { db.node = {};
db.node.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';
@ -91,7 +95,8 @@ describe('Bitcoin DB', function() {
var db = new DB({store: memdown}); var db = new DB({store: memdown});
var blockBuffer = new Buffer(blockData, 'hex'); var blockBuffer = new Buffer(blockData, 'hex');
var expectedBlock = Block.fromBuffer(blockBuffer); var expectedBlock = Block.fromBuffer(blockBuffer);
db.bitcoind = { db.node = {};
db.node.bitcoind = {
getBlock: sinon.stub().callsArgWith(1, null, blockBuffer) getBlock: sinon.stub().callsArgWith(1, null, blockBuffer)
}; };
@ -103,7 +108,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.bitcoind.getBlock = sinon.stub().callsArgWith(1, new Error('error')); db.node = {};
db.node.bitcoind = {};
db.node.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');
@ -125,7 +132,8 @@ describe('Bitcoin DB', function() {
describe('#getPrevHash', function() { describe('#getPrevHash', 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.bitcoind = { db.node = {};
db.node.bitcoind = {
getBlockIndex: sinon.stub().returns({ getBlockIndex: sinon.stub().returns({
prevHash: 'prevhash' prevHash: 'prevhash'
}) })
@ -140,7 +148,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.bitcoind = { db.node = {};
db.node.bitcoind = {
getBlockIndex: sinon.stub().returns(null) getBlockIndex: sinon.stub().returns(null)
}; };
@ -161,7 +170,8 @@ describe('Bitcoin DB', function() {
}; };
var db = new DB({store: memdown}); var db = new DB({store: memdown});
db.bitcoind = { db.node = {};
db.node.bitcoind = {
getTransactionWithBlockInfo: sinon.stub().callsArgWith(2, null, info) getTransactionWithBlockInfo: sinon.stub().callsArgWith(2, null, info)
}; };
@ -174,7 +184,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.bitcoind = { db.node = {};
db.node.bitcoind = {
getTransactionWithBlockInfo: sinon.stub().callsArgWith(2, new Error('error')) getTransactionWithBlockInfo: sinon.stub().callsArgWith(2, new Error('error'))
}; };
@ -188,7 +199,8 @@ describe('Bitcoin DB', function() {
describe('#sendTransaction', function() { describe('#sendTransaction', 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.bitcoind = { db.node = {};
db.node.bitcoind = {
sendTransaction: sinon.stub().returns('txid') sendTransaction: sinon.stub().returns('txid')
}; };
@ -201,7 +213,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.bitcoind = { db.node = {};
db.node.bitcoind = {
sendTransaction: sinon.stub().throws(new Error('error')) sendTransaction: sinon.stub().throws(new Error('error'))
}; };
@ -216,14 +229,15 @@ describe('Bitcoin DB', function() {
describe("#estimateFee", function() { describe("#estimateFee", 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.bitcoind = { db.node = {};
db.node.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.bitcoind.estimateFee.args[0][0].should.equal(5); db.node.bitcoind.estimateFee.args[0][0].should.equal(5);
done(); done();
}); });
}); });
@ -391,11 +405,14 @@ describe('Bitcoin DB', function() {
inherits(Module1, BaseModule); inherits(Module1, BaseModule);
var db = new DB({store: memdown}); var db = new DB({store: memdown});
var node = {};
db.node = node;
db.modules = []; db.modules = [];
db.addModule(Module1); db.addModule(Module1);
db.modules.length.should.equal(1); db.modules.length.should.equal(1);
should.exist(db.modules[0].db); should.exist(db.modules[0].node);
db.modules[0].node.should.equal(node);
}); });
it('should throw an error if module is not an instance of BaseModule', function() { it('should throw an error if module is not an instance of BaseModule', function() {

View File

@ -16,11 +16,18 @@ var mockdb = {
} }
}; };
var mocknode = {
db: mockdb,
bitcoind: {
on: sinon.stub()
}
};
describe('AddressModule', function() { describe('AddressModule', function() {
describe('#getAPIMethods', function() { describe('#getAPIMethods', function() {
it('should return the correct methods', function() { it('should return the correct methods', function() {
var am = new AddressModule({db: mockdb}); var am = new AddressModule({node: mocknode});
var methods = am.getAPIMethods(); var methods = am.getAPIMethods();
methods.length.should.equal(5); methods.length.should.equal(5);
}); });
@ -28,7 +35,7 @@ describe('AddressModule', function() {
describe('#getPublishEvents', function() { describe('#getPublishEvents', function() {
it('will return an array of publish event objects', function() { it('will return an array of publish event objects', function() {
var am = new AddressModule({db: mockdb}); var am = new AddressModule({node: mocknode});
am.subscribe = sinon.spy(); am.subscribe = sinon.spy();
am.unsubscribe = sinon.spy(); am.unsubscribe = sinon.spy();
var events = am.getPublishEvents(); var events = am.getPublishEvents();
@ -64,7 +71,7 @@ describe('AddressModule', function() {
it('create a message for an address', function() { it('create a message for an address', function() {
var txBuf = new Buffer('01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000', 'hex'); var txBuf = new Buffer('01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000', 'hex');
var tx = bitcore.Transaction().fromBuffer(txBuf); var tx = bitcore.Transaction().fromBuffer(txBuf);
var am = new AddressModule({db: mockdb}); var am = new AddressModule({node: mocknode});
var address = '12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX'; var address = '12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX';
var messages = {}; var messages = {};
am.transactionOutputHandler(messages, tx, 0, true); am.transactionOutputHandler(messages, tx, 0, true);
@ -80,7 +87,7 @@ describe('AddressModule', function() {
describe('#transactionHandler', function() { describe('#transactionHandler', function() {
it('will pass outputs to transactionOutputHandler and call transactionEventHandler', function() { it('will pass outputs to transactionOutputHandler and call transactionEventHandler', function() {
var txBuf = new Buffer('01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000', 'hex'); var txBuf = new Buffer('01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000', 'hex');
var am = new AddressModule({db: mockdb}); var am = new AddressModule({node: mocknode});
var address = '12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX'; var address = '12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX';
var message = {}; var message = {};
am.transactionOutputHandler = function(messages) { am.transactionOutputHandler = function(messages) {
@ -151,7 +158,7 @@ describe('AddressModule', function() {
var value64 = data[2].value; var value64 = data[2].value;
before(function() { before(function() {
am = new AddressModule({db: db, network: 'livenet'}); am = new AddressModule({node: mocknode, network: 'livenet'});
}); });
it('should create the correct operations when updating/adding outputs', function(done) { it('should create the correct operations when updating/adding outputs', function(done) {
@ -211,7 +218,7 @@ describe('AddressModule', function() {
} }
}; };
var am = new AddressModule({db: db, network: 'livenet'}); var am = new AddressModule({node: mocknode, network: 'livenet'});
var block = { var block = {
__height: 345003, __height: 345003,
@ -245,7 +252,13 @@ describe('AddressModule', function() {
on: sinon.stub() on: sinon.stub()
} }
}; };
var am = new AddressModule({db: db, network: 'livenet'}); var testnode = {
db: db,
bitcoind: {
on: sinon.stub()
}
};
var am = new AddressModule({node: testnode, network: 'livenet'});
am.transactionEventHandler = sinon.spy(); am.transactionEventHandler = sinon.spy();
am.balanceEventHandler = sinon.spy(); am.balanceEventHandler = sinon.spy();
@ -273,7 +286,7 @@ describe('AddressModule', function() {
describe('#transactionEventHandler', function() { describe('#transactionEventHandler', function() {
it('will emit a transaction if there is a subscriber', function(done) { it('will emit a transaction if there is a subscriber', function(done) {
var am = new AddressModule({db: mockdb}); var am = new AddressModule({node: mocknode});
var emitter = new EventEmitter(); var emitter = new EventEmitter();
am.subscriptions['address/transaction'] = { am.subscriptions['address/transaction'] = {
'1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N': [emitter] '1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N': [emitter]
@ -303,7 +316,7 @@ describe('AddressModule', function() {
describe('#balanceEventHandler', function() { describe('#balanceEventHandler', function() {
it('will emit a balance if there is a subscriber', function(done) { it('will emit a balance if there is a subscriber', function(done) {
var am = new AddressModule({db: mockdb}); var am = new AddressModule({node: mocknode});
var emitter = new EventEmitter(); var emitter = new EventEmitter();
am.subscriptions['address/balance'] = { am.subscriptions['address/balance'] = {
'1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N': [emitter] '1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N': [emitter]
@ -323,7 +336,7 @@ describe('AddressModule', function() {
describe('#subscribe', function() { describe('#subscribe', function() {
it('will add emitters to the subscribers array (transaction)', function() { it('will add emitters to the subscribers array (transaction)', function() {
var am = new AddressModule({db: mockdb}); var am = new AddressModule({node: mocknode});
var emitter = new EventEmitter(); var emitter = new EventEmitter();
var address = '1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N'; var address = '1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N';
@ -340,7 +353,7 @@ describe('AddressModule', function() {
am.subscriptions['address/transaction'][address].should.deep.equal([emitter, emitter2]); am.subscriptions['address/transaction'][address].should.deep.equal([emitter, emitter2]);
}); });
it('will add an emitter to the subscribers array (balance)', function() { it('will add an emitter to the subscribers array (balance)', function() {
var am = new AddressModule({db: mockdb}); var am = new AddressModule({node: mocknode});
var emitter = new EventEmitter(); var emitter = new EventEmitter();
var name = 'address/balance'; var name = 'address/balance';
var address = '1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N'; var address = '1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N';
@ -359,7 +372,7 @@ describe('AddressModule', function() {
describe('#unsubscribe', function() { describe('#unsubscribe', function() {
it('will remove emitter from subscribers array (transaction)', function() { it('will remove emitter from subscribers array (transaction)', function() {
var am = new AddressModule({db: mockdb}); var am = new AddressModule({node: mocknode});
var emitter = new EventEmitter(); var emitter = new EventEmitter();
var emitter2 = new EventEmitter(); var emitter2 = new EventEmitter();
var address = '1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N'; var address = '1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N';
@ -369,7 +382,7 @@ describe('AddressModule', function() {
am.subscriptions['address/transaction'][address].should.deep.equal([emitter2]); am.subscriptions['address/transaction'][address].should.deep.equal([emitter2]);
}); });
it('will remove emitter from subscribers array (balance)', function() { it('will remove emitter from subscribers array (balance)', function() {
var am = new AddressModule({db: mockdb}); var am = new AddressModule({node: mocknode});
var emitter = new EventEmitter(); var emitter = new EventEmitter();
var emitter2 = new EventEmitter(); var emitter2 = new EventEmitter();
var address = '1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N'; var address = '1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N';
@ -379,7 +392,7 @@ describe('AddressModule', function() {
am.subscriptions['address/balance'][address].should.deep.equal([emitter2]); am.subscriptions['address/balance'][address].should.deep.equal([emitter2]);
}); });
it('should unsubscribe from all addresses if no addresses are specified', function() { it('should unsubscribe from all addresses if no addresses are specified', function() {
var am = new AddressModule({db: mockdb}); var am = new AddressModule({node: mocknode});
var emitter = new EventEmitter(); var emitter = new EventEmitter();
var emitter2 = new EventEmitter(); var emitter2 = new EventEmitter();
am.subscriptions['address/balance'] = { am.subscriptions['address/balance'] = {
@ -396,7 +409,7 @@ describe('AddressModule', function() {
describe('#getBalance', function() { describe('#getBalance', function() {
it('should sum up the unspent outputs', function(done) { it('should sum up the unspent outputs', function(done) {
var am = new AddressModule({db: mockdb}); var am = new AddressModule({node: mocknode});
var outputs = [ var outputs = [
{satoshis: 1000}, {satoshis: 2000}, {satoshis: 3000} {satoshis: 1000}, {satoshis: 2000}, {satoshis: 3000}
]; ];
@ -409,7 +422,7 @@ describe('AddressModule', function() {
}); });
it('will handle error from unspent outputs', function(done) { it('will handle error from unspent outputs', function(done) {
var am = new AddressModule({db: mockdb}); var am = new AddressModule({node: mocknode});
am.getUnspentOutputs = sinon.stub().callsArgWith(2, new Error('error')); am.getUnspentOutputs = sinon.stub().callsArgWith(2, new Error('error'));
am.getBalance('someaddress', false, function(err) { am.getBalance('someaddress', false, function(err) {
should.exist(err); should.exist(err);
@ -423,24 +436,26 @@ describe('AddressModule', function() {
describe('#getOutputs', function() { describe('#getOutputs', function() {
var am; var am;
var address = '1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W'; var address = '1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W';
var db = { var db = {};
bitcoind: { var testnode = {
on: sinon.stub()
},
chain: { chain: {
tip: { tip: {
__height: 1 __height: 1
} }
},
db: db,
bitcoind: {
on: sinon.stub()
} }
}; };
before(function() { before(function() {
am = new AddressModule({db: db}); am = new AddressModule({node: testnode});
}); });
it('should get outputs for an address', function(done) { it('should get outputs for an address', function(done) {
var readStream1 = new EventEmitter(); var readStream1 = new EventEmitter();
am.db.store = { am.node.db.store = {
createReadStream: sinon.stub().returns(readStream1) createReadStream: sinon.stub().returns(readStream1)
}; };
var mempoolOutputs = [ var mempoolOutputs = [
@ -452,7 +467,7 @@ describe('AddressModule', function() {
blockHeight: 352532 blockHeight: 352532
} }
]; ];
am.db.bitcoind = { am.node.bitcoind = {
getMempoolOutputs: sinon.stub().returns(mempoolOutputs) getMempoolOutputs: sinon.stub().returns(mempoolOutputs)
}; };
@ -495,7 +510,7 @@ describe('AddressModule', function() {
it('should give an error if the readstream has an error', function(done) { it('should give an error if the readstream has an error', function(done) {
var readStream2 = new EventEmitter(); var readStream2 = new EventEmitter();
am.db.store = { am.node.db.store = {
createReadStream: sinon.stub().returns(readStream2) createReadStream: sinon.stub().returns(readStream2)
}; };
@ -525,7 +540,13 @@ describe('AddressModule', function() {
on: sinon.spy() on: sinon.spy()
} }
}; };
var am = new AddressModule({db: db}); var testnode = {
db: db,
bitcoind: {
on: sinon.stub()
}
};
var am = new AddressModule({node: testnode});
am.getUnspentOutputsForAddress = function(address, queryMempool, callback) { am.getUnspentOutputsForAddress = function(address, queryMempool, callback) {
var result = addresses[address]; var result = addresses[address];
if(result instanceof Error) { if(result instanceof Error) {
@ -553,7 +574,13 @@ describe('AddressModule', function() {
on: sinon.spy() on: sinon.spy()
} }
}; };
var am = new AddressModule({db: db}); var testnode = {
db: db,
bitcoind: {
on: sinon.stub()
}
};
var am = new AddressModule({node: testnode});
am.getUnspentOutputsForAddress = function(address, queryMempool, callback) { am.getUnspentOutputsForAddress = function(address, queryMempool, callback) {
var result = addresses[address]; var result = addresses[address];
if(result instanceof Error) { if(result instanceof Error) {
@ -582,7 +609,13 @@ describe('AddressModule', function() {
on: sinon.spy() on: sinon.spy()
} }
}; };
var am = new AddressModule({db: db}); var testnode = {
db: db,
bitcoind: {
on: sinon.stub()
}
};
var am = new AddressModule({node: testnode});
am.getUnspentOutputsForAddress = function(address, queryMempool, callback) { am.getUnspentOutputsForAddress = function(address, queryMempool, callback) {
var result = addresses[address]; var result = addresses[address];
if(result instanceof Error) { if(result instanceof Error) {
@ -618,7 +651,7 @@ describe('AddressModule', function() {
]; ];
var i = 0; var i = 0;
var am = new AddressModule({db: mockdb}); var am = new AddressModule({node: mocknode});
am.getOutputs = sinon.stub().callsArgWith(2, null, outputs); am.getOutputs = sinon.stub().callsArgWith(2, null, outputs);
am.isUnspent = function(output, queryMempool, callback) { am.isUnspent = function(output, queryMempool, callback) {
callback(!outputs[i].spent); callback(!outputs[i].spent);
@ -634,7 +667,7 @@ describe('AddressModule', function() {
}); });
}); });
it('should handle an error from getOutputs', function(done) { it('should handle an error from getOutputs', function(done) {
var am = new AddressModule({db: mockdb}); var am = new AddressModule({node: mocknode});
am.getOutputs = sinon.stub().callsArgWith(2, new Error('error')); am.getOutputs = sinon.stub().callsArgWith(2, new Error('error'));
am.getUnspentOutputsForAddress('1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W', false, function(err, outputs) { am.getUnspentOutputsForAddress('1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W', false, function(err, outputs) {
should.exist(err); should.exist(err);
@ -643,7 +676,7 @@ describe('AddressModule', function() {
}); });
}); });
it('should handle when there are no outputs', function(done) { it('should handle when there are no outputs', function(done) {
var am = new AddressModule({db: mockdb}); var am = new AddressModule({node: mocknode});
am.getOutputs = sinon.stub().callsArgWith(2, null, []); am.getOutputs = sinon.stub().callsArgWith(2, null, []);
am.getUnspentOutputsForAddress('1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W', false, function(err, outputs) { am.getUnspentOutputsForAddress('1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W', false, function(err, outputs) {
should.exist(err); should.exist(err);
@ -658,7 +691,7 @@ describe('AddressModule', function() {
var am; var am;
before(function() { before(function() {
am = new AddressModule({db: mockdb}); am = new AddressModule({node: mocknode});
}); });
it('should give true when isSpent() gives false', function(done) { it('should give true when isSpent() gives false', function(done) {
@ -693,9 +726,15 @@ describe('AddressModule', function() {
on: sinon.stub() on: sinon.stub()
} }
}; };
var testnode = {
db: db,
bitcoind: {
on: sinon.stub()
}
};
before(function() { before(function() {
am = new AddressModule({db: db}); am = new AddressModule({node: testnode});
am.db.bitcoind = { am.node.bitcoind = {
isSpent: sinon.stub().returns(true), isSpent: sinon.stub().returns(true),
on: sinon.stub() on: sinon.stub()
}; };
@ -714,12 +753,15 @@ describe('AddressModule', function() {
var db = { var db = {
store: { store: {
get: sinon.stub().callsArgWith(1, null, 'spendtxid:1') get: sinon.stub().callsArgWith(1, null, 'spendtxid:1')
}, }
};
var testnode = {
db: db,
bitcoind: { bitcoind: {
on: sinon.stub() on: sinon.stub()
} }
}; };
var am = new AddressModule({db: db}); var am = new AddressModule({node: testnode});
am.getSpendInfoForOutput('txid', 3, function(err, info) { am.getSpendInfoForOutput('txid', 3, function(err, info) {
should.not.exist(err); should.not.exist(err);
info.txid.should.equal('spendtxid'); info.txid.should.equal('spendtxid');
@ -824,17 +866,20 @@ describe('AddressModule', function() {
} }
} }
callback(new Error('tx ' + txid + ' not found')); callback(new Error('tx ' + txid + ' not found'));
}, }
bitcoind: { };
on: sinon.stub() var testnode = {
},
chain: { chain: {
tip: { tip: {
__height: 1 __height: 1
} }
},
db: db,
bitcoind: {
on: sinon.stub()
} }
}; };
var am = new AddressModule({db: db}); var am = new AddressModule({node: testnode});
am.getOutputs = sinon.stub().callsArgWith(2, null, incoming); am.getOutputs = sinon.stub().callsArgWith(2, null, incoming);
am.getSpendInfoForOutput = function(txid, outputIndex, callback) { am.getSpendInfoForOutput = function(txid, outputIndex, callback) {

View File

@ -528,12 +528,6 @@ describe('Bitcoind Node', function() {
node._initialize(); node._initialize();
// references
node.db.chain.should.equal(node.chain);
node.db.bitcoind.should.equal(node.bitcoind);
node.chain.db.should.equal(node.db);
node.chain.db.should.equal(node.db);
// event handlers // event handlers
node._initializeBitcoind.callCount.should.equal(1); node._initializeBitcoind.callCount.should.equal(1);
node._initializeDatabase.callCount.should.equal(1); node._initializeDatabase.callCount.should.equal(1);