Merge pull request #111 from pnagurny/feature/changes-for-bws
Changes for integrating into BWS
This commit is contained in:
commit
96824feeaa
12
bin/start.js
12
bin/start.js
@ -77,11 +77,7 @@ node.on('ready', function() {
|
||||
}
|
||||
|
||||
if(result) {
|
||||
if(result.toJSON) {
|
||||
response.result = result.toJSON();
|
||||
} else {
|
||||
response.result = result;
|
||||
}
|
||||
response.result = result;
|
||||
}
|
||||
|
||||
socketCallback(response);
|
||||
@ -114,11 +110,7 @@ node.on('ready', function() {
|
||||
var results = [];
|
||||
|
||||
for(var i = 0; i < arguments.length; i++) {
|
||||
if(arguments[i].toJSON) {
|
||||
results.push(arguments[i].toJSON());
|
||||
} else {
|
||||
results.push(arguments[i]);
|
||||
}
|
||||
results.push(arguments[i]);
|
||||
}
|
||||
|
||||
var params = [event.name].concat(results);
|
||||
|
||||
@ -11,7 +11,7 @@ socket.on('disconnect', function(){
|
||||
|
||||
var message = {
|
||||
method: 'getOutputs',
|
||||
params: ['1HTxCVrXuthad6YW5895K98XmVsdMvvBSw', true]
|
||||
params: ['2NChMRHVCxTPq9KeyvHQUSbfLaQY55Zzzp8', true]
|
||||
};
|
||||
|
||||
socket.send(message, function(response) {
|
||||
@ -37,8 +37,13 @@ socket.send(message2, function(response) {
|
||||
console.log(response.result);
|
||||
});
|
||||
|
||||
socket.on('transaction', function(address, block) {
|
||||
console.log(address, block);
|
||||
socket.on('transaction', function(obj) {
|
||||
console.log(JSON.stringify(obj, null, 2));
|
||||
});
|
||||
|
||||
socket.emit('subscribe', 'transaction', ['13FMwCYz3hUhwPcaWuD2M1U2KzfTtvLM89']);
|
||||
socket.on('address/transaction', function(obj) {
|
||||
console.log(JSON.stringify(obj, null, 2));
|
||||
});
|
||||
|
||||
socket.emit('subscribe', 'transaction');
|
||||
socket.emit('subscribe', 'address/transaction', ['13FMwCYz3hUhwPcaWuD2M1U2KzfTtvLM89']);
|
||||
@ -306,7 +306,8 @@ describe('Daemon Binding Functionality', function() {
|
||||
var outputs = bitcoind.getMempoolOutputs(changeAddress);
|
||||
var expected = [
|
||||
{
|
||||
script: 'OP_DUP OP_HASH160 073b7eae2823efa349e3b9155b8a735526463a0f OP_EQUALVERIFY OP_CHECKSIG',
|
||||
address: 'mgBCJAsvzgT2qNNeXsoECg2uPKrUsZ76up',
|
||||
script: '76a914073b7eae2823efa349e3b9155b8a735526463a0f88ac',
|
||||
satoshis: 40000,
|
||||
txid: tx.hash,
|
||||
outputIndex: 1
|
||||
|
||||
@ -48,8 +48,9 @@ Block.fromBufferReader = function(br) {
|
||||
return new Block(obj);
|
||||
};
|
||||
|
||||
Block.prototype.toObject = function() {
|
||||
Block.prototype.toObject = Block.prototype.toJSON = function() {
|
||||
return {
|
||||
hash: this.hash,
|
||||
version: this.version,
|
||||
prevHash: this.prevHash,
|
||||
merkleRoot: this.merkleRoot,
|
||||
@ -60,10 +61,6 @@ Block.prototype.toObject = function() {
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.toJSON = function() {
|
||||
return JSON.stringify(this.toObject());
|
||||
};
|
||||
|
||||
Block.prototype.headerToBufferWriter = function(bw) {
|
||||
/* jshint maxstatements: 20 */
|
||||
|
||||
|
||||
59
lib/bus.js
59
lib/bus.js
@ -11,44 +11,53 @@ function Bus(params) {
|
||||
util.inherits(Bus, events.EventEmitter);
|
||||
|
||||
Bus.prototype.subscribe = function(name) {
|
||||
for (var i = 0; i < this.db.modules.length; i++) {
|
||||
var events = this.db.getPublishEvents();
|
||||
|
||||
for(var i = 0; i < this.db.modules.length; i++) {
|
||||
var mod = this.db.modules[i];
|
||||
var events = mod.getPublishEvents();
|
||||
for (var j = 0; j < events.length; j++) {
|
||||
var event = events[j];
|
||||
var params = Array.prototype.slice.call(arguments).slice(1);
|
||||
params.unshift(this);
|
||||
if (name === event.name) {
|
||||
event.subscribe.apply(event.scope, params);
|
||||
}
|
||||
events = events.concat(mod.getPublishEvents());
|
||||
}
|
||||
|
||||
for (var j = 0; j < events.length; j++) {
|
||||
var event = events[j];
|
||||
var params = Array.prototype.slice.call(arguments).slice(1);
|
||||
params.unshift(this);
|
||||
if (name === event.name) {
|
||||
event.subscribe.apply(event.scope, params);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Bus.prototype.unsubscribe = function(name) {
|
||||
for (var i = 0; i < this.db.modules.length; i++) {
|
||||
var events = this.db.getPublishEvents();
|
||||
|
||||
for(var i = 0; i < this.db.modules.length; i++) {
|
||||
var mod = this.db.modules[i];
|
||||
var events = mod.getPublishEvents();
|
||||
for (var j = 0; j < events.length; j++) {
|
||||
var event = events[j];
|
||||
var params = Array.prototype.slice.call(arguments).slice(1);
|
||||
params.unshift(this);
|
||||
if (name === event.name) {
|
||||
event.unsubscribe.apply(event.scope, params);
|
||||
}
|
||||
events = events.concat(mod.getPublishEvents());
|
||||
}
|
||||
|
||||
for (var j = 0; j < events.length; j++) {
|
||||
var event = events[j];
|
||||
var params = Array.prototype.slice.call(arguments).slice(1);
|
||||
params.unshift(this);
|
||||
if (name === event.name) {
|
||||
event.unsubscribe.apply(event.scope, params);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Bus.prototype.close = function() {
|
||||
// Unsubscribe from all events
|
||||
for (var i = 0; i < this.db.modules.length; i++) {
|
||||
var events = this.db.getPublishEvents();
|
||||
|
||||
for(var i = 0; i < this.db.modules.length; i++) {
|
||||
var mod = this.db.modules[i];
|
||||
var events = mod.getPublishEvents();
|
||||
for (var j = 0; j < events.length; j++) {
|
||||
var event = events[j];
|
||||
event.unsubscribe.call(event.scope, this);
|
||||
}
|
||||
events = events.concat(mod.getPublishEvents());
|
||||
}
|
||||
|
||||
// Unsubscribe from all events
|
||||
for (var j = 0; j < events.length; j++) {
|
||||
var event = events[j];
|
||||
event.unsubscribe.call(event.scope, this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
84
lib/db.js
84
lib/db.js
@ -32,10 +32,25 @@ function DB(options) {
|
||||
|
||||
this.modules = [];
|
||||
|
||||
this.subscriptions = {
|
||||
transaction: [],
|
||||
block: []
|
||||
};
|
||||
}
|
||||
|
||||
util.inherits(DB, BaseDB);
|
||||
|
||||
DB.prototype.initialize = function() {
|
||||
// Add all db option modules
|
||||
if(this._modules && this._modules.length) {
|
||||
for(var i = 0; i < this._modules.length; i++) {
|
||||
this.addModule(this._modules[i]);
|
||||
}
|
||||
}
|
||||
this.bitcoind.on('tx', this.transactionHandler.bind(this));
|
||||
this.emit('ready');
|
||||
}
|
||||
|
||||
DB.prototype.getBlock = function(hash, callback) {
|
||||
var self = this;
|
||||
|
||||
@ -91,6 +106,28 @@ DB.prototype.getTransactionWithBlockInfo = function(txid, queryMempool, callback
|
||||
});
|
||||
};
|
||||
|
||||
DB.prototype.sendTransaction = function(tx, callback) {
|
||||
if(tx instanceof this.Transaction) {
|
||||
tx = tx.toString();
|
||||
}
|
||||
$.checkArgument(typeof tx === 'string', 'Argument must be a hex string or Transaction');
|
||||
|
||||
try {
|
||||
var txid = this.bitcoind.sendTransaction(tx);
|
||||
return callback(null, txid);
|
||||
} catch(err) {
|
||||
return callback(err);
|
||||
}
|
||||
};
|
||||
|
||||
DB.prototype.estimateFee = function(blocks, callback) {
|
||||
var self = this;
|
||||
|
||||
setImmediate(function() {
|
||||
callback(null, self.bitcoind.estimateFee(blocks));
|
||||
});
|
||||
}
|
||||
|
||||
DB.prototype.validateBlockData = function(block, callback) {
|
||||
// bitcoind does the validation
|
||||
setImmediate(callback);
|
||||
@ -195,6 +232,11 @@ 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.modules,
|
||||
function(module, next) {
|
||||
@ -222,7 +264,9 @@ DB.prototype.blockHandler = function(block, add, callback) {
|
||||
DB.prototype.getAPIMethods = function() {
|
||||
var methods = [
|
||||
['getBlock', this, this.getBlock, 1],
|
||||
['getTransaction', this, this.getTransaction, 2]
|
||||
['getTransaction', this, this.getTransaction, 2],
|
||||
['sendTransaction', this, this.sendTransaction, 1],
|
||||
['estimateFee', this, this.estimateFee, 1]
|
||||
];
|
||||
|
||||
for(var i = 0; i < this.modules.length; i++) {
|
||||
@ -232,6 +276,23 @@ DB.prototype.getAPIMethods = function() {
|
||||
return methods;
|
||||
};
|
||||
|
||||
DB.prototype.getPublishEvents = function() {
|
||||
return [
|
||||
{
|
||||
name: 'transaction',
|
||||
scope: this,
|
||||
subscribe: this.subscribe.bind(this, 'transaction'),
|
||||
unsubscribe: this.unsubscribe.bind(this, 'transaction')
|
||||
},
|
||||
{
|
||||
name: 'block',
|
||||
scope: this,
|
||||
subscribe: this.subscribe.bind(this, 'block'),
|
||||
unsubscribe: this.unsubscribe.bind(this, 'block')
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
DB.prototype.addModule = function(Module) {
|
||||
var module = new Module({
|
||||
db: this
|
||||
@ -240,4 +301,25 @@ DB.prototype.addModule = function(Module) {
|
||||
this.modules.push(module);
|
||||
};
|
||||
|
||||
DB.prototype.subscribe = function(name, emitter) {
|
||||
this.subscriptions[name].push(emitter);
|
||||
};
|
||||
|
||||
DB.prototype.unsubscribe = function(name, emitter) {
|
||||
var index = this.subscriptions[name].indexOf(emitter);
|
||||
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
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = DB;
|
||||
|
||||
@ -18,8 +18,8 @@ var AddressModule = function(options) {
|
||||
BaseModule.call(this, options);
|
||||
|
||||
this.subscriptions = {};
|
||||
this.subscriptions.transaction = {};
|
||||
this.subscriptions.balance = {};
|
||||
this.subscriptions['address/transaction'] = {};
|
||||
this.subscriptions['address/balance'] = {};
|
||||
|
||||
this.db.bitcoind.on('tx', this.transactionHandler.bind(this));
|
||||
|
||||
@ -45,16 +45,16 @@ AddressModule.prototype.getAPIMethods = function() {
|
||||
AddressModule.prototype.getPublishEvents = function() {
|
||||
return [
|
||||
{
|
||||
name: 'transaction',
|
||||
name: 'address/transaction',
|
||||
scope: this,
|
||||
subscribe: this.subscribe.bind(this, 'transaction'),
|
||||
unsubscribe: this.unsubscribe.bind(this, 'transaction')
|
||||
subscribe: this.subscribe.bind(this, 'address/transaction'),
|
||||
unsubscribe: this.unsubscribe.bind(this, 'address/transaction')
|
||||
},
|
||||
{
|
||||
name: 'balance',
|
||||
name: 'address/balance',
|
||||
scope: this,
|
||||
subscribe: this.subscribe.bind(this, 'balance'),
|
||||
unsubscribe: this.unsubscribe.bind(this, 'balance')
|
||||
subscribe: this.subscribe.bind(this, 'address/balance'),
|
||||
unsubscribe: this.unsubscribe.bind(this, 'address/balance')
|
||||
}
|
||||
];
|
||||
};
|
||||
@ -123,7 +123,6 @@ AddressModule.prototype.transactionHandler = function(txInfo) {
|
||||
for (var key in messages) {
|
||||
this.transactionEventHandler(messages[key]);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
AddressModule.prototype.blockHandler = function(block, addOutput, callback) {
|
||||
@ -234,24 +233,24 @@ AddressModule.prototype.blockHandler = function(block, addOutput, callback) {
|
||||
* @param {Boolean} [obj.rejected] - If the transaction was not accepted in the mempool
|
||||
*/
|
||||
AddressModule.prototype.transactionEventHandler = function(obj) {
|
||||
if(this.subscriptions.transaction[obj.address]) {
|
||||
var emitters = this.subscriptions.transaction[obj.address];
|
||||
for(var k = 0; k < emitters.length; k++) {
|
||||
emitters[k].emit('transaction', obj);
|
||||
if(this.subscriptions['address/transaction'][obj.address]) {
|
||||
var emitters = this.subscriptions['address/transaction'][obj.address];
|
||||
for(var i = 0; i < emitters.length; i++) {
|
||||
emitters[i].emit('address/transaction', obj);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AddressModule.prototype.balanceEventHandler = function(block, address) {
|
||||
if(this.subscriptions.balance[address]) {
|
||||
var emitters = this.subscriptions.balance[address];
|
||||
if(this.subscriptions['address/balance'][address]) {
|
||||
var emitters = this.subscriptions['address/balance'][address];
|
||||
this.getBalance(address, true, function(err, balance) {
|
||||
if(err) {
|
||||
return this.emit(err);
|
||||
}
|
||||
|
||||
for(var i = 0; i < emitters.length; i++) {
|
||||
emitters[i].emit('balance', address, balance, block);
|
||||
emitters[i].emit('address/balance', address, balance, block);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -338,9 +337,11 @@ AddressModule.prototype.getOutputs = function(addressStr, queryMempool, callback
|
||||
address: addressStr,
|
||||
txid: key[3],
|
||||
outputIndex: Number(key[4]),
|
||||
timestamp: key[2],
|
||||
satoshis: Number(value[0]),
|
||||
script: value[1],
|
||||
blockHeight: Number(value[2])
|
||||
blockHeight: Number(value[2]),
|
||||
confirmations: self.db.chain.tip.__height - Number(value[2]) + 1
|
||||
};
|
||||
|
||||
outputs.push(output);
|
||||
@ -371,7 +372,32 @@ AddressModule.prototype.getOutputs = function(addressStr, queryMempool, callback
|
||||
|
||||
};
|
||||
|
||||
AddressModule.prototype.getUnspentOutputs = function(address, queryMempool, callback) {
|
||||
AddressModule.prototype.getUnspentOutputs = function(addresses, queryMempool, callback) {
|
||||
var self = this;
|
||||
|
||||
if(!Array.isArray(addresses)) {
|
||||
addresses = [addresses];
|
||||
}
|
||||
|
||||
var utxos = [];
|
||||
|
||||
async.eachSeries(addresses, function(address, next) {
|
||||
self.getUnspentOutputsForAddress(address, queryMempool, function(err, unspents) {
|
||||
if(err && err instanceof errors.NoOutputs) {
|
||||
return next();
|
||||
} else if(err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
utxos = utxos.concat(unspents);
|
||||
next();
|
||||
});
|
||||
}, function(err) {
|
||||
callback(err, utxos);
|
||||
});
|
||||
};
|
||||
|
||||
AddressModule.prototype.getUnspentOutputsForAddress = function(address, queryMempool, callback) {
|
||||
|
||||
var self = this;
|
||||
|
||||
@ -427,7 +453,30 @@ AddressModule.prototype.getSpendInfoForOutput = function(txid, outputIndex, call
|
||||
});
|
||||
};
|
||||
|
||||
AddressModule.prototype.getAddressHistory = function(address, queryMempool, callback) {
|
||||
AddressModule.prototype.getAddressHistory = function(addresses, queryMempool, callback) {
|
||||
var self = this;
|
||||
|
||||
if(!Array.isArray(addresses)) {
|
||||
addresses = [addresses];
|
||||
}
|
||||
|
||||
var history = [];
|
||||
|
||||
async.eachSeries(addresses, function(address, next) {
|
||||
self.getAddressHistoryForAddress(address, queryMempool, function(err, h) {
|
||||
if(err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
history = history.concat(h);
|
||||
next();
|
||||
});
|
||||
}, function(err) {
|
||||
callback(err, history);
|
||||
});
|
||||
};
|
||||
|
||||
AddressModule.prototype.getAddressHistoryForAddress = function(address, queryMempool, callback) {
|
||||
var self = this;
|
||||
|
||||
var txinfos = {};
|
||||
@ -447,13 +496,21 @@ AddressModule.prototype.getAddressHistory = function(address, queryMempool, call
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
var confirmations = 0;
|
||||
if(transaction.__height >= 0) {
|
||||
confirmations = self.db.chain.tip.__height - transaction.__height;
|
||||
}
|
||||
|
||||
txinfos[transaction.hash] = {
|
||||
address: address,
|
||||
satoshis: 0,
|
||||
height: transaction.__height,
|
||||
confirmations: confirmations,
|
||||
timestamp: transaction.__timestamp,
|
||||
fees: transaction.getFee(),
|
||||
outputIndexes: [],
|
||||
inputIndexes: [],
|
||||
transaction: transaction
|
||||
tx: transaction
|
||||
};
|
||||
|
||||
callback(null, txinfos[transaction.hash]);
|
||||
@ -490,7 +547,7 @@ AddressModule.prototype.getAddressHistory = function(address, queryMempool, call
|
||||
}
|
||||
|
||||
txinfo.inputIndexes.push(spendInfo.inputIndex);
|
||||
txinfo.satoshis -= txinfo.transaction.inputs[spendInfo.inputIndex].output.satoshis;
|
||||
txinfo.satoshis -= txinfo.tx.inputs[spendInfo.inputIndex].output.satoshis;
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
11
lib/node.js
11
lib/node.js
@ -39,7 +39,7 @@ Node.prototype.getAllAPIMethods = function() {
|
||||
};
|
||||
|
||||
Node.prototype.getAllPublishEvents = function() {
|
||||
var events = [];
|
||||
var events = this.db.getPublishEvents();
|
||||
for (var i = 0; i < this.db.modules.length; i++) {
|
||||
var mod = this.db.modules[i];
|
||||
events = events.concat(mod.getPublishEvents());
|
||||
@ -407,15 +407,6 @@ Node.prototype._initializeDatabase = function() {
|
||||
|
||||
// Database
|
||||
this.db.on('ready', function() {
|
||||
|
||||
// Add all db option modules
|
||||
var modules = self.db._modules;
|
||||
if(modules && modules.length) {
|
||||
for(var i = 0; i < modules.length; i++) {
|
||||
self.db.addModule(modules[i]);
|
||||
}
|
||||
}
|
||||
|
||||
log.info('Bitcoin Database Ready');
|
||||
self.chain.initialize();
|
||||
});
|
||||
|
||||
@ -7,6 +7,7 @@ var chainlib = require('chainlib');
|
||||
var BaseTransaction = chainlib.Transaction;
|
||||
var BaseDatabase = chainlib.DB;
|
||||
var levelup = chainlib.deps.levelup;
|
||||
var _ = bitcore.deps._;
|
||||
|
||||
Transaction.prototype.populateInputs = function(db, poolTransactions, callback) {
|
||||
var self = this;
|
||||
@ -29,7 +30,7 @@ Transaction.prototype._populateInput = function(db, input, poolTransactions, cal
|
||||
return callback(new Error('Input is expected to have prevTxId as a buffer'));
|
||||
}
|
||||
var txid = input.prevTxId.toString('hex');
|
||||
db.getTransaction(txid, false, function(err, prevTx) {
|
||||
db.getTransaction(txid, true, function(err, prevTx) {
|
||||
if(err instanceof levelup.errors.NotFoundError) {
|
||||
// Check the pool for transaction
|
||||
for(var i = 0; i < poolTransactions.length; i++) {
|
||||
|
||||
@ -44,8 +44,8 @@
|
||||
"dependencies": {
|
||||
"async": "1.3.0",
|
||||
"bindings": "^1.2.1",
|
||||
"bitcore": "^0.12.15",
|
||||
"chainlib": "^0.1.1",
|
||||
"bitcore": "^0.13.0",
|
||||
"chainlib": "^0.1.3",
|
||||
"errno": "^0.1.2",
|
||||
"memdown": "^1.0.0",
|
||||
"mkdirp": "0.5.0",
|
||||
|
||||
@ -1566,7 +1566,10 @@ NAN_METHOD(GetMempoolOutputs) {
|
||||
|
||||
Local<Object> output = NanNew<Object>();
|
||||
|
||||
output->Set(NanNew<String>("script"), NanNew<String>(script.ToString()));
|
||||
output->Set(NanNew<String>("address"), NanNew<String>(psz));
|
||||
|
||||
std::string scriptHex = HexStr(script.begin(), script.end());
|
||||
output->Set(NanNew<String>("script"), NanNew<String>(scriptHex));
|
||||
|
||||
uint64_t satoshis = txout.nValue;
|
||||
output->Set(NanNew<String>("satoshis"), NanNew<Number>(satoshis)); // can't go above 2 ^ 53 -1
|
||||
|
||||
@ -7,68 +7,107 @@ var Bus = require('../lib/bus');
|
||||
describe('Bus', function() {
|
||||
|
||||
describe('#subscribe', function() {
|
||||
it('will call modules subscribe function with the correct arguments', function() {
|
||||
var subscribe = sinon.spy();
|
||||
it('will call db and modules subscribe function with the correct arguments', function() {
|
||||
var subscribeDb = sinon.spy();
|
||||
var subscribeModule = sinon.spy();
|
||||
var db = {
|
||||
getPublishEvents: sinon.stub().returns([
|
||||
{
|
||||
name: 'dbtest',
|
||||
scope: this,
|
||||
subscribe: subscribeDb
|
||||
}
|
||||
]
|
||||
),
|
||||
modules: [
|
||||
{
|
||||
getPublishEvents: sinon.stub().returns([
|
||||
{
|
||||
name: 'test',
|
||||
scope: this,
|
||||
subscribe: subscribe,
|
||||
subscribe: subscribeModule,
|
||||
}
|
||||
])
|
||||
}
|
||||
]
|
||||
};
|
||||
var bus = new Bus({db: db});
|
||||
bus.subscribe('dbtest', 'a', 'b', 'c');
|
||||
bus.subscribe('test', 'a', 'b', 'c');
|
||||
subscribe.callCount.should.equal(1);
|
||||
subscribe.args[0][0].should.equal(bus);
|
||||
subscribe.args[0][1].should.equal('a');
|
||||
subscribe.args[0][2].should.equal('b');
|
||||
subscribe.args[0][3].should.equal('c');
|
||||
subscribeModule.callCount.should.equal(1);
|
||||
subscribeDb.callCount.should.equal(1);
|
||||
subscribeDb.args[0][0].should.equal(bus);
|
||||
subscribeDb.args[0][1].should.equal('a');
|
||||
subscribeDb.args[0][2].should.equal('b');
|
||||
subscribeDb.args[0][3].should.equal('c');
|
||||
subscribeModule.args[0][0].should.equal(bus);
|
||||
subscribeModule.args[0][1].should.equal('a');
|
||||
subscribeModule.args[0][2].should.equal('b');
|
||||
subscribeModule.args[0][3].should.equal('c');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#unsubscribe', function() {
|
||||
it('will call modules unsubscribe function with the correct arguments', function() {
|
||||
var unsubscribe = sinon.spy();
|
||||
it('will call db and modules unsubscribe function with the correct arguments', function() {
|
||||
var unsubscribeDb = sinon.spy();
|
||||
var unsubscribeModule = sinon.spy();
|
||||
var db = {
|
||||
getPublishEvents: sinon.stub().returns([
|
||||
{
|
||||
name: 'dbtest',
|
||||
scope: this,
|
||||
unsubscribe: unsubscribeDb
|
||||
}
|
||||
]
|
||||
),
|
||||
modules: [
|
||||
{
|
||||
getPublishEvents: sinon.stub().returns([
|
||||
{
|
||||
name: 'test',
|
||||
scope: this,
|
||||
unsubscribe: unsubscribe
|
||||
unsubscribe: unsubscribeModule,
|
||||
}
|
||||
])
|
||||
}
|
||||
]
|
||||
};
|
||||
var bus = new Bus({db: db});
|
||||
bus.unsubscribe('dbtest', 'a', 'b', 'c');
|
||||
bus.unsubscribe('test', 'a', 'b', 'c');
|
||||
unsubscribe.callCount.should.equal(1);
|
||||
unsubscribe.args[0][0].should.equal(bus);
|
||||
unsubscribe.args[0][1].should.equal('a');
|
||||
unsubscribe.args[0][2].should.equal('b');
|
||||
unsubscribe.args[0][3].should.equal('c');
|
||||
unsubscribeModule.callCount.should.equal(1);
|
||||
unsubscribeDb.callCount.should.equal(1);
|
||||
unsubscribeDb.args[0][0].should.equal(bus);
|
||||
unsubscribeDb.args[0][1].should.equal('a');
|
||||
unsubscribeDb.args[0][2].should.equal('b');
|
||||
unsubscribeDb.args[0][3].should.equal('c');
|
||||
unsubscribeModule.args[0][0].should.equal(bus);
|
||||
unsubscribeModule.args[0][1].should.equal('a');
|
||||
unsubscribeModule.args[0][2].should.equal('b');
|
||||
unsubscribeModule.args[0][3].should.equal('c');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#close', function() {
|
||||
it('will unsubscribe from all events', function() {
|
||||
var unsubscribe = sinon.spy();
|
||||
var unsubscribeDb = sinon.spy();
|
||||
var unsubscribeModule = sinon.spy();
|
||||
var db = {
|
||||
getPublishEvents: sinon.stub().returns([
|
||||
{
|
||||
name: 'dbtest',
|
||||
scope: this,
|
||||
unsubscribe: unsubscribeDb
|
||||
}
|
||||
]
|
||||
),
|
||||
modules: [
|
||||
{
|
||||
getPublishEvents: sinon.stub().returns([
|
||||
{
|
||||
name: 'test',
|
||||
scope: this,
|
||||
unsubscribe: unsubscribe
|
||||
unsubscribe: unsubscribeModule
|
||||
}
|
||||
])
|
||||
}
|
||||
@ -78,9 +117,12 @@ describe('Bus', function() {
|
||||
var bus = new Bus({db: db});
|
||||
bus.close();
|
||||
|
||||
unsubscribe.callCount.should.equal(1);
|
||||
unsubscribe.args[0].length.should.equal(1);
|
||||
unsubscribe.args[0][0].should.equal(bus);
|
||||
unsubscribeDb.callCount.should.equal(1);
|
||||
unsubscribeModule.callCount.should.equal(1);
|
||||
unsubscribeDb.args[0].length.should.equal(1);
|
||||
unsubscribeDb.args[0][0].should.equal(bus);
|
||||
unsubscribeModule.args[0].length.should.equal(1);
|
||||
unsubscribeModule.args[0][0].should.equal(bus);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
125
test/db.unit.js
125
test/db.unit.js
@ -10,10 +10,25 @@ var errors = bitcoindjs.errors;
|
||||
var memdown = require('memdown');
|
||||
var inherits = require('util').inherits;
|
||||
var BaseModule = require('../lib/module');
|
||||
var bitcore = require('bitcore');
|
||||
var Transaction = bitcore.Transaction;
|
||||
|
||||
describe('Bitcoin DB', function() {
|
||||
var coinbaseAmount = 50 * 1e8;
|
||||
|
||||
describe('#initialize', function() {
|
||||
it('should emit ready', function(done) {
|
||||
var db = new DB({store: memdown});
|
||||
db._modules = ['mod1', 'mod2'];
|
||||
db.bitcoind = {
|
||||
on: sinon.spy()
|
||||
};
|
||||
db.addModule = sinon.spy();
|
||||
db.on('ready', done);
|
||||
db.initialize();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getTransaction', function() {
|
||||
it('will return a NotFound error', function(done) {
|
||||
var db = new DB({store: memdown});
|
||||
@ -89,6 +104,112 @@ describe('Bitcoin DB', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getPrevHash', function() {
|
||||
it('should return prevHash from bitcoind', function(done) {
|
||||
var db = new DB({store: memdown});
|
||||
db.bitcoind = {
|
||||
getBlockIndex: sinon.stub().returns({
|
||||
prevHash: 'prevhash'
|
||||
})
|
||||
};
|
||||
|
||||
db.getPrevHash('hash', function(err, prevHash) {
|
||||
should.not.exist(err);
|
||||
prevHash.should.equal('prevhash');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should give an error if bitcoind could not find it', function(done) {
|
||||
var db = new DB({store: memdown});
|
||||
db.bitcoind = {
|
||||
getBlockIndex: sinon.stub().returns(null)
|
||||
};
|
||||
|
||||
db.getPrevHash('hash', function(err, prevHash) {
|
||||
should.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getTransactionWithBlockInfo', function() {
|
||||
it('should give a transaction with height and timestamp', function(done) {
|
||||
var txBuffer = new Buffer('01000000016f95980911e01c2c664b3e78299527a47933aac61a515930a8fe0213d1ac9abe01000000da0047304402200e71cda1f71e087c018759ba3427eb968a9ea0b1decd24147f91544629b17b4f0220555ee111ed0fc0f751ffebf097bdf40da0154466eb044e72b6b3dcd5f06807fa01483045022100c86d6c8b417bff6cc3bbf4854c16bba0aaca957e8f73e19f37216e2b06bb7bf802205a37be2f57a83a1b5a8cc511dc61466c11e9ba053c363302e7b99674be6a49fc0147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a9148a31d53a448c18996e81ce67811e5fb7da21e4468738c9d6f90000000017a9148ce5408cfeaddb7ccb2545ded41ef478109454848700000000', 'hex');
|
||||
var info = {
|
||||
height: 530482,
|
||||
timestamp: 1439559434000,
|
||||
buffer: txBuffer
|
||||
};
|
||||
|
||||
var db = new DB({store: memdown});
|
||||
db.bitcoind = {
|
||||
getTransactionWithBlockInfo: sinon.stub().callsArgWith(2, null, info)
|
||||
};
|
||||
|
||||
db.getTransactionWithBlockInfo('2d950d00494caf6bfc5fff2a3f839f0eb50f663ae85ce092bc5f9d45296ae91f', true, function(err, tx) {
|
||||
should.not.exist(err);
|
||||
tx.__height.should.equal(info.height);
|
||||
tx.__timestamp.should.equal(info.timestamp);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should give an error if one occurred', function(done) {
|
||||
var db = new DB({store: memdown});
|
||||
db.bitcoind = {
|
||||
getTransactionWithBlockInfo: sinon.stub().callsArgWith(2, new Error('error'))
|
||||
};
|
||||
|
||||
db.getTransactionWithBlockInfo('tx', true, function(err, tx) {
|
||||
should.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#sendTransaction', function() {
|
||||
it('should give the txid on success', function(done) {
|
||||
var db = new DB({store: memdown});
|
||||
db.bitcoind = {
|
||||
sendTransaction: sinon.stub().returns('txid')
|
||||
};
|
||||
|
||||
var tx = new Transaction();
|
||||
db.sendTransaction(tx, function(err, txid) {
|
||||
should.not.exist(err);
|
||||
txid.should.equal('txid');
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should give an error if bitcoind threw an error', function(done) {
|
||||
var db = new DB({store: memdown});
|
||||
db.bitcoind = {
|
||||
sendTransaction: sinon.stub().throws(new Error('error'))
|
||||
};
|
||||
|
||||
var tx = new Transaction();
|
||||
db.sendTransaction(tx, function(err, txid) {
|
||||
should.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#estimateFee", function() {
|
||||
it('should pass along the fee from bitcoind', function(done) {
|
||||
var db = new DB({store: memdown});
|
||||
db.bitcoind = {
|
||||
estimateFee: sinon.stub().returns(1000)
|
||||
};
|
||||
|
||||
db.estimateFee(5, function(err, fee) {
|
||||
should.not.exist(err);
|
||||
fee.should.equal(1000);
|
||||
db.bitcoind.estimateFee.args[0][0].should.equal(5);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('#buildGenesisData', function() {
|
||||
it('build genisis data', function() {
|
||||
var db = new DB({path: 'path', store: memdown});
|
||||
@ -301,7 +422,7 @@ describe('Bitcoin DB', function() {
|
||||
var db = new DB({store: memdown});
|
||||
db.modules = [];
|
||||
var methods = db.getAPIMethods();
|
||||
methods.length.should.equal(2);
|
||||
methods.length.should.equal(4);
|
||||
});
|
||||
|
||||
it('should also return modules API methods', function() {
|
||||
@ -325,7 +446,7 @@ describe('Bitcoin DB', function() {
|
||||
db.modules = [module1, module2];
|
||||
|
||||
var methods = db.getAPIMethods();
|
||||
methods.length.should.equal(5);
|
||||
methods.length.should.equal(7);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -2,12 +2,12 @@
|
||||
|
||||
var should = require('chai').should();
|
||||
var sinon = require('sinon');
|
||||
var bitcoindjs = require('../../');
|
||||
var AddressModule = bitcoindjs.modules.AddressModule;
|
||||
var bitcorenode = require('../../');
|
||||
var AddressModule = bitcorenode.modules.AddressModule;
|
||||
var blockData = require('../data/livenet-345003.json');
|
||||
var bitcore = require('bitcore');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var errors = bitcoindjs.errors;
|
||||
var errors = bitcorenode.errors;
|
||||
var chainlib = require('chainlib');
|
||||
var levelup = chainlib.deps.levelup;
|
||||
|
||||
@ -257,7 +257,7 @@ describe('AddressModule', function() {
|
||||
it('will emit a transaction if there is a subscriber', function(done) {
|
||||
var am = new AddressModule({db: mockdb});
|
||||
var emitter = new EventEmitter();
|
||||
am.subscriptions.transaction = {
|
||||
am.subscriptions['address/transaction'] = {
|
||||
'1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N': [emitter]
|
||||
};
|
||||
var block = {
|
||||
@ -265,7 +265,7 @@ describe('AddressModule', function() {
|
||||
timestamp: new Date()
|
||||
};
|
||||
var tx = {};
|
||||
emitter.on('transaction', function(obj) {
|
||||
emitter.on('address/transaction', function(obj) {
|
||||
obj.address.should.equal('1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N');
|
||||
obj.tx.should.equal(tx);
|
||||
obj.timestamp.should.equal(block.timestamp);
|
||||
@ -287,13 +287,13 @@ describe('AddressModule', function() {
|
||||
it('will emit a balance if there is a subscriber', function(done) {
|
||||
var am = new AddressModule({db: mockdb});
|
||||
var emitter = new EventEmitter();
|
||||
am.subscriptions.balance = {
|
||||
am.subscriptions['address/balance'] = {
|
||||
'1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N': [emitter]
|
||||
};
|
||||
var block = {};
|
||||
var balance = 1000;
|
||||
am.getBalance = sinon.stub().callsArgWith(2, null, balance);
|
||||
emitter.on('balance', function(address, bal, b) {
|
||||
emitter.on('address/balance', function(address, bal, b) {
|
||||
address.should.equal('1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N');
|
||||
bal.should.equal(balance);
|
||||
b.should.equal(block);
|
||||
@ -309,33 +309,33 @@ describe('AddressModule', function() {
|
||||
var emitter = new EventEmitter();
|
||||
|
||||
var address = '1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N';
|
||||
var name = 'transaction';
|
||||
var name = 'address/transaction';
|
||||
am.subscribe(name, emitter, [address]);
|
||||
am.subscriptions.transaction[address].should.deep.equal([emitter]);
|
||||
am.subscriptions['address/transaction'][address].should.deep.equal([emitter]);
|
||||
|
||||
var address2 = '1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W';
|
||||
am.subscribe(name, emitter, [address2]);
|
||||
am.subscriptions.transaction[address2].should.deep.equal([emitter]);
|
||||
am.subscriptions['address/transaction'][address2].should.deep.equal([emitter]);
|
||||
|
||||
var emitter2 = new EventEmitter();
|
||||
am.subscribe(name, emitter2, [address]);
|
||||
am.subscriptions.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() {
|
||||
var am = new AddressModule({db: mockdb});
|
||||
var emitter = new EventEmitter();
|
||||
var name = 'balance';
|
||||
var name = 'address/balance';
|
||||
var address = '1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N';
|
||||
am.subscribe(name, emitter, [address]);
|
||||
am.subscriptions.balance[address].should.deep.equal([emitter]);
|
||||
am.subscriptions['address/balance'][address].should.deep.equal([emitter]);
|
||||
|
||||
var address2 = '1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W';
|
||||
am.subscribe(name, emitter, [address2]);
|
||||
am.subscriptions.balance[address2].should.deep.equal([emitter]);
|
||||
am.subscriptions['address/balance'][address2].should.deep.equal([emitter]);
|
||||
|
||||
var emitter2 = new EventEmitter();
|
||||
am.subscribe(name, emitter2, [address]);
|
||||
am.subscriptions.balance[address].should.deep.equal([emitter, emitter2]);
|
||||
am.subscriptions['address/balance'][address].should.deep.equal([emitter, emitter2]);
|
||||
});
|
||||
});
|
||||
|
||||
@ -345,31 +345,31 @@ describe('AddressModule', function() {
|
||||
var emitter = new EventEmitter();
|
||||
var emitter2 = new EventEmitter();
|
||||
var address = '1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N';
|
||||
am.subscriptions.transaction[address] = [emitter, emitter2];
|
||||
var name = 'transaction';
|
||||
am.subscriptions['address/transaction'][address] = [emitter, emitter2];
|
||||
var name = 'address/transaction';
|
||||
am.unsubscribe(name, emitter, [address]);
|
||||
am.subscriptions.transaction[address].should.deep.equal([emitter2]);
|
||||
am.subscriptions['address/transaction'][address].should.deep.equal([emitter2]);
|
||||
});
|
||||
it('will remove emitter from subscribers array (balance)', function() {
|
||||
var am = new AddressModule({db: mockdb});
|
||||
var emitter = new EventEmitter();
|
||||
var emitter2 = new EventEmitter();
|
||||
var address = '1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N';
|
||||
var name = 'balance';
|
||||
am.subscriptions.balance[address] = [emitter, emitter2];
|
||||
var name = 'address/balance';
|
||||
am.subscriptions['address/balance'][address] = [emitter, emitter2];
|
||||
am.unsubscribe(name, emitter, [address]);
|
||||
am.subscriptions.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() {
|
||||
var am = new AddressModule({db: mockdb});
|
||||
var emitter = new EventEmitter();
|
||||
var emitter2 = new EventEmitter();
|
||||
am.subscriptions.balance = {
|
||||
am.subscriptions['address/balance'] = {
|
||||
'1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W': [emitter, emitter2],
|
||||
'1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N': [emitter2, emitter]
|
||||
};
|
||||
am.unsubscribe('balance', emitter);
|
||||
am.subscriptions.balance.should.deep.equal({
|
||||
am.unsubscribe('address/balance', emitter);
|
||||
am.subscriptions['address/balance'].should.deep.equal({
|
||||
'1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W': [emitter2],
|
||||
'1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N': [emitter2]
|
||||
});
|
||||
@ -408,6 +408,11 @@ describe('AddressModule', function() {
|
||||
var db = {
|
||||
bitcoind: {
|
||||
on: sinon.stub()
|
||||
},
|
||||
chain: {
|
||||
tip: {
|
||||
__height: 1
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -490,6 +495,94 @@ describe('AddressModule', function() {
|
||||
});
|
||||
|
||||
describe('#getUnspentOutputs', function() {
|
||||
it('should concatenate utxos for multiple addresses, even those with none found', function(done) {
|
||||
var addresses = {
|
||||
'addr1': ['utxo1', 'utxo2'],
|
||||
'addr2': new errors.NoOutputs(),
|
||||
'addr3': ['utxo3']
|
||||
};
|
||||
|
||||
var db = {
|
||||
bitcoind: {
|
||||
on: sinon.spy()
|
||||
}
|
||||
};
|
||||
var am = new AddressModule({db: db});
|
||||
am.getUnspentOutputsForAddress = function(address, queryMempool, callback) {
|
||||
var result = addresses[address];
|
||||
if(result instanceof Error) {
|
||||
return callback(result);
|
||||
} else {
|
||||
return callback(null, result);
|
||||
}
|
||||
};
|
||||
|
||||
am.getUnspentOutputs(['addr1', 'addr2', 'addr3'], true, function(err, utxos) {
|
||||
should.not.exist(err);
|
||||
utxos.should.deep.equal(['utxo1', 'utxo2', 'utxo3']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should give an error if an error occurred', function(done) {
|
||||
var addresses = {
|
||||
'addr1': ['utxo1', 'utxo2'],
|
||||
'addr2': new Error('weird error'),
|
||||
'addr3': ['utxo3']
|
||||
};
|
||||
|
||||
var db = {
|
||||
bitcoind: {
|
||||
on: sinon.spy()
|
||||
}
|
||||
};
|
||||
var am = new AddressModule({db: db});
|
||||
am.getUnspentOutputsForAddress = function(address, queryMempool, callback) {
|
||||
var result = addresses[address];
|
||||
if(result instanceof Error) {
|
||||
return callback(result);
|
||||
} else {
|
||||
return callback(null, result);
|
||||
}
|
||||
};
|
||||
|
||||
am.getUnspentOutputs(['addr1', 'addr2', 'addr3'], true, function(err, utxos) {
|
||||
should.exist(err);
|
||||
err.message.should.equal('weird error');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should also work for a single address', function(done) {
|
||||
var addresses = {
|
||||
'addr1': ['utxo1', 'utxo2'],
|
||||
'addr2': new Error('weird error'),
|
||||
'addr3': ['utxo3']
|
||||
};
|
||||
|
||||
var db = {
|
||||
bitcoind: {
|
||||
on: sinon.spy()
|
||||
}
|
||||
};
|
||||
var am = new AddressModule({db: db});
|
||||
am.getUnspentOutputsForAddress = function(address, queryMempool, callback) {
|
||||
var result = addresses[address];
|
||||
if(result instanceof Error) {
|
||||
return callback(result);
|
||||
} else {
|
||||
return callback(null, result);
|
||||
}
|
||||
};
|
||||
|
||||
am.getUnspentOutputs('addr1', true, function(err, utxos) {
|
||||
should.not.exist(err);
|
||||
utxos.should.deep.equal(['utxo1', 'utxo2']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getUnspentOutputsForAddress', function() {
|
||||
it('should filter out spent outputs', function(done) {
|
||||
var outputs = [
|
||||
{
|
||||
@ -514,7 +607,7 @@ describe('AddressModule', function() {
|
||||
i++;
|
||||
};
|
||||
|
||||
am.getUnspentOutputs('1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W', false, function(err, outputs) {
|
||||
am.getUnspentOutputsForAddress('1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W', false, function(err, outputs) {
|
||||
should.not.exist(err);
|
||||
outputs.length.should.equal(2);
|
||||
outputs[0].satoshis.should.equal(1000);
|
||||
@ -525,7 +618,7 @@ describe('AddressModule', function() {
|
||||
it('should handle an error from getOutputs', function(done) {
|
||||
var am = new AddressModule({db: mockdb});
|
||||
am.getOutputs = sinon.stub().callsArgWith(2, new Error('error'));
|
||||
am.getUnspentOutputs('1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W', false, function(err, outputs) {
|
||||
am.getUnspentOutputsForAddress('1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W', false, function(err, outputs) {
|
||||
should.exist(err);
|
||||
err.message.should.equal('error');
|
||||
done();
|
||||
@ -534,7 +627,7 @@ describe('AddressModule', function() {
|
||||
it('should handle when there are no outputs', function(done) {
|
||||
var am = new AddressModule({db: mockdb});
|
||||
am.getOutputs = sinon.stub().callsArgWith(2, null, []);
|
||||
am.getUnspentOutputs('1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W', false, function(err, outputs) {
|
||||
am.getUnspentOutputsForAddress('1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W', false, function(err, outputs) {
|
||||
should.exist(err);
|
||||
err.should.be.instanceof(errors.NoOutputs);
|
||||
outputs.length.should.equal(0);
|
||||
@ -628,14 +721,16 @@ describe('AddressModule', function() {
|
||||
inputIndex: 0,
|
||||
height: 1,
|
||||
timestamp: 1438289011844,
|
||||
satoshis: 5000
|
||||
satoshis: 5000,
|
||||
getFee: sinon.stub().returns(1000)
|
||||
},
|
||||
{
|
||||
txid: 'tx3',
|
||||
outputIndex: 1,
|
||||
height: 3,
|
||||
timestamp: 1438289031844,
|
||||
satoshis: 2000
|
||||
satoshis: 2000,
|
||||
getFee: sinon.stub().returns(1000)
|
||||
},
|
||||
{
|
||||
txid: 'tx4',
|
||||
@ -644,7 +739,8 @@ describe('AddressModule', function() {
|
||||
inputIndex: 1,
|
||||
height: 4,
|
||||
timestamp: 1438289041844,
|
||||
satoshis: 3000
|
||||
satoshis: 3000,
|
||||
getFee: sinon.stub().returns(1000)
|
||||
},
|
||||
];
|
||||
|
||||
@ -659,7 +755,8 @@ describe('AddressModule', function() {
|
||||
satoshis: 5000
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
getFee: sinon.stub().returns(1000)
|
||||
},
|
||||
{
|
||||
txid: 'tx5',
|
||||
@ -672,7 +769,8 @@ describe('AddressModule', function() {
|
||||
satoshis: 3000
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
getFee: sinon.stub().returns(1000)
|
||||
}
|
||||
];
|
||||
|
||||
@ -689,6 +787,7 @@ describe('AddressModule', function() {
|
||||
transaction.hash = txid;
|
||||
transaction.__height = incoming[i].height;
|
||||
transaction.__timestamp = incoming[i].timestamp;
|
||||
transaction.getFee = incoming[i].getFee;
|
||||
return callback(null, transaction);
|
||||
}
|
||||
}
|
||||
@ -702,6 +801,7 @@ describe('AddressModule', function() {
|
||||
transaction.__height = outgoing[i].height;
|
||||
transaction.__timestamp = outgoing[i].timestamp;
|
||||
transaction.inputs = outgoing[i].inputs;
|
||||
transaction.getFee = outgoing[i].getFee;
|
||||
return callback(null, transaction);
|
||||
}
|
||||
}
|
||||
@ -709,6 +809,11 @@ describe('AddressModule', function() {
|
||||
},
|
||||
bitcoind: {
|
||||
on: sinon.stub()
|
||||
},
|
||||
chain: {
|
||||
tip: {
|
||||
__height: 1
|
||||
}
|
||||
}
|
||||
};
|
||||
var am = new AddressModule({db: db});
|
||||
@ -733,26 +838,31 @@ describe('AddressModule', function() {
|
||||
it('should give transaction history for an address', function(done) {
|
||||
am.getAddressHistory('address', true, function(err, history) {
|
||||
should.not.exist(err);
|
||||
history[0].transaction.hash.should.equal('tx1');
|
||||
history[0].tx.hash.should.equal('tx1');
|
||||
history[0].satoshis.should.equal(5000);
|
||||
history[0].height.should.equal(1);
|
||||
history[0].timestamp.should.equal(1438289011844);
|
||||
history[1].transaction.hash.should.equal('tx2');
|
||||
history[0].fees.should.equal(1000);
|
||||
history[1].tx.hash.should.equal('tx2');
|
||||
history[1].satoshis.should.equal(-5000);
|
||||
history[1].height.should.equal(2);
|
||||
history[1].timestamp.should.equal(1438289021844);
|
||||
history[2].transaction.hash.should.equal('tx3');
|
||||
history[1].fees.should.equal(1000);
|
||||
history[2].tx.hash.should.equal('tx3');
|
||||
history[2].satoshis.should.equal(2000);
|
||||
history[2].height.should.equal(3);
|
||||
history[2].timestamp.should.equal(1438289031844);
|
||||
history[3].transaction.hash.should.equal('tx4');
|
||||
history[2].fees.should.equal(1000);
|
||||
history[3].tx.hash.should.equal('tx4');
|
||||
history[3].satoshis.should.equal(3000);
|
||||
history[3].height.should.equal(4);
|
||||
history[3].timestamp.should.equal(1438289041844);
|
||||
history[4].transaction.hash.should.equal('tx5');
|
||||
history[3].fees.should.equal(1000);
|
||||
history[4].tx.hash.should.equal('tx5');
|
||||
history[4].satoshis.should.equal(-3000);
|
||||
history[4].height.should.equal(5);
|
||||
history[4].timestamp.should.equal(1438289051844);
|
||||
history[4].fees.should.equal(1000);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
@ -71,6 +71,7 @@ describe('Bitcoind Node', function() {
|
||||
it('should return modules publish events', function() {
|
||||
var node = new Node({});
|
||||
var db = {
|
||||
getPublishEvents: sinon.stub().returns(['db1', 'db2']),
|
||||
modules: [
|
||||
{
|
||||
getPublishEvents: sinon.stub().returns(['mda1', 'mda2'])
|
||||
@ -83,7 +84,7 @@ describe('Bitcoind Node', function() {
|
||||
node.db = db;
|
||||
|
||||
var events = node.getAllPublishEvents();
|
||||
events.should.deep.equal(['mda1', 'mda2', 'mdb1', 'mdb2']);
|
||||
events.should.deep.equal(['db1', 'db2', 'mda1', 'mda2', 'mdb1', 'mdb2']);
|
||||
});
|
||||
});
|
||||
describe('#_loadConfiguration', function() {
|
||||
@ -462,7 +463,6 @@ describe('Bitcoind Node', function() {
|
||||
setImmediate(function() {
|
||||
chainlib.log.info.callCount.should.equal(1);
|
||||
chainlib.log.info.restore();
|
||||
node.db.addModule.callCount.should.equal(1);
|
||||
node.chain.initialize.callCount.should.equal(1);
|
||||
done();
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user