Address: Added unit tests for new mempool index methods
This commit is contained in:
parent
89ef28f0b7
commit
5ac3b1c61f
@ -7,6 +7,8 @@ var bitcorenode = require('../../../');
|
|||||||
var AddressService = bitcorenode.services.Address;
|
var AddressService = bitcorenode.services.Address;
|
||||||
var blockData = require('../../data/livenet-345003.json');
|
var blockData = require('../../data/livenet-345003.json');
|
||||||
var bitcore = require('bitcore-lib');
|
var bitcore = require('bitcore-lib');
|
||||||
|
var memdown = require('memdown');
|
||||||
|
var leveldown = require('leveldown');
|
||||||
var Script = bitcore.Script;
|
var Script = bitcore.Script;
|
||||||
var Address = bitcore.Address;
|
var Address = bitcore.Address;
|
||||||
var Networks = bitcore.Networks;
|
var Networks = bitcore.Networks;
|
||||||
@ -31,6 +33,258 @@ var mocknode = {
|
|||||||
|
|
||||||
describe('Address Service', function() {
|
describe('Address Service', function() {
|
||||||
var txBuf = new Buffer(txData[0], 'hex');
|
var txBuf = new Buffer(txData[0], 'hex');
|
||||||
|
|
||||||
|
describe('@constructor', function() {
|
||||||
|
it('config to use memdown for mempool index', function() {
|
||||||
|
var am = new AddressService({
|
||||||
|
mempoolMemoryIndex: true,
|
||||||
|
node: mocknode
|
||||||
|
});
|
||||||
|
am.levelupStore.should.equal(memdown);
|
||||||
|
});
|
||||||
|
it('config to use leveldown for mempool index', function() {
|
||||||
|
var am = new AddressService({
|
||||||
|
node: mocknode
|
||||||
|
});
|
||||||
|
am.levelupStore.should.equal(leveldown);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#start', function() {
|
||||||
|
it('will flush existing mempool', function(done) {
|
||||||
|
var leveldownmock = {
|
||||||
|
destroy: sinon.stub().callsArgWith(1, null)
|
||||||
|
};
|
||||||
|
var TestAddressService = proxyquire('../../../lib/services/address', {
|
||||||
|
'fs': {
|
||||||
|
existsSync: sinon.stub().returns(true)
|
||||||
|
},
|
||||||
|
'leveldown': leveldownmock,
|
||||||
|
'levelup': sinon.stub().callsArgWith(2, null),
|
||||||
|
'mkdirp': sinon.stub().callsArgWith(1, null)
|
||||||
|
});
|
||||||
|
var am = new TestAddressService({
|
||||||
|
mempoolMemoryIndex: true,
|
||||||
|
node: mocknode
|
||||||
|
});
|
||||||
|
am.start(function() {
|
||||||
|
leveldownmock.destroy.callCount.should.equal(1);
|
||||||
|
leveldownmock.destroy.args[0][0].should.equal('testdir/testnet3/bitcore-addressmempool.db');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('will mkdirp if directory does not exist', function(done) {
|
||||||
|
var leveldownmock = {
|
||||||
|
destroy: sinon.stub().callsArgWith(1, null)
|
||||||
|
};
|
||||||
|
var mkdirpmock = sinon.stub().callsArgWith(1, null);
|
||||||
|
var TestAddressService = proxyquire('../../../lib/services/address', {
|
||||||
|
'fs': {
|
||||||
|
existsSync: sinon.stub().returns(false)
|
||||||
|
},
|
||||||
|
'leveldown': leveldownmock,
|
||||||
|
'levelup': sinon.stub().callsArgWith(2, null),
|
||||||
|
'mkdirp': mkdirpmock
|
||||||
|
});
|
||||||
|
var am = new TestAddressService({
|
||||||
|
mempoolMemoryIndex: true,
|
||||||
|
node: mocknode
|
||||||
|
});
|
||||||
|
am.start(function() {
|
||||||
|
mkdirpmock.callCount.should.equal(1);
|
||||||
|
mkdirpmock.args[0][0].should.equal('testdir/testnet3/bitcore-addressmempool.db');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('start levelup db for mempool index', function(done) {
|
||||||
|
var TestAddressService = proxyquire('../../../lib/services/address', {
|
||||||
|
'fs': {
|
||||||
|
existsSync: sinon.stub().returns(true)
|
||||||
|
},
|
||||||
|
'leveldown': {
|
||||||
|
destroy: sinon.stub().callsArgWith(1, null)
|
||||||
|
},
|
||||||
|
'levelup': function(dbPath, options, callback) {
|
||||||
|
dbPath.should.equal('testdir/testnet3/bitcore-addressmempool.db');
|
||||||
|
options.db.should.equal(memdown);
|
||||||
|
options.keyEncoding.should.equal('binary');
|
||||||
|
options.valueEncoding.should.equal('binary');
|
||||||
|
options.fillCache.should.equal(false);
|
||||||
|
setImmediate(callback);
|
||||||
|
},
|
||||||
|
'mkdirp': sinon.stub().callsArgWith(1, null)
|
||||||
|
});
|
||||||
|
var am = new TestAddressService({
|
||||||
|
mempoolMemoryIndex: true,
|
||||||
|
node: mocknode
|
||||||
|
});
|
||||||
|
am.start(function() {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('handle error from mkdirp', function(done) {
|
||||||
|
var TestAddressService = proxyquire('../../../lib/services/address', {
|
||||||
|
'fs': {
|
||||||
|
existsSync: sinon.stub().returns(false)
|
||||||
|
},
|
||||||
|
'leveldown': {
|
||||||
|
destroy: sinon.stub().callsArgWith(1, null)
|
||||||
|
},
|
||||||
|
'levelup': sinon.stub().callsArgWith(2, null),
|
||||||
|
'mkdirp': sinon.stub().callsArgWith(1, new Error('testerror'))
|
||||||
|
});
|
||||||
|
var am = new TestAddressService({
|
||||||
|
mempoolMemoryIndex: true,
|
||||||
|
node: mocknode
|
||||||
|
});
|
||||||
|
am.start(function(err) {
|
||||||
|
err.message.should.equal('testerror');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('handle error from levelup', function(done) {
|
||||||
|
var TestAddressService = proxyquire('../../../lib/services/address', {
|
||||||
|
'fs': {
|
||||||
|
existsSync: sinon.stub().returns(false)
|
||||||
|
},
|
||||||
|
'leveldown': {
|
||||||
|
destroy: sinon.stub().callsArgWith(1, null)
|
||||||
|
},
|
||||||
|
'levelup': sinon.stub().callsArgWith(2, new Error('leveltesterror')),
|
||||||
|
'mkdirp': sinon.stub().callsArgWith(1, null)
|
||||||
|
});
|
||||||
|
var am = new TestAddressService({
|
||||||
|
mempoolMemoryIndex: true,
|
||||||
|
node: mocknode
|
||||||
|
});
|
||||||
|
am.start(function(err) {
|
||||||
|
err.message.should.equal('leveltesterror');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('handle error from leveldown.destroy', function(done) {
|
||||||
|
var TestAddressService = proxyquire('../../../lib/services/address', {
|
||||||
|
'fs': {
|
||||||
|
existsSync: sinon.stub().returns(true)
|
||||||
|
},
|
||||||
|
'leveldown': {
|
||||||
|
destroy: sinon.stub().callsArgWith(1, new Error('destroy'))
|
||||||
|
},
|
||||||
|
'levelup': sinon.stub().callsArgWith(2, null),
|
||||||
|
'mkdirp': sinon.stub().callsArgWith(1, null)
|
||||||
|
});
|
||||||
|
var am = new TestAddressService({
|
||||||
|
mempoolMemoryIndex: true,
|
||||||
|
node: mocknode
|
||||||
|
});
|
||||||
|
am.start(function(err) {
|
||||||
|
err.message.should.equal('destroy');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#stop', function() {
|
||||||
|
it('will close mempool levelup', function(done) {
|
||||||
|
var am = new AddressService({
|
||||||
|
mempoolMemoryIndex: true,
|
||||||
|
node: mocknode
|
||||||
|
});
|
||||||
|
am.mempoolIndex = {};
|
||||||
|
am.mempoolIndex.close = sinon.stub().callsArg(0);
|
||||||
|
am.stop(function() {
|
||||||
|
am.mempoolIndex.close.callCount.should.equal(1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#_setMempoolIndexPath', function() {
|
||||||
|
it('should set the database path', function() {
|
||||||
|
var testnode = {
|
||||||
|
network: Networks.livenet,
|
||||||
|
datadir: process.env.HOME + '/.bitcoin',
|
||||||
|
services: {
|
||||||
|
bitcoind: {
|
||||||
|
on: sinon.stub()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var am = new AddressService({
|
||||||
|
mempoolMemoryIndex: true,
|
||||||
|
node: testnode
|
||||||
|
});
|
||||||
|
am._setMempoolIndexPath();
|
||||||
|
am.mempoolIndexPath.should.equal(process.env.HOME + '/.bitcoin/bitcore-addressmempool.db');
|
||||||
|
});
|
||||||
|
it('should load the db for testnet', function() {
|
||||||
|
var testnode = {
|
||||||
|
network: Networks.testnet,
|
||||||
|
datadir: process.env.HOME + '/.bitcoin',
|
||||||
|
services: {
|
||||||
|
bitcoind: {
|
||||||
|
on: sinon.stub()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var am = new AddressService({
|
||||||
|
mempoolMemoryIndex: true,
|
||||||
|
node: testnode
|
||||||
|
});
|
||||||
|
am._setMempoolIndexPath();
|
||||||
|
am.mempoolIndexPath.should.equal(process.env.HOME + '/.bitcoin/testnet3/bitcore-addressmempool.db');
|
||||||
|
});
|
||||||
|
it('error with unknown network', function() {
|
||||||
|
var testnode = {
|
||||||
|
network: 'unknown',
|
||||||
|
datadir: process.env.HOME + '/.bitcoin',
|
||||||
|
services: {
|
||||||
|
bitcoind: {
|
||||||
|
on: sinon.stub()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(function() {
|
||||||
|
var am = new AddressService({
|
||||||
|
mempoolMemoryIndex: true,
|
||||||
|
node: testnode
|
||||||
|
});
|
||||||
|
}).should.throw('Unknown network');
|
||||||
|
});
|
||||||
|
it('should load the db with regtest', function() {
|
||||||
|
// Switch to use regtest
|
||||||
|
// Networks.remove(Networks.testnet);
|
||||||
|
Networks.add({
|
||||||
|
name: 'regtest',
|
||||||
|
alias: 'regtest',
|
||||||
|
pubkeyhash: 0x6f,
|
||||||
|
privatekey: 0xef,
|
||||||
|
scripthash: 0xc4,
|
||||||
|
xpubkey: 0x043587cf,
|
||||||
|
xprivkey: 0x04358394,
|
||||||
|
networkMagic: 0xfabfb5da,
|
||||||
|
port: 18444,
|
||||||
|
dnsSeeds: [ ]
|
||||||
|
});
|
||||||
|
var regtest = Networks.get('regtest');
|
||||||
|
var testnode = {
|
||||||
|
network: regtest,
|
||||||
|
datadir: process.env.HOME + '/.bitcoin',
|
||||||
|
services: {
|
||||||
|
bitcoind: {
|
||||||
|
on: sinon.stub()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var am = new AddressService({
|
||||||
|
mempoolMemoryIndex: true,
|
||||||
|
node: testnode
|
||||||
|
});
|
||||||
|
am.mempoolIndexPath.should.equal(process.env.HOME + '/.bitcoin/regtest/bitcore-addressmempool.db');
|
||||||
|
Networks.remove(regtest);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('#getAPIMethods', function() {
|
describe('#getAPIMethods', function() {
|
||||||
it('should return the correct methods', function() {
|
it('should return the correct methods', function() {
|
||||||
var am = new AddressService({
|
var am = new AddressService({
|
||||||
@ -791,6 +1045,50 @@ describe('Address Service', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#_getSpentMempool', function() {
|
||||||
|
it('will decode data from the database', function() {
|
||||||
|
var am = new AddressService({
|
||||||
|
mempoolMemoryIndex: true,
|
||||||
|
node: mocknode
|
||||||
|
});
|
||||||
|
am.mempoolIndex = {};
|
||||||
|
var mempoolValue = Buffer.concat([
|
||||||
|
new Buffer('85630d684f1f414264f88a31bddfc79dd0c00659330dcdc393b321c121f4078b', 'hex'),
|
||||||
|
new Buffer('00000003', 'hex')
|
||||||
|
]);
|
||||||
|
am.mempoolIndex.get = sinon.stub().callsArgWith(1, null, mempoolValue);
|
||||||
|
var prevTxIdBuffer = new Buffer('e7888264d286be2da26b0a4dbd2fc5c9ece82b3e40e6791b137e4155b6da8981', 'hex');
|
||||||
|
var outputIndex = 1;
|
||||||
|
var outputIndexBuffer = new Buffer('00000001', 'hex');
|
||||||
|
var expectedKey = Buffer.concat([
|
||||||
|
new Buffer('03', 'hex'),
|
||||||
|
prevTxIdBuffer,
|
||||||
|
outputIndexBuffer
|
||||||
|
]).toString('hex');
|
||||||
|
am._getSpentMempool(prevTxIdBuffer, outputIndex, function(err, value) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
am.mempoolIndex.get.args[0][0].toString('hex').should.equal(expectedKey);
|
||||||
|
value.inputTxId.should.equal('85630d684f1f414264f88a31bddfc79dd0c00659330dcdc393b321c121f4078b');
|
||||||
|
value.inputIndex.should.equal(3);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('handle error from levelup', function() {
|
||||||
|
var am = new AddressService({
|
||||||
|
mempoolMemoryIndex: true,
|
||||||
|
node: mocknode
|
||||||
|
});
|
||||||
|
am.mempoolIndex = {};
|
||||||
|
am.mempoolIndex.get = sinon.stub().callsArgWith(1, new Error('test'));
|
||||||
|
var prevTxIdBuffer = new Buffer('e7888264d286be2da26b0a4dbd2fc5c9ece82b3e40e6791b137e4155b6da8981', 'hex');
|
||||||
|
var outputIndex = 1;
|
||||||
|
am._getSpentMempool(prevTxIdBuffer, outputIndex, function(err) {
|
||||||
|
err.message.should.equal('test');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('#getOutputs', function() {
|
describe('#getOutputs', function() {
|
||||||
var am;
|
var am;
|
||||||
var address = '1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W';
|
var address = '1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W';
|
||||||
@ -935,6 +1233,93 @@ describe('Address Service', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#_getOutputsMempool', function() {
|
||||||
|
var am;
|
||||||
|
var address = '1KiW1A4dx1oRgLHtDtBjcunUGkYtFgZ1W';
|
||||||
|
var hashBuffer = bitcore.Address(address).hashBuffer;
|
||||||
|
var db = {
|
||||||
|
tip: {
|
||||||
|
__height: 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var testnode = {
|
||||||
|
network: Networks.testnet,
|
||||||
|
datadir: 'testdir',
|
||||||
|
services: {
|
||||||
|
db: db,
|
||||||
|
bitcoind: {
|
||||||
|
on: sinon.stub()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
before(function() {
|
||||||
|
am = new AddressService({
|
||||||
|
mempoolMemoryIndex: true,
|
||||||
|
node: testnode
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('it will handle error', function(done) {
|
||||||
|
var testStream = new EventEmitter();
|
||||||
|
am.mempoolIndex = {};
|
||||||
|
am.mempoolIndex.createReadStream = sinon.stub().returns(testStream);
|
||||||
|
am._getOutputsMempool(address, hashBuffer, function(err, outputs) {
|
||||||
|
should.exist(err);
|
||||||
|
err.message.should.equal('readstreamerror');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
testStream.emit('error', new Error('readstreamerror'));
|
||||||
|
setImmediate(function() {
|
||||||
|
testStream.emit('close');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('it will parse data', function(done) {
|
||||||
|
var testStream = new EventEmitter();
|
||||||
|
am.mempoolIndex = {};
|
||||||
|
am.mempoolIndex.createReadStream = sinon.stub().returns(testStream);
|
||||||
|
|
||||||
|
am._getOutputsMempool(address, hashBuffer, function(err, outputs) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
outputs.length.should.equal(1);
|
||||||
|
outputs[0].address.should.equal(address);
|
||||||
|
outputs[0].txid.should.equal(txid);
|
||||||
|
outputs[0].outputIndex.should.equal(outputIndex);
|
||||||
|
outputs[0].height.should.equal(-1);
|
||||||
|
outputs[0].satoshis.should.equal(3);
|
||||||
|
outputs[0].script.should.equal('ac');
|
||||||
|
outputs[0].confirmations.should.equal(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
var txid = '5d32f0fff6871c377e00c16f48ebb5e89c723d0b9dd25f68fdda70c3392bee61';
|
||||||
|
var txidBuffer = new Buffer(txid, 'hex');
|
||||||
|
var outputIndex = 3;
|
||||||
|
var outputIndexBuffer = new Buffer(4);
|
||||||
|
outputIndexBuffer.writeUInt32BE(outputIndex);
|
||||||
|
var keyData = Buffer.concat([
|
||||||
|
new Buffer('01', 'hex'),
|
||||||
|
hashBuffer,
|
||||||
|
txidBuffer,
|
||||||
|
outputIndexBuffer
|
||||||
|
]);
|
||||||
|
|
||||||
|
var valueData = Buffer.concat([
|
||||||
|
new Buffer('4008000000000000', 'hex'),
|
||||||
|
new Buffer('ac', 'hex')
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Note: key is not used currently
|
||||||
|
testStream.emit('data', {
|
||||||
|
key: keyData,
|
||||||
|
value: valueData
|
||||||
|
});
|
||||||
|
setImmediate(function() {
|
||||||
|
testStream.emit('close');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('#getUnspentOutputs', function() {
|
describe('#getUnspentOutputs', function() {
|
||||||
it('should concatenate utxos for multiple addresses, even those with none found', function(done) {
|
it('should concatenate utxos for multiple addresses, even those with none found', function(done) {
|
||||||
var addresses = {
|
var addresses = {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user