Merge pull request #159 from braydonf/noderef
Use node as a reference in modules, db and chain.
This commit is contained in:
commit
aa6b03ae58
|
@ -293,7 +293,7 @@ inherits(MyModule, Node.Module);
|
|||
* @param {Function} callback - call with the leveldb database operations to perform
|
||||
*/
|
||||
MyModule.prototype.blockHandler = function(block, add, callback) {
|
||||
var transactions = this.db.getTransactionsFromBlock(block);
|
||||
var transactions = block.transactions;
|
||||
// loop through transactions and outputs
|
||||
// call the callback with leveldb database operations
|
||||
var operations = [];
|
||||
|
@ -353,7 +353,7 @@ MyModule.prototype.subscribeCustom = function(emitter, param) {
|
|||
|
||||
MyModule.prototype.getData = function(arg1, callback) {
|
||||
// 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;
|
||||
|
|
1
index.js
1
index.js
|
@ -3,7 +3,6 @@
|
|||
module.exports = require('./lib');
|
||||
module.exports.daemon = require('./lib/daemon');
|
||||
module.exports.Node = require('./lib/node');
|
||||
module.exports.Block = require('./lib/block');
|
||||
module.exports.Chain = require('./lib/chain');
|
||||
module.exports.DB = require('./lib/db');
|
||||
module.exports.Transaction = require('./lib/transaction');
|
||||
|
|
|
@ -102,7 +102,7 @@ describe('Node Functionality', function() {
|
|||
|
||||
after(function(done) {
|
||||
this.timeout(20000);
|
||||
node.db.bitcoind.stop(function(err, result) {
|
||||
node.bitcoind.stop(function(err, result) {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
|
168
lib/block.js
168
lib/block.js
|
@ -1,168 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var bitcore = require('bitcore');
|
||||
var BufferReader = bitcore.encoding.BufferReader;
|
||||
var BufferWriter = bitcore.encoding.BufferWriter;
|
||||
var Hash = bitcore.crypto.Hash;
|
||||
|
||||
//TODO: use bitcore.Block
|
||||
|
||||
function Block(obj) {
|
||||
/* jshint maxstatements: 25 */
|
||||
if (!(this instanceof Block)) {
|
||||
return new Block(obj);
|
||||
}
|
||||
|
||||
this.version = obj.version || 1;
|
||||
this.prevHash = obj.prevHash;
|
||||
|
||||
if (!obj.hasOwnProperty('prevHash')) {
|
||||
throw new TypeError('"prevHash" is expected');
|
||||
}
|
||||
if (!obj.timestamp) {
|
||||
throw new TypeError('"timestamp" is expected');
|
||||
}
|
||||
this.timestamp = obj.timestamp;
|
||||
if (typeof this.timestamp === 'string') {
|
||||
this.timestamp = new Date(obj.timestamp);
|
||||
}
|
||||
|
||||
this.merkleRoot = obj.merkleRoot;
|
||||
|
||||
if (obj.data) {
|
||||
if (!Buffer.isBuffer(obj.data)) {
|
||||
throw new TypeError('"data" is expected to be a buffer');
|
||||
}
|
||||
this.data = obj.data;
|
||||
} else {
|
||||
this.data = new Buffer(0);
|
||||
}
|
||||
|
||||
var hashProperty = {
|
||||
configurable: false,
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return this.getHash();
|
||||
},
|
||||
set: function() {}
|
||||
};
|
||||
|
||||
Object.defineProperty(this, 'hash', hashProperty);
|
||||
|
||||
this.bits = obj.bits;
|
||||
this.nonce = obj.nonce || 0;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Block.fromBuffer = function(buffer) {
|
||||
var br = new BufferReader(buffer);
|
||||
return Block.fromBufferReader(br);
|
||||
};
|
||||
|
||||
Block.fromBufferReader = function(br) {
|
||||
var obj = {};
|
||||
obj.version = br.readUInt32LE();
|
||||
obj.prevHash = BufferReader(br.read(32)).readReverse().toString('hex');
|
||||
var nullHash = new Buffer(Array(32)).toString('hex');
|
||||
if (obj.prevHash === nullHash) {
|
||||
obj.prevHash = null;
|
||||
}
|
||||
obj.merkleRoot = BufferReader(br.read(32)).readReverse().toString('hex');
|
||||
var timestamp = br.readUInt32LE();
|
||||
obj.timestamp = new Date(timestamp * 1000);
|
||||
obj.bits = br.readUInt32LE();
|
||||
obj.nonce = br.readUInt32LE();
|
||||
obj.data = br.readAll();
|
||||
return new Block(obj);
|
||||
};
|
||||
|
||||
Block.prototype.validate = function(chain, callback) {
|
||||
// bitcoind does all validation
|
||||
setImmediate(callback);
|
||||
};
|
||||
|
||||
Block.prototype.headerToBuffer = function() {
|
||||
var bw = new BufferWriter();
|
||||
this.headerToBufferWriter(bw);
|
||||
return bw.concat();
|
||||
};
|
||||
|
||||
Block.prototype.headerToBufferWriter = function(bw) {
|
||||
/* jshint maxstatements: 20 */
|
||||
|
||||
// version
|
||||
bw.writeUInt32LE(this.version);
|
||||
|
||||
// prevhash
|
||||
if (!this.prevHash) {
|
||||
bw.write(new Buffer(Array(32)));
|
||||
} else {
|
||||
var prevHashBuffer = new Buffer(this.prevHash, 'hex');
|
||||
prevHashBuffer = BufferReader(prevHashBuffer).readReverse();
|
||||
if (prevHashBuffer.length !== 32) {
|
||||
throw new Error('"prevHash" is expected to be 32 bytes');
|
||||
}
|
||||
bw.write(prevHashBuffer);
|
||||
}
|
||||
|
||||
// merkleroot
|
||||
if (!this.merkleRoot) {
|
||||
bw.write(new Buffer(Array(32)));
|
||||
} else {
|
||||
var merkleRoot = new Buffer(this.merkleRoot, 'hex');
|
||||
merkleRoot = BufferReader(merkleRoot).readReverse();
|
||||
if (merkleRoot.length !== 32) {
|
||||
throw new Error('"merkleRoot" is expected to be 32 bytes');
|
||||
}
|
||||
bw.write(merkleRoot);
|
||||
}
|
||||
|
||||
// timestamp
|
||||
bw.writeUInt32LE(Math.floor(this.timestamp.getTime() / 1000));
|
||||
|
||||
// bits
|
||||
bw.writeUInt32LE(this.bits);
|
||||
|
||||
// nonce
|
||||
bw.writeUInt32LE(this.nonce);
|
||||
|
||||
return bw;
|
||||
|
||||
};
|
||||
|
||||
Block.prototype.toObject = Block.prototype.toJSON = function() {
|
||||
return {
|
||||
hash: this.hash,
|
||||
version: this.version,
|
||||
prevHash: this.prevHash,
|
||||
merkleRoot: this.merkleRoot,
|
||||
timestamp: this.timestamp.toISOString(),
|
||||
bits: this.bits,
|
||||
nonce: this.nonce,
|
||||
data: this.data.toString('hex')
|
||||
};
|
||||
};
|
||||
|
||||
Block.prototype.toBufferWriter = function(bw) {
|
||||
// header
|
||||
this.headerToBufferWriter(bw);
|
||||
|
||||
// transaction data
|
||||
bw.write(this.data);
|
||||
return bw;
|
||||
};
|
||||
|
||||
Block.prototype.toBuffer = function() {
|
||||
var bw = new BufferWriter();
|
||||
this.toBufferWriter(bw);
|
||||
return bw.concat();
|
||||
};
|
||||
|
||||
Block.prototype.getHash = function() {
|
||||
var hashBuffer = BufferReader(Hash.sha256sha256(this.headerToBuffer())).readReverse();
|
||||
var hash = hashBuffer.toString('hex');
|
||||
return hash;
|
||||
};
|
||||
|
||||
module.exports = Block;
|
26
lib/chain.js
26
lib/chain.js
|
@ -5,7 +5,7 @@ var EventEmitter = require('events').EventEmitter;
|
|||
var bitcore = require('bitcore');
|
||||
var BN = bitcore.crypto.BN;
|
||||
var $ = bitcore.util.preconditions;
|
||||
var Block = require('./block');
|
||||
var Block = bitcore.Block;
|
||||
var index = require('./index');
|
||||
var log = index.log;
|
||||
var utils = require('./utils');
|
||||
|
@ -34,9 +34,6 @@ function Chain(opts) {
|
|||
opts = {};
|
||||
}
|
||||
|
||||
this.db = opts.db;
|
||||
this.p2p = opts.p2p;
|
||||
|
||||
this.genesis = opts.genesis;
|
||||
this.genesisOptions = opts.genesisOptions;
|
||||
this.genesisWeight = new BN(0);
|
||||
|
@ -102,18 +99,18 @@ Chain.prototype.initialize = function() {
|
|||
var self = this;
|
||||
|
||||
// Does our database already have a tip?
|
||||
self.db.getMetadata(function getMetadataCallback(err, metadata) {
|
||||
self.node.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.db.putBlock(self.genesis, function putBlockCallback(err) {
|
||||
self.node.db.putBlock(self.genesis, function putBlockCallback(err) {
|
||||
if(err) {
|
||||
return self.emit('error', err);
|
||||
}
|
||||
self.db._onChainAddBlock(self.genesis, function(err) {
|
||||
self.node.db._onChainAddBlock(self.genesis, function(err) {
|
||||
if(err) {
|
||||
return self.emit('error', err);
|
||||
}
|
||||
|
@ -125,7 +122,7 @@ Chain.prototype.initialize = function() {
|
|||
});
|
||||
} else {
|
||||
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) {
|
||||
return self.emit('error', err);
|
||||
}
|
||||
|
@ -144,13 +141,6 @@ Chain.prototype.stop = function(callback) {
|
|||
setImmediate(callback);
|
||||
};
|
||||
|
||||
Chain.prototype._writeBlock = function(block, callback) {
|
||||
// Update hashes
|
||||
this.cache.hashes[block.hash] = block.prevHash;
|
||||
// call db.putBlock to update prevHash index, but it won't write the block to disk
|
||||
this.db.putBlock(block, callback);
|
||||
};
|
||||
|
||||
Chain.prototype._validateBlock = function(block, callback) {
|
||||
// All validation is done by bitcoind
|
||||
setImmediate(callback);
|
||||
|
@ -162,7 +152,7 @@ Chain.prototype.startBuilder = function() {
|
|||
|
||||
Chain.prototype.getWeight = function getWeight(blockHash, callback) {
|
||||
var self = this;
|
||||
var blockIndex = self.db.bitcoind.getBlockIndex(blockHash);
|
||||
var blockIndex = self.node.bitcoind.getBlockIndex(blockHash);
|
||||
|
||||
setImmediate(function() {
|
||||
if (blockIndex) {
|
||||
|
@ -225,7 +215,7 @@ Chain.prototype.getHashes = function getHashes(tipHash, callback) {
|
|||
}
|
||||
} else {
|
||||
// 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) {
|
||||
return callback(err);
|
||||
}
|
||||
|
@ -256,7 +246,7 @@ Chain.prototype.saveMetadata = function saveMetadata(callback) {
|
|||
|
||||
self.lastSavedMetadata = new Date();
|
||||
|
||||
self.db.putMetadata(metadata, callback);
|
||||
self.node.db.putMetadata(metadata, callback);
|
||||
};
|
||||
|
||||
module.exports = Chain;
|
||||
|
|
60
lib/db.js
60
lib/db.js
|
@ -6,9 +6,8 @@ var async = require('async');
|
|||
var levelup = require('levelup');
|
||||
var leveldown = require('leveldown');
|
||||
var bitcore = require('bitcore');
|
||||
var Block = bitcore.Block;
|
||||
var $ = bitcore.util.preconditions;
|
||||
var BufferReader = bitcore.encoding.BufferReader;
|
||||
var BufferWriter = bitcore.encoding.BufferWriter;
|
||||
var index = require('./');
|
||||
var errors = index.errors;
|
||||
var log = index.log;
|
||||
|
@ -38,8 +37,6 @@ function DB(options) {
|
|||
}
|
||||
|
||||
this.store = levelup(options.path, { db: levelupStore });
|
||||
this.chain = options.chain;
|
||||
this.Block = options.Block || require('./block');
|
||||
this.txPrefix = options.txPrefix || DB.PREFIXES.TX;
|
||||
this.prevHashPrefix = options.prevHashPrefix || DB.PREFIXES.PREV_HASH;
|
||||
this.blockPrefix = options.blockPrefix || DB.PREFIXES.BLOCK;
|
||||
|
@ -88,7 +85,7 @@ DB.prototype.start = function(callback) {
|
|||
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');
|
||||
setImmediate(callback);
|
||||
};
|
||||
|
@ -102,16 +99,16 @@ DB.prototype.getBlock = function(hash, callback) {
|
|||
var self = this;
|
||||
|
||||
// get block from bitcoind
|
||||
this.bitcoind.getBlock(hash, function(err, blockData) {
|
||||
this.node.bitcoind.getBlock(hash, function(err, blockData) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
callback(null, self.Block.fromBuffer(blockData));
|
||||
callback(null, Block.fromBuffer(blockData));
|
||||
});
|
||||
};
|
||||
|
||||
DB.prototype.getPrevHash = function(blockHash, callback) {
|
||||
var blockIndex = this.bitcoind.getBlockIndex(blockHash);
|
||||
var blockIndex = this.node.bitcoind.getBlockIndex(blockHash);
|
||||
setImmediate(function() {
|
||||
if (blockIndex) {
|
||||
callback(null, blockIndex.prevHash);
|
||||
|
@ -127,7 +124,7 @@ DB.prototype.putBlock = function(block, 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) {
|
||||
return callback(err);
|
||||
}
|
||||
|
@ -140,7 +137,7 @@ DB.prototype.getTransaction = 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) {
|
||||
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');
|
||||
|
||||
try {
|
||||
var txid = this.bitcoind.sendTransaction(tx);
|
||||
var txid = this.node.bitcoind.sendTransaction(tx);
|
||||
return callback(null, txid);
|
||||
} catch(err) {
|
||||
return callback(err);
|
||||
|
@ -171,7 +168,7 @@ DB.prototype.estimateFee = function(blocks, callback) {
|
|||
var self = this;
|
||||
|
||||
setImmediate(function() {
|
||||
callback(null, self.bitcoind.estimateFee(blocks));
|
||||
callback(null, self.node.bitcoind.estimateFee(blocks));
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -232,43 +229,6 @@ DB.prototype.close = function(callback) {
|
|||
this.store.close(callback);
|
||||
};
|
||||
|
||||
DB.prototype.addTransactionsToBlock = function addTransactionsToBlock(block, transactions) {
|
||||
var txs = this.getTransactionsFromBlock(block);
|
||||
txs = txs.concat(transactions);
|
||||
var txsBuffer = this.Transaction.manyToBuffer(txs);
|
||||
var bw = new BufferWriter();
|
||||
bw.writeVarintNum(txs.length);
|
||||
bw.write(txsBuffer);
|
||||
block.merkleRoot = this.getMerkleRoot(txs);
|
||||
block.data = bw.concat();
|
||||
block.__transactions = txs;
|
||||
};
|
||||
|
||||
DB.prototype.getTransactionsFromBlock = function getTransactionsFromBlock(block) {
|
||||
var self = this;
|
||||
if (block.data.length === 0) {
|
||||
return [];
|
||||
} else if(block.__transactions) {
|
||||
return block.__transactions;
|
||||
}
|
||||
|
||||
var br = new BufferReader(block.data);
|
||||
var count = br.readVarintNum();
|
||||
var transactions = [];
|
||||
for (var i = 0; i < count; i++) {
|
||||
var tx;
|
||||
if (self.Transaction.prototype.fromBufferReader) {
|
||||
tx = self.Transaction().fromBufferReader(br);
|
||||
} else {
|
||||
tx = self.Transaction.fromBufferReader(br);
|
||||
}
|
||||
transactions.push(tx);
|
||||
}
|
||||
|
||||
block.__transactions = transactions;
|
||||
return transactions;
|
||||
};
|
||||
|
||||
DB.prototype.getOutputTotal = function(transactions, excludeCoinbase) {
|
||||
var totals = transactions.map(function(tx) {
|
||||
if(tx.isCoinbase() && excludeCoinbase) {
|
||||
|
@ -375,7 +335,7 @@ DB.prototype.getPublishEvents = function() {
|
|||
|
||||
DB.prototype.addModule = function(Module) {
|
||||
var module = new Module({
|
||||
db: this
|
||||
node: this.node
|
||||
});
|
||||
$.checkArgumentType(module, BaseModule);
|
||||
this.modules.push(module);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
var Module = function(options) {
|
||||
this.db = options.db;
|
||||
this.node = options.node;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,7 +21,7 @@ var AddressModule = function(options) {
|
|||
this.subscriptions['address/transaction'] = {};
|
||||
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
|
||||
var address = script.toAddress(this.db.network);
|
||||
var address = script.toAddress(this.node.db.network);
|
||||
if (!address && script.isPublicKeyOut()) {
|
||||
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){
|
||||
return;
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ AddressModule.prototype.transactionHandler = function(txInfo) {
|
|||
};
|
||||
|
||||
AddressModule.prototype.blockHandler = function(block, addOutput, callback) {
|
||||
var txs = this.db.getTransactionsFromBlock(block);
|
||||
var txs = block.transactions;
|
||||
|
||||
var action = 'put';
|
||||
if (!addOutput) {
|
||||
|
@ -157,16 +157,17 @@ AddressModule.prototype.blockHandler = function(block, addOutput, callback) {
|
|||
continue;
|
||||
}
|
||||
|
||||
var address = script.toAddress(this.db.network);
|
||||
var address = script.toAddress(this.node.db.network);
|
||||
if (!address && script.isPublicKeyOut()) {
|
||||
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){
|
||||
continue;
|
||||
}
|
||||
|
||||
var outputIndex = j;
|
||||
var timestamp = block.timestamp.getTime();
|
||||
// TODO: expose block timestamp as a date object in bitcore?
|
||||
var timestamp = block.header.timestamp;
|
||||
var height = block.__height;
|
||||
|
||||
var addressStr = address.toString();
|
||||
|
@ -190,7 +191,7 @@ AddressModule.prototype.blockHandler = function(block, addOutput, callback) {
|
|||
height: block.__height,
|
||||
outputIndexes: [outputIndex],
|
||||
address: addressStr,
|
||||
timestamp: block.timestamp
|
||||
timestamp: block.header.timestamp
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -323,7 +324,7 @@ AddressModule.prototype.getOutputs = function(addressStr, queryMempool, callback
|
|||
var outputs = [];
|
||||
var key = [AddressModule.PREFIXES.OUTPUTS, addressStr].join('-');
|
||||
|
||||
var stream = this.db.store.createReadStream({
|
||||
var stream = this.node.db.store.createReadStream({
|
||||
start: key,
|
||||
end: key + '~'
|
||||
});
|
||||
|
@ -341,7 +342,7 @@ AddressModule.prototype.getOutputs = function(addressStr, queryMempool, callback
|
|||
satoshis: Number(value[0]),
|
||||
script: value[1],
|
||||
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);
|
||||
|
@ -362,7 +363,7 @@ AddressModule.prototype.getOutputs = function(addressStr, queryMempool, callback
|
|||
}
|
||||
|
||||
if(queryMempool) {
|
||||
outputs = outputs.concat(self.db.bitcoind.getMempoolOutputs(addressStr));
|
||||
outputs = outputs.concat(self.node.bitcoind.getMempoolOutputs(addressStr));
|
||||
}
|
||||
|
||||
callback(null, outputs);
|
||||
|
@ -429,7 +430,7 @@ AddressModule.prototype.isSpent = function(output, queryMempool, callback) {
|
|||
var txid = output.prevTxId ? output.prevTxId.toString('hex') : output.txid;
|
||||
|
||||
setImmediate(function() {
|
||||
callback(self.db.bitcoind.isSpent(txid, output.outputIndex));
|
||||
callback(self.node.bitcoind.isSpent(txid, output.outputIndex));
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -437,7 +438,7 @@ AddressModule.prototype.getSpendInfoForOutput = function(txid, outputIndex, call
|
|||
var self = this;
|
||||
|
||||
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) {
|
||||
return callback(err);
|
||||
}
|
||||
|
@ -486,19 +487,19 @@ AddressModule.prototype.getAddressHistoryForAddress = function(address, queryMem
|
|||
return callback(null, txinfos[txid]);
|
||||
}
|
||||
|
||||
self.db.getTransactionWithBlockInfo(txid, queryMempool, function(err, transaction) {
|
||||
self.node.db.getTransactionWithBlockInfo(txid, queryMempool, function(err, transaction) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
transaction.populateInputs(self.db, [], function(err) {
|
||||
transaction.populateInputs(self.node.db, [], function(err) {
|
||||
if(err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
var confirmations = 0;
|
||||
if(transaction.__height >= 0) {
|
||||
confirmations = self.db.chain.tip.__height - transaction.__height;
|
||||
confirmations = self.node.chain.tip.__height - transaction.__height;
|
||||
}
|
||||
|
||||
txinfos[transaction.hash] = {
|
||||
|
|
32
lib/node.js
32
lib/node.js
|
@ -6,11 +6,12 @@ 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;
|
||||
var _ = bitcore.deps._;
|
||||
var $ = bitcore.util.preconditions;
|
||||
var Block = bitcore.Block;
|
||||
var Chain = require('./chain');
|
||||
var Block = require('./block');
|
||||
var DB = require('./db');
|
||||
var index = require('./');
|
||||
var log = index.log;
|
||||
|
@ -24,7 +25,6 @@ function Node(config) {
|
|||
|
||||
this.db = null;
|
||||
this.chain = null;
|
||||
this.p2p = null;
|
||||
this.network = null;
|
||||
|
||||
this._loadConfiguration(config);
|
||||
|
@ -136,7 +136,8 @@ Node.prototype._syncBitcoindAncestor = function(block, done) {
|
|||
currentHashesMap[currentHashes[i]] = true;
|
||||
}
|
||||
|
||||
var ancestorHash = block.prevHash;
|
||||
// TODO: expose prevHash as a string from bitcore
|
||||
var ancestorHash = BufferUtil.reverse(block.header.prevHash).toString('hex');
|
||||
|
||||
// We only need to go back until we meet the main chain for the forked block
|
||||
// and thus don't need to find the entire chain of hashes.
|
||||
|
@ -183,7 +184,10 @@ Node.prototype._syncBitcoindRewind = function(block, done) {
|
|||
|
||||
var tip = self.chain.tip;
|
||||
|
||||
self.getBlock(tip.prevHash, function(err, previousTip) {
|
||||
// TODO: expose prevHash as a string from bitcore
|
||||
var prevHash = BufferUtil.reverse(tip.header.prevHash).toString('hex');
|
||||
|
||||
self.getBlock(prevHash, function(err, previousTip) {
|
||||
if (err) {
|
||||
removeDone(err);
|
||||
}
|
||||
|
@ -195,7 +199,6 @@ Node.prototype._syncBitcoindRewind = function(block, done) {
|
|||
}
|
||||
|
||||
// Set the new tip
|
||||
delete self.chain.tip.__transactions;
|
||||
previousTip.__height = self.chain.tip.__height - 1;
|
||||
self.chain.tip = previousTip;
|
||||
self.chain.saveMetadata();
|
||||
|
@ -241,9 +244,12 @@ Node.prototype._syncBitcoind = function() {
|
|||
return done(err);
|
||||
}
|
||||
|
||||
var block = self.Block.fromBuffer(blockBuffer);
|
||||
var block = Block.fromBuffer(blockBuffer);
|
||||
|
||||
if (block.prevHash === self.chain.tip.hash) {
|
||||
// TODO: expose prevHash as a string from bitcore
|
||||
var prevHash = BufferUtil.reverse(block.header.prevHash).toString('hex');
|
||||
|
||||
if (prevHash === self.chain.tip.hash) {
|
||||
|
||||
// This block appends to the current chain tip and we can
|
||||
// immediately add it to the chain and create indexes.
|
||||
|
@ -252,7 +258,7 @@ Node.prototype._syncBitcoind = function() {
|
|||
block.__height = self.chain.tip.__height + 1;
|
||||
|
||||
// Update chain.cache.hashes
|
||||
self.chain.cache.hashes[block.hash] = block.prevHash;
|
||||
self.chain.cache.hashes[block.hash] = prevHash;
|
||||
|
||||
// Update chain.cache.chainHashes
|
||||
self.chain.getHashes(block.hash, function(err, hashes) {
|
||||
|
@ -264,7 +270,6 @@ Node.prototype._syncBitcoind = function() {
|
|||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
delete self.chain.tip.__transactions;
|
||||
self.chain.tip = block;
|
||||
log.debug('Saving metadata');
|
||||
self.chain.saveMetadata();
|
||||
|
@ -369,7 +374,6 @@ Node.prototype._loadConsensus = function(config) {
|
|||
options = _.clone(config.consensus || {});
|
||||
}
|
||||
options.node = this;
|
||||
this.Block = Block;
|
||||
this.chain = new Chain(options);
|
||||
};
|
||||
|
||||
|
@ -391,14 +395,6 @@ Node.prototype._loadAPI = function() {
|
|||
Node.prototype._initialize = function() {
|
||||
var self = this;
|
||||
|
||||
// DB References
|
||||
this.db.chain = this.chain;
|
||||
this.db.Block = this.Block;
|
||||
this.db.bitcoind = this.bitcoind;
|
||||
|
||||
// Chain References
|
||||
this.chain.db = this.db;
|
||||
|
||||
this._initializeBitcoind();
|
||||
this._initializeDatabase();
|
||||
this._initializeChain();
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var chai = require('chai');
|
||||
var should = chai.should();
|
||||
var sinon = require('sinon');
|
||||
var bitcore = require('bitcore');
|
||||
var BN = bitcore.crypto.BN;
|
||||
var BufferWriter = bitcore.encoding.BufferWriter;
|
||||
var BufferReader = bitcore.encoding.BufferReader;
|
||||
var bitcoindjs = require('../');
|
||||
var Block = bitcoindjs.Block;
|
||||
var chainData = require('./data/pow-chain.json');
|
||||
|
||||
describe('Bitcoin Block', function() {
|
||||
|
||||
describe('@constructor', function() {
|
||||
it('set bits and nonce', function() {
|
||||
var block = new Block(chainData[1]);
|
||||
should.exist(block.bits);
|
||||
block.bits.should.equal(chainData[1].bits);
|
||||
should.exist(block.nonce);
|
||||
block.nonce.should.equal(chainData[1].nonce);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#fromBuffer', function() {
|
||||
var buffer = new Buffer('010000004404c1ff5f300e5ed830b45ec9f68fbe9a0c51c4b4eaa4ce09a03ac4ddde01750000000000000000000000000000000000000000000000000000000000000000b134de547fcc071f4a020000abcdef', 'hex');
|
||||
|
||||
it('deserializes correctly', function() {
|
||||
var block = Block.fromBuffer(buffer);
|
||||
block.version.should.equal(1);
|
||||
block.prevHash.should.equal('7501deddc43aa009cea4eab4c4510c9abe8ff6c95eb430d85e0e305fffc10444');
|
||||
block.merkleRoot.should.equal(new Buffer(Array(32)).toString('hex'));
|
||||
block.timestamp.should.be.instanceof(Date);
|
||||
block.timestamp.toISOString().should.equal('2015-02-13T17:30:25.000Z');
|
||||
block.bits.should.equal(520604799);
|
||||
block.nonce.should.equal(586);
|
||||
block.data.should.deep.equal(new Buffer('abcdef', 'hex'));
|
||||
});
|
||||
it('roundtrip serialization', function() {
|
||||
var actual = Block.fromBuffer(buffer).toBuffer();
|
||||
actual.should.deep.equal(buffer);
|
||||
});
|
||||
it('set null prevHash if null hash buffer', function() {
|
||||
var blockBuffer = new Buffer('0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d4d5fd834b0100007fcc071f4a020000abcdef', 'hex');
|
||||
var block = Block.fromBuffer(blockBuffer);
|
||||
block.hasOwnProperty('prevHash').should.equal(true);
|
||||
should.equal(block.prevHash, null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#headerToBufferWriter', function() {
|
||||
it('serializes correctly', function() {
|
||||
var block = new Block(chainData[1]);
|
||||
var bw = new BufferWriter();
|
||||
block.headerToBufferWriter(bw);
|
||||
bw.bufs[0].toString('hex').should.equal('01000000'); // version
|
||||
BufferReader(bw.bufs[1]).readReverse().toString('hex').should.equal(chainData[1].prevHash); // prevhash
|
||||
Number(bw.bufs[2].toString('hex')).should.equal(0); // merkle root
|
||||
should.exist(bw.bufs[3]); // time
|
||||
bw.bufs[3].length.should.equal(4);
|
||||
should.exist(bw.bufs[4]); // bits
|
||||
bw.bufs[4].length.should.equal(4);
|
||||
should.exist(bw.bufs[5]); // nonce
|
||||
bw.bufs[5].length.should.equal(4);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Bitcoin Block', function() {
|
||||
it('should load and serialize the Bitcoin testnet genesis block correctly', function() {
|
||||
var blockBuffer = new Buffer('0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff001d1aa4ae180101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000', 'hex');
|
||||
var block = Block.fromBuffer(blockBuffer);
|
||||
block.hash.should.equal('000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943');
|
||||
});
|
||||
it('should load and serialize Bitcoin testnet #1 block correctly', function() {
|
||||
var blockBuffer = new Buffer('0100000043497fd7f826957108f4a30fd9cec3aeba79972084e90ead01ea330900000000bac8b0fa927c0ac8234287e33c5f74d38d354820e24756ad709d7038fc5f31f020e7494dffff001d03e4b6720101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0420e7494d017f062f503253482fffffffff0100f2052a010000002321021aeaf2f8638a129a3156fbe7e5ef635226b0bafd495ff03afe2c843d7e3a4b51ac00000000', 'hex');
|
||||
var block = Block.fromBuffer(blockBuffer);
|
||||
block.hash.should.equal('00000000b873e79784647a6c82962c70d228557d24a747ea4d1b8bbe878e1206');
|
||||
block.toBuffer().should.deep.equal(blockBuffer);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
|
@ -8,8 +8,9 @@ var memdown = require('memdown');
|
|||
var index = require('../');
|
||||
var DB = index.DB;
|
||||
var Chain = index.Chain;
|
||||
var Block = index.Block;
|
||||
var bitcore = require('bitcore');
|
||||
var BufferUtil = bitcore.util.buffer;
|
||||
var Block = bitcore.Block;
|
||||
var BN = bitcore.crypto.BN;
|
||||
|
||||
var chainData = require('./data/testnet-blocks.json');
|
||||
|
@ -51,7 +52,10 @@ describe('Bitcoin Chain', function() {
|
|||
db.mempool = {
|
||||
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() {
|
||||
should.exist(chain.tip);
|
||||
|
@ -78,7 +82,10 @@ describe('Bitcoin Chain', function() {
|
|||
db.mempool = {
|
||||
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.getWeight = sinon.stub().callsArgWith(1, null, new BN(50));
|
||||
chain.on('ready', function() {
|
||||
|
@ -104,7 +111,10 @@ describe('Bitcoin Chain', function() {
|
|||
db.mempool = {
|
||||
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) {
|
||||
should.exist(error);
|
||||
error.message.should.equal('getMetadataError');
|
||||
|
@ -126,7 +136,10 @@ describe('Bitcoin Chain', function() {
|
|||
db.mempool = {
|
||||
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) {
|
||||
should.exist(error);
|
||||
error.message.should.equal('putBlockError');
|
||||
|
@ -148,7 +161,10 @@ describe('Bitcoin Chain', function() {
|
|||
db.mempool = {
|
||||
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) {
|
||||
should.exist(error);
|
||||
error.message.should.equal('getBlockError');
|
||||
|
@ -165,21 +181,6 @@ describe('Bitcoin Chain', function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe('#_writeBlock', function() {
|
||||
it('should update hashes and call putBlock', function(done) {
|
||||
var chain = new Chain();
|
||||
chain.db = {
|
||||
putBlock: sinon.stub().callsArg(1)
|
||||
};
|
||||
chain._writeBlock({hash: 'hash', prevHash: 'prevhash'}, function(err) {
|
||||
should.not.exist(err);
|
||||
chain.db.putBlock.callCount.should.equal(1);
|
||||
chain.cache.hashes.hash.should.equal('prevhash');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#_validateBlock', function() {
|
||||
it('should call the callback', function(done) {
|
||||
var chain = new Chain();
|
||||
|
@ -193,12 +194,12 @@ describe('Bitcoin Chain', function() {
|
|||
describe('#getWeight', function() {
|
||||
var work = '000000000000000000000000000000000000000000005a7b3c42ea8b844374e9';
|
||||
var chain = new Chain();
|
||||
chain.db = {
|
||||
bitcoind: {
|
||||
getBlockIndex: sinon.stub().returns({
|
||||
chainWork: work
|
||||
})
|
||||
}
|
||||
chain.node = {};
|
||||
chain.node.db = {};
|
||||
chain.node.bitcoind = {
|
||||
getBlockIndex: sinon.stub().returns({
|
||||
chainWork: work
|
||||
})
|
||||
};
|
||||
|
||||
it('should give the weight as a BN', function(done) {
|
||||
|
@ -210,7 +211,7 @@ describe('Bitcoin Chain', function() {
|
|||
});
|
||||
|
||||
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) {
|
||||
should.exist(err);
|
||||
done();
|
||||
|
@ -232,11 +233,17 @@ describe('Bitcoin Chain', function() {
|
|||
|
||||
var db = new DB({store: memdown});
|
||||
db.getPrevHash = function(blockHash, cb) {
|
||||
cb(null, blocks[blockHash].prevHash);
|
||||
// TODO: expose prevHash as a string from bitcore
|
||||
var prevHash = BufferUtil.reverse(blocks[blockHash].header.prevHash).toString('hex');
|
||||
cb(null, prevHash);
|
||||
};
|
||||
|
||||
var node = {
|
||||
db: db
|
||||
};
|
||||
|
||||
var chain = new Chain({
|
||||
db: db,
|
||||
node: node,
|
||||
genesis: genesisBlock
|
||||
});
|
||||
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
[
|
||||
{
|
||||
"version": 1,
|
||||
"prevHash": null,
|
||||
"timestamp": "2015-04-16T20:02:24.777Z",
|
||||
"bits": 520617984,
|
||||
"nonce": 0,
|
||||
"data": ""
|
||||
},
|
||||
{
|
||||
"version": 1,
|
||||
"prevHash": "bab3003201bdf327ac03735e70a5f02968bc1e8cf74cc9045ae960c074139386",
|
||||
"timestamp": "2015-04-16T20:02:26.650Z",
|
||||
"bits": 520617984,
|
||||
"nonce": 6256,
|
||||
"data": ""
|
||||
},
|
||||
{
|
||||
"version": 1,
|
||||
"prevHash": "0002cbf2807997765971f14bdd7c748e93c315c2d3af35b85c6604126c788fa8",
|
||||
"timestamp": "2015-04-16T20:02:27.885Z",
|
||||
"bits": 520617984,
|
||||
"nonce": 12232,
|
||||
"data": ""
|
||||
},
|
||||
{
|
||||
"version": 1,
|
||||
"prevHash": "0007b3fec55496a3741caa992aac55395921a965e8cec6192659f266eec39f62",
|
||||
"timestamp": "2015-04-16T20:02:28.559Z",
|
||||
"bits": 520355840,
|
||||
"nonce": 6492,
|
||||
"data": ""
|
||||
},
|
||||
{
|
||||
"version": 1,
|
||||
"prevHash": "000002de06d8fdd4d7036fc99ddc8c9b432bfa910e0968756b988e25f7f43d8e",
|
||||
"timestamp": "2015-04-16T20:02:29.593Z",
|
||||
"bits": 520355840,
|
||||
"nonce": 9502,
|
||||
"data": ""
|
||||
},
|
||||
{
|
||||
"version": 1,
|
||||
"prevHash": "00016a5c727ef18b406b16c188af017c101f5a32c2d881e92dd7aa1746b185ea",
|
||||
"timestamp": "2015-04-16T20:02:30.713Z",
|
||||
"bits": 520355840,
|
||||
"nonce": 10586,
|
||||
"data": ""
|
||||
},
|
||||
{
|
||||
"version": 1,
|
||||
"prevHash": "00023ac90a33ce9faf07f407b525f186180c902fbb2e71c48cd73ffb25a8dc5b",
|
||||
"timestamp": "22015-04-16T20:02:31.440Z",
|
||||
"bits": 520181077,
|
||||
"nonce": 6983,
|
||||
"data": ""
|
||||
}
|
||||
]
|
|
@ -2,11 +2,13 @@
|
|||
|
||||
var should = require('chai').should();
|
||||
var sinon = require('sinon');
|
||||
var bitcoindjs = require('../');
|
||||
var DB = bitcoindjs.DB;
|
||||
var index = require('../');
|
||||
var DB = index.DB;
|
||||
var blockData = require('./data/livenet-345003.json');
|
||||
var bitcore = require('bitcore');
|
||||
var Block = bitcore.Block;
|
||||
var transactionData = require('./data/bitcoin-transactions.json');
|
||||
var errors = bitcoindjs.errors;
|
||||
var errors = index.errors;
|
||||
var memdown = require('memdown');
|
||||
var inherits = require('util').inherits;
|
||||
var BaseModule = require('../lib/module');
|
||||
|
@ -20,7 +22,8 @@ describe('Bitcoin DB', function() {
|
|||
it('should emit ready', function(done) {
|
||||
var db = new DB({store: memdown});
|
||||
db._modules = ['mod1', 'mod2'];
|
||||
db.bitcoind = {
|
||||
db.node = {};
|
||||
db.node.bitcoind = {
|
||||
on: sinon.spy()
|
||||
};
|
||||
db.addModule = sinon.spy();
|
||||
|
@ -49,7 +52,8 @@ describe('Bitcoin DB', function() {
|
|||
describe('#getTransaction', function() {
|
||||
it('will return a NotFound error', function(done) {
|
||||
var db = new DB({store: memdown});
|
||||
db.bitcoind = {
|
||||
db.node = {};
|
||||
db.node.bitcoind = {
|
||||
getTransaction: sinon.stub().callsArgWith(2, null, null)
|
||||
};
|
||||
var txid = '7426c707d0e9705bdd8158e60983e37d0f5d63529086d6672b07d9238d5aa623';
|
||||
|
@ -60,7 +64,8 @@ describe('Bitcoin DB', function() {
|
|||
});
|
||||
it('will return an error from bitcoind', function(done) {
|
||||
var db = new DB({store: memdown});
|
||||
db.bitcoind = {
|
||||
db.node = {};
|
||||
db.node.bitcoind = {
|
||||
getTransaction: sinon.stub().callsArgWith(2, new Error('test error'))
|
||||
};
|
||||
var txid = '7426c707d0e9705bdd8158e60983e37d0f5d63529086d6672b07d9238d5aa623';
|
||||
|
@ -71,7 +76,8 @@ describe('Bitcoin DB', function() {
|
|||
});
|
||||
it('will return an error from bitcoind', function(done) {
|
||||
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'))
|
||||
};
|
||||
var txid = '7426c707d0e9705bdd8158e60983e37d0f5d63529086d6672b07d9238d5aa623';
|
||||
|
@ -87,22 +93,24 @@ describe('Bitcoin DB', function() {
|
|||
|
||||
describe('#getBlock', function() {
|
||||
var db = new DB({store: memdown});
|
||||
db.bitcoind = {
|
||||
getBlock: sinon.stub().callsArgWith(1, null, new Buffer(blockData, 'hex'))
|
||||
};
|
||||
db.Block = {
|
||||
fromBuffer: sinon.stub().returns('block')
|
||||
var blockBuffer = new Buffer(blockData, 'hex');
|
||||
var expectedBlock = Block.fromBuffer(blockBuffer);
|
||||
db.node = {};
|
||||
db.node.bitcoind = {
|
||||
getBlock: sinon.stub().callsArgWith(1, null, blockBuffer)
|
||||
};
|
||||
|
||||
it('should get the block from bitcoind.js', function(done) {
|
||||
it('should get the block from bitcoin daemon', function(done) {
|
||||
db.getBlock('00000000000000000593b60d8b4f40fd1ec080bdb0817d475dae47b5f5b1f735', function(err, block) {
|
||||
should.not.exist(err);
|
||||
block.should.equal('block');
|
||||
block.hash.should.equal(expectedBlock.hash);
|
||||
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) {
|
||||
should.exist(err);
|
||||
err.message.should.equal('error');
|
||||
|
@ -124,7 +132,8 @@ describe('Bitcoin DB', function() {
|
|||
describe('#getPrevHash', function() {
|
||||
it('should return prevHash from bitcoind', function(done) {
|
||||
var db = new DB({store: memdown});
|
||||
db.bitcoind = {
|
||||
db.node = {};
|
||||
db.node.bitcoind = {
|
||||
getBlockIndex: sinon.stub().returns({
|
||||
prevHash: 'prevhash'
|
||||
})
|
||||
|
@ -139,7 +148,8 @@ describe('Bitcoin DB', function() {
|
|||
|
||||
it('should give an error if bitcoind could not find it', function(done) {
|
||||
var db = new DB({store: memdown});
|
||||
db.bitcoind = {
|
||||
db.node = {};
|
||||
db.node.bitcoind = {
|
||||
getBlockIndex: sinon.stub().returns(null)
|
||||
};
|
||||
|
||||
|
@ -160,7 +170,8 @@ describe('Bitcoin DB', function() {
|
|||
};
|
||||
|
||||
var db = new DB({store: memdown});
|
||||
db.bitcoind = {
|
||||
db.node = {};
|
||||
db.node.bitcoind = {
|
||||
getTransactionWithBlockInfo: sinon.stub().callsArgWith(2, null, info)
|
||||
};
|
||||
|
||||
|
@ -173,7 +184,8 @@ describe('Bitcoin DB', function() {
|
|||
});
|
||||
it('should give an error if one occurred', function(done) {
|
||||
var db = new DB({store: memdown});
|
||||
db.bitcoind = {
|
||||
db.node = {};
|
||||
db.node.bitcoind = {
|
||||
getTransactionWithBlockInfo: sinon.stub().callsArgWith(2, new Error('error'))
|
||||
};
|
||||
|
||||
|
@ -187,7 +199,8 @@ describe('Bitcoin DB', function() {
|
|||
describe('#sendTransaction', function() {
|
||||
it('should give the txid on success', function(done) {
|
||||
var db = new DB({store: memdown});
|
||||
db.bitcoind = {
|
||||
db.node = {};
|
||||
db.node.bitcoind = {
|
||||
sendTransaction: sinon.stub().returns('txid')
|
||||
};
|
||||
|
||||
|
@ -200,7 +213,8 @@ describe('Bitcoin DB', function() {
|
|||
});
|
||||
it('should give an error if bitcoind threw an error', function(done) {
|
||||
var db = new DB({store: memdown});
|
||||
db.bitcoind = {
|
||||
db.node = {};
|
||||
db.node.bitcoind = {
|
||||
sendTransaction: sinon.stub().throws(new Error('error'))
|
||||
};
|
||||
|
||||
|
@ -215,14 +229,15 @@ describe('Bitcoin DB', function() {
|
|||
describe("#estimateFee", function() {
|
||||
it('should pass along the fee from bitcoind', function(done) {
|
||||
var db = new DB({store: memdown});
|
||||
db.bitcoind = {
|
||||
db.node = {};
|
||||
db.node.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);
|
||||
db.node.bitcoind.estimateFee.args[0][0].should.equal(5);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -390,11 +405,14 @@ describe('Bitcoin DB', function() {
|
|||
inherits(Module1, BaseModule);
|
||||
|
||||
var db = new DB({store: memdown});
|
||||
var node = {};
|
||||
db.node = node;
|
||||
db.modules = [];
|
||||
db.addModule(Module1);
|
||||
|
||||
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() {
|
||||
|
|
|
@ -16,11 +16,18 @@ var mockdb = {
|
|||
}
|
||||
};
|
||||
|
||||
var mocknode = {
|
||||
db: mockdb,
|
||||
bitcoind: {
|
||||
on: sinon.stub()
|
||||
}
|
||||
};
|
||||
|
||||
describe('AddressModule', function() {
|
||||
|
||||
describe('#getAPIMethods', function() {
|
||||
it('should return the correct methods', function() {
|
||||
var am = new AddressModule({db: mockdb});
|
||||
var am = new AddressModule({node: mocknode});
|
||||
var methods = am.getAPIMethods();
|
||||
methods.length.should.equal(5);
|
||||
});
|
||||
|
@ -28,7 +35,7 @@ describe('AddressModule', function() {
|
|||
|
||||
describe('#getPublishEvents', 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.unsubscribe = sinon.spy();
|
||||
var events = am.getPublishEvents();
|
||||
|
@ -64,7 +71,7 @@ describe('AddressModule', function() {
|
|||
it('create a message for an address', function() {
|
||||
var txBuf = new Buffer('01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000', 'hex');
|
||||
var tx = bitcore.Transaction().fromBuffer(txBuf);
|
||||
var am = new AddressModule({db: mockdb});
|
||||
var am = new AddressModule({node: mocknode});
|
||||
var address = '12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX';
|
||||
var messages = {};
|
||||
am.transactionOutputHandler(messages, tx, 0, true);
|
||||
|
@ -80,7 +87,7 @@ describe('AddressModule', function() {
|
|||
describe('#transactionHandler', function() {
|
||||
it('will pass outputs to transactionOutputHandler and call transactionEventHandler', function() {
|
||||
var txBuf = new Buffer('01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000', 'hex');
|
||||
var am = new AddressModule({db: mockdb});
|
||||
var am = new AddressModule({node: mocknode});
|
||||
var address = '12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX';
|
||||
var message = {};
|
||||
am.transactionOutputHandler = function(messages) {
|
||||
|
@ -97,21 +104,18 @@ describe('AddressModule', function() {
|
|||
describe('#blockHandler', function() {
|
||||
var am;
|
||||
var db = {
|
||||
getTransactionsFromBlock: function() {
|
||||
return block.transactions.slice(0, 8);
|
||||
},
|
||||
bitcoind: {
|
||||
on: sinon.stub()
|
||||
}
|
||||
};
|
||||
|
||||
var block = bitcore.Block.fromString(blockData);
|
||||
var testBlock = bitcore.Block.fromString(blockData);
|
||||
|
||||
var data = [
|
||||
{
|
||||
key: {
|
||||
address: '1F1MAvhTKg2VG29w8cXsiSN2PJ8gSsrJw',
|
||||
timestamp: 1424836934000,
|
||||
timestamp: 1424836934,
|
||||
txid: 'fdbefe0d064729d85556bd3ab13c3a889b685d042499c02b4aa2064fb1e16923',
|
||||
outputIndex: 0
|
||||
},
|
||||
|
@ -129,13 +133,13 @@ describe('AddressModule', function() {
|
|||
value: {
|
||||
txid: '5780f3ee54889a0717152a01abee9a32cec1b0cdf8d5537a08c7bd9eeb6bfbca',
|
||||
inputIndex: 0,
|
||||
timestamp: 1424836934000
|
||||
timestamp: 1424836934
|
||||
}
|
||||
},
|
||||
{
|
||||
key: {
|
||||
address: '1Ep5LA4T6Y7zaBPiwruUJurjGFvCJHzJhm',
|
||||
timestamp: 1424836934000,
|
||||
timestamp: 1424836934,
|
||||
txid: 'e66f3b989c790178de2fc1a5329f94c0d8905d0d3df4e7ecf0115e7f90a6283d',
|
||||
outputIndex: 1
|
||||
},
|
||||
|
@ -154,11 +158,19 @@ describe('AddressModule', function() {
|
|||
var value64 = data[2].value;
|
||||
|
||||
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) {
|
||||
am.blockHandler({__height: 345003, timestamp: new Date(1424836934000)}, true, function(err, operations) {
|
||||
var block = {
|
||||
__height: 345003,
|
||||
header: {
|
||||
timestamp: 1424836934
|
||||
},
|
||||
transactions: testBlock.transactions.slice(0, 8)
|
||||
};
|
||||
|
||||
am.blockHandler(block, true, function(err, operations) {
|
||||
should.not.exist(err);
|
||||
operations.length.should.equal(81);
|
||||
operations[0].type.should.equal('put');
|
||||
|
@ -177,7 +189,14 @@ describe('AddressModule', function() {
|
|||
});
|
||||
});
|
||||
it('should create the correct operations when removing outputs', function(done) {
|
||||
am.blockHandler({__height: 345003, timestamp: new Date(1424836934000)}, false, function(err, operations) {
|
||||
var block = {
|
||||
__height: 345003,
|
||||
header: {
|
||||
timestamp: 1424836934
|
||||
},
|
||||
transactions: testBlock.transactions.slice(0, 8)
|
||||
};
|
||||
am.blockHandler(block, false, function(err, operations) {
|
||||
should.not.exist(err);
|
||||
operations.length.should.equal(81);
|
||||
operations[0].type.should.equal('del');
|
||||
|
@ -193,53 +212,66 @@ describe('AddressModule', function() {
|
|||
});
|
||||
});
|
||||
it('should continue if output script is null', function(done) {
|
||||
var transactions = [
|
||||
{
|
||||
inputs: [],
|
||||
outputs: [
|
||||
{
|
||||
script: null,
|
||||
satoshis: 1000,
|
||||
}
|
||||
],
|
||||
isCoinbase: sinon.stub().returns(false)
|
||||
}
|
||||
];
|
||||
var db = {
|
||||
getTransactionsFromBlock: function() {
|
||||
return transactions;
|
||||
},
|
||||
bitcoind: {
|
||||
on: sinon.stub()
|
||||
}
|
||||
};
|
||||
|
||||
var am = new AddressModule({db: db, network: 'livenet'});
|
||||
var am = new AddressModule({node: mocknode, network: 'livenet'});
|
||||
|
||||
am.blockHandler({__height: 345003, timestamp: new Date(1424836934000)}, false, function(err, operations) {
|
||||
var block = {
|
||||
__height: 345003,
|
||||
header: {
|
||||
timestamp: 1424836934
|
||||
},
|
||||
transactions: [
|
||||
{
|
||||
inputs: [],
|
||||
outputs: [
|
||||
{
|
||||
script: null,
|
||||
satoshis: 1000,
|
||||
}
|
||||
],
|
||||
isCoinbase: sinon.stub().returns(false)
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
am.blockHandler(block, false, function(err, operations) {
|
||||
should.not.exist(err);
|
||||
operations.length.should.equal(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('will call event handlers', function() {
|
||||
var block = bitcore.Block.fromString(blockData);
|
||||
var testBlock = bitcore.Block.fromString(blockData);
|
||||
var db = {
|
||||
getTransactionsFromBlock: function() {
|
||||
return block.transactions.slice(0, 8);
|
||||
},
|
||||
bitcoind: {
|
||||
on: sinon.stub()
|
||||
}
|
||||
};
|
||||
var testnode = {
|
||||
db: db,
|
||||
bitcoind: {
|
||||
on: sinon.stub()
|
||||
}
|
||||
};
|
||||
var am = new AddressModule({db: db, network: 'livenet'});
|
||||
var am = new AddressModule({node: testnode, network: 'livenet'});
|
||||
am.transactionEventHandler = sinon.spy();
|
||||
am.balanceEventHandler = sinon.spy();
|
||||
am.blockHandler(
|
||||
{
|
||||
__height: 345003,
|
||||
timestamp: new Date(1424836934000)
|
||||
|
||||
var block = {
|
||||
__height: 345003,
|
||||
header: {
|
||||
timestamp: 1424836934
|
||||
},
|
||||
transactions: testBlock.transactions.slice(0, 8)
|
||||
};
|
||||
|
||||
am.blockHandler(
|
||||
block,
|
||||
true,
|
||||
function(err) {
|
||||
if (err) {
|
||||
|
@ -254,7 +286,7 @@ describe('AddressModule', function() {
|
|||
|
||||
describe('#transactionEventHandler', function() {
|
||||
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();
|
||||
am.subscriptions['address/transaction'] = {
|
||||
'1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N': [emitter]
|
||||
|
@ -284,7 +316,7 @@ describe('AddressModule', function() {
|
|||
|
||||
describe('#balanceEventHandler', function() {
|
||||
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();
|
||||
am.subscriptions['address/balance'] = {
|
||||
'1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N': [emitter]
|
||||
|
@ -304,7 +336,7 @@ describe('AddressModule', function() {
|
|||
|
||||
describe('#subscribe', 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 address = '1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N';
|
||||
|
@ -321,7 +353,7 @@ describe('AddressModule', function() {
|
|||
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 am = new AddressModule({node: mocknode});
|
||||
var emitter = new EventEmitter();
|
||||
var name = 'address/balance';
|
||||
var address = '1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N';
|
||||
|
@ -340,7 +372,7 @@ describe('AddressModule', function() {
|
|||
|
||||
describe('#unsubscribe', 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 emitter2 = new EventEmitter();
|
||||
var address = '1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N';
|
||||
|
@ -350,7 +382,7 @@ describe('AddressModule', function() {
|
|||
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 am = new AddressModule({node: mocknode});
|
||||
var emitter = new EventEmitter();
|
||||
var emitter2 = new EventEmitter();
|
||||
var address = '1DzjESe6SLmAKVPLFMj6Sx1sWki3qt5i8N';
|
||||
|
@ -360,7 +392,7 @@ describe('AddressModule', function() {
|
|||
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 am = new AddressModule({node: mocknode});
|
||||
var emitter = new EventEmitter();
|
||||
var emitter2 = new EventEmitter();
|
||||
am.subscriptions['address/balance'] = {
|
||||
|
@ -377,7 +409,7 @@ describe('AddressModule', function() {
|
|||
|
||||
describe('#getBalance', function() {
|
||||
it('should sum up the unspent outputs', function(done) {
|
||||
var am = new AddressModule({db: mockdb});
|
||||
var am = new AddressModule({node: mocknode});
|
||||
var outputs = [
|
||||
{satoshis: 1000}, {satoshis: 2000}, {satoshis: 3000}
|
||||
];
|
||||
|
@ -390,7 +422,7 @@ describe('AddressModule', function() {
|
|||
});
|
||||
|
||||
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.getBalance('someaddress', false, function(err) {
|
||||
should.exist(err);
|
||||
|
@ -404,24 +436,26 @@ describe('AddressModule', function() {
|
|||
describe('#getOutputs', function() {
|
||||
var am;
|
||||
var address = '1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W';
|
||||
var db = {
|
||||
bitcoind: {
|
||||
on: sinon.stub()
|
||||
},
|
||||
var db = {};
|
||||
var testnode = {
|
||||
chain: {
|
||||
tip: {
|
||||
__height: 1
|
||||
}
|
||||
},
|
||||
db: db,
|
||||
bitcoind: {
|
||||
on: sinon.stub()
|
||||
}
|
||||
};
|
||||
|
||||
before(function() {
|
||||
am = new AddressModule({db: db});
|
||||
am = new AddressModule({node: testnode});
|
||||
});
|
||||
|
||||
it('should get outputs for an address', function(done) {
|
||||
var readStream1 = new EventEmitter();
|
||||
am.db.store = {
|
||||
am.node.db.store = {
|
||||
createReadStream: sinon.stub().returns(readStream1)
|
||||
};
|
||||
var mempoolOutputs = [
|
||||
|
@ -433,7 +467,7 @@ describe('AddressModule', function() {
|
|||
blockHeight: 352532
|
||||
}
|
||||
];
|
||||
am.db.bitcoind = {
|
||||
am.node.bitcoind = {
|
||||
getMempoolOutputs: sinon.stub().returns(mempoolOutputs)
|
||||
};
|
||||
|
||||
|
@ -476,7 +510,7 @@ describe('AddressModule', function() {
|
|||
|
||||
it('should give an error if the readstream has an error', function(done) {
|
||||
var readStream2 = new EventEmitter();
|
||||
am.db.store = {
|
||||
am.node.db.store = {
|
||||
createReadStream: sinon.stub().returns(readStream2)
|
||||
};
|
||||
|
||||
|
@ -506,7 +540,13 @@ describe('AddressModule', function() {
|
|||
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) {
|
||||
var result = addresses[address];
|
||||
if(result instanceof Error) {
|
||||
|
@ -534,7 +574,13 @@ describe('AddressModule', function() {
|
|||
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) {
|
||||
var result = addresses[address];
|
||||
if(result instanceof Error) {
|
||||
|
@ -563,7 +609,13 @@ describe('AddressModule', function() {
|
|||
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) {
|
||||
var result = addresses[address];
|
||||
if(result instanceof Error) {
|
||||
|
@ -599,7 +651,7 @@ describe('AddressModule', function() {
|
|||
];
|
||||
var i = 0;
|
||||
|
||||
var am = new AddressModule({db: mockdb});
|
||||
var am = new AddressModule({node: mocknode});
|
||||
am.getOutputs = sinon.stub().callsArgWith(2, null, outputs);
|
||||
am.isUnspent = function(output, queryMempool, callback) {
|
||||
callback(!outputs[i].spent);
|
||||
|
@ -615,7 +667,7 @@ describe('AddressModule', function() {
|
|||
});
|
||||
});
|
||||
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.getUnspentOutputsForAddress('1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W', false, function(err, outputs) {
|
||||
should.exist(err);
|
||||
|
@ -624,7 +676,7 @@ describe('AddressModule', function() {
|
|||
});
|
||||
});
|
||||
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.getUnspentOutputsForAddress('1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W', false, function(err, outputs) {
|
||||
should.exist(err);
|
||||
|
@ -639,7 +691,7 @@ describe('AddressModule', function() {
|
|||
var am;
|
||||
|
||||
before(function() {
|
||||
am = new AddressModule({db: mockdb});
|
||||
am = new AddressModule({node: mocknode});
|
||||
});
|
||||
|
||||
it('should give true when isSpent() gives false', function(done) {
|
||||
|
@ -674,9 +726,15 @@ describe('AddressModule', function() {
|
|||
on: sinon.stub()
|
||||
}
|
||||
};
|
||||
var testnode = {
|
||||
db: db,
|
||||
bitcoind: {
|
||||
on: sinon.stub()
|
||||
}
|
||||
};
|
||||
before(function() {
|
||||
am = new AddressModule({db: db});
|
||||
am.db.bitcoind = {
|
||||
am = new AddressModule({node: testnode});
|
||||
am.node.bitcoind = {
|
||||
isSpent: sinon.stub().returns(true),
|
||||
on: sinon.stub()
|
||||
};
|
||||
|
@ -695,12 +753,15 @@ describe('AddressModule', function() {
|
|||
var db = {
|
||||
store: {
|
||||
get: sinon.stub().callsArgWith(1, null, 'spendtxid:1')
|
||||
},
|
||||
}
|
||||
};
|
||||
var testnode = {
|
||||
db: db,
|
||||
bitcoind: {
|
||||
on: sinon.stub()
|
||||
}
|
||||
};
|
||||
var am = new AddressModule({db: db});
|
||||
var am = new AddressModule({node: testnode});
|
||||
am.getSpendInfoForOutput('txid', 3, function(err, info) {
|
||||
should.not.exist(err);
|
||||
info.txid.should.equal('spendtxid');
|
||||
|
@ -805,17 +866,20 @@ describe('AddressModule', function() {
|
|||
}
|
||||
}
|
||||
callback(new Error('tx ' + txid + ' not found'));
|
||||
},
|
||||
bitcoind: {
|
||||
on: sinon.stub()
|
||||
},
|
||||
}
|
||||
};
|
||||
var testnode = {
|
||||
chain: {
|
||||
tip: {
|
||||
__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.getSpendInfoForOutput = function(txid, outputIndex, callback) {
|
||||
|
|
|
@ -5,8 +5,9 @@ var sinon = require('sinon');
|
|||
var EventEmitter = require('events').EventEmitter;
|
||||
var bitcore = require('bitcore');
|
||||
var Networks = bitcore.Networks;
|
||||
var BufferUtil = bitcore.util.buffer;
|
||||
var Block = bitcore.Block;
|
||||
var blockData = require('./data/livenet-345003.json');
|
||||
var Block = require('../lib/block');
|
||||
var proxyquire = require('proxyquire');
|
||||
var index = require('..');
|
||||
var fs = require('fs');
|
||||
|
@ -18,6 +19,14 @@ describe('Bitcoind Node', function() {
|
|||
var Node;
|
||||
var BadNode;
|
||||
|
||||
function hexlebuf(hexString){
|
||||
return BufferUtil.reverse(new Buffer(hexString, 'hex'));
|
||||
}
|
||||
|
||||
function lebufhex(buf) {
|
||||
return BufferUtil.reverse(buf).toString('hex');
|
||||
}
|
||||
|
||||
before(function() {
|
||||
|
||||
BadNode = proxyquire('../lib/node', {
|
||||
|
@ -154,29 +163,45 @@ describe('Bitcoind Node', function() {
|
|||
}
|
||||
};
|
||||
var expectedAncestor = chainHashes[chainHashes.length - 6];
|
||||
|
||||
var forkedBlocks = {
|
||||
'd7fa6f3d5b2fe35d711e6aca5530d311b8c6e45f588a65c642b8baf4b4441d82': {
|
||||
prevHash: '76d920dbd83beca9fa8b2f346d5c5a81fe4a350f4b355873008229b1e6f8701a'
|
||||
header: {
|
||||
prevHash: hexlebuf('76d920dbd83beca9fa8b2f346d5c5a81fe4a350f4b355873008229b1e6f8701a')
|
||||
}
|
||||
},
|
||||
'76d920dbd83beca9fa8b2f346d5c5a81fe4a350f4b355873008229b1e6f8701a': {
|
||||
prevHash: 'f0a0d76a628525243c8af7606ee364741ccd5881f0191bbe646c8a4b2853e60c'
|
||||
header: {
|
||||
prevHash: hexlebuf('f0a0d76a628525243c8af7606ee364741ccd5881f0191bbe646c8a4b2853e60c')
|
||||
}
|
||||
},
|
||||
'f0a0d76a628525243c8af7606ee364741ccd5881f0191bbe646c8a4b2853e60c': {
|
||||
prevHash: '2f72b809d5ccb750c501abfdfa8c4c4fad46b0b66c088f0568d4870d6f509c31'
|
||||
header: {
|
||||
prevHash: hexlebuf('2f72b809d5ccb750c501abfdfa8c4c4fad46b0b66c088f0568d4870d6f509c31')
|
||||
}
|
||||
},
|
||||
'2f72b809d5ccb750c501abfdfa8c4c4fad46b0b66c088f0568d4870d6f509c31': {
|
||||
prevHash: 'adf66e6ae10bc28fc22bc963bf43e6b53ef4429269bdb65038927acfe66c5453'
|
||||
header: {
|
||||
prevHash: hexlebuf('adf66e6ae10bc28fc22bc963bf43e6b53ef4429269bdb65038927acfe66c5453')
|
||||
}
|
||||
},
|
||||
'adf66e6ae10bc28fc22bc963bf43e6b53ef4429269bdb65038927acfe66c5453': {
|
||||
prevHash: '3ea12707e92eed024acf97c6680918acc72560ec7112cf70ac213fb8bb4fa618'
|
||||
header: {
|
||||
prevHash: hexlebuf('3ea12707e92eed024acf97c6680918acc72560ec7112cf70ac213fb8bb4fa618')
|
||||
}
|
||||
},
|
||||
'3ea12707e92eed024acf97c6680918acc72560ec7112cf70ac213fb8bb4fa618': {
|
||||
prevHash: expectedAncestor
|
||||
header: {
|
||||
prevHash: hexlebuf(expectedAncestor)
|
||||
}
|
||||
},
|
||||
};
|
||||
node.bitcoind = {
|
||||
getBlockIndex: function(hash) {
|
||||
return forkedBlocks[hash];
|
||||
var block = forkedBlocks[hash];
|
||||
return {
|
||||
prevHash: BufferUtil.reverse(block.header.prevHash).toString('hex')
|
||||
};
|
||||
}
|
||||
};
|
||||
var block = forkedBlocks['d7fa6f3d5b2fe35d711e6aca5530d311b8c6e45f588a65c642b8baf4b4441d82'];
|
||||
|
@ -196,7 +221,9 @@ describe('Bitcoind Node', function() {
|
|||
tip: {
|
||||
__height: 10,
|
||||
hash: chainHashes[chainHashes.length],
|
||||
prevHash: chainHashes[chainHashes.length - 1]
|
||||
header: {
|
||||
prevHash: hexlebuf(chainHashes[chainHashes.length - 1])
|
||||
}
|
||||
},
|
||||
saveMetadata: sinon.stub(),
|
||||
emit: sinon.stub()
|
||||
|
@ -204,11 +231,14 @@ describe('Bitcoind Node', function() {
|
|||
node.getBlock = function(hash, callback) {
|
||||
setImmediate(function() {
|
||||
for(var i = chainHashes.length; i > 0; i--) {
|
||||
var block = {
|
||||
hash: chainHashes[i],
|
||||
header: {
|
||||
prevHash: hexlebuf(chainHashes[i - 1])
|
||||
}
|
||||
};
|
||||
if (chainHashes[i] === hash) {
|
||||
callback(null, {
|
||||
hash: chainHashes[i],
|
||||
prevHash: chainHashes[i - 1]
|
||||
});
|
||||
callback(null, block);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -236,8 +266,7 @@ describe('Bitcoind Node', function() {
|
|||
describe('#_syncBitcoind', function() {
|
||||
it('will get and add block up to the tip height', function(done) {
|
||||
var node = new Node({});
|
||||
node.Block = Block;
|
||||
var blockBuffer = new Buffer(blockData);
|
||||
var blockBuffer = new Buffer(blockData, 'hex');
|
||||
var block = Block.fromBuffer(blockBuffer);
|
||||
node.bitcoind = {
|
||||
getBlock: sinon.stub().callsArgWith(1, null, blockBuffer),
|
||||
|
@ -247,7 +276,7 @@ describe('Bitcoind Node', function() {
|
|||
node.chain = {
|
||||
tip: {
|
||||
__height: 0,
|
||||
hash: block.prevHash
|
||||
hash: lebufhex(block.header.prevHash)
|
||||
},
|
||||
getHashes: sinon.stub().callsArgWith(1, null),
|
||||
saveMetadata: sinon.stub(),
|
||||
|
@ -286,8 +315,7 @@ describe('Bitcoind Node', function() {
|
|||
});
|
||||
it('will stop syncing when the node is stopping', function(done) {
|
||||
var node = new Node({});
|
||||
node.Block = Block;
|
||||
var blockBuffer = new Buffer(blockData);
|
||||
var blockBuffer = new Buffer(blockData, 'hex');
|
||||
var block = Block.fromBuffer(blockBuffer);
|
||||
node.bitcoind = {
|
||||
getBlock: sinon.stub().callsArgWith(1, null, blockBuffer),
|
||||
|
@ -451,7 +479,6 @@ describe('Bitcoind Node', function() {
|
|||
|
||||
it('will set properties', function() {
|
||||
node._loadConsensus();
|
||||
should.exist(node.Block);
|
||||
should.exist(node.chain);
|
||||
});
|
||||
|
||||
|
@ -501,13 +528,6 @@ describe('Bitcoind Node', function() {
|
|||
|
||||
node._initialize();
|
||||
|
||||
// references
|
||||
node.db.chain.should.equal(node.chain);
|
||||
node.db.Block.should.equal(node.Block);
|
||||
node.db.bitcoind.should.equal(node.bitcoind);
|
||||
node.chain.db.should.equal(node.db);
|
||||
node.chain.db.should.equal(node.db);
|
||||
|
||||
// event handlers
|
||||
node._initializeBitcoind.callCount.should.equal(1);
|
||||
node._initializeDatabase.callCount.should.equal(1);
|
||||
|
|
Loading…
Reference in New Issue