fix address regressions

This commit is contained in:
Manuel Araoz 2015-04-30 08:59:28 -03:00
parent 85ad9fcdb6
commit 671665c052
4 changed files with 178 additions and 103 deletions

View File

@ -5,8 +5,6 @@ var _ = bitcore.deps._;
var $ = bitcore.util.preconditions; var $ = bitcore.util.preconditions;
var Address = bitcore.Address; var Address = bitcore.Address;
var BitcoreNode = require('../../');
var Addresses = {}; var Addresses = {};
var node; var node;

View File

@ -11,17 +11,11 @@ var _ = bitcore.deps._;
var mockAddresses = require('../data/addresses'); var mockAddresses = require('../data/addresses');
var mockTransactions = require('../data/transactions');
describe('BitcoreHTTP v1 addresses routes', function() { describe('BitcoreHTTP v1 addresses routes', function() {
// mocks // mocks
var transactionList = _.values(mockTransactions);
var nodeMock, agent; var nodeMock, agent;
var txs_for_addr = function(addr) {
var amount = mockAddresses[addr].summary.transactions.length;
return transactionList.slice(0, amount);
};
var utxos_for_addrs = function(addrs) { var utxos_for_addrs = function(addrs) {
return _.reduce(addrs, function(utxos, addr) { return _.reduce(addrs, function(utxos, addr) {
return utxos.concat(mockAddresses[addr].utxos); return utxos.concat(mockAddresses[addr].utxos);
@ -53,10 +47,7 @@ describe('BitcoreHTTP v1 addresses routes', function() {
nodeMock.addressService.getSummary = function(address) { nodeMock.addressService.getSummary = function(address) {
return Promise.resolve(mockAddresses[address.toString()].summary); return Promise.resolve(mockAddresses[address.toString()].summary);
}; };
nodeMock.listTransactions = function(opts) { nodeMock.addressService.getUnspent = function(addresses) {
return Promise.resolve(txs_for_addr(opts.address));
};
nodeMock.getUTXOs = function(addresses) {
return Promise.resolve(utxos_for_addrs(addresses)); return Promise.resolve(utxos_for_addrs(addresses));
}; };
agent = require('../app')(nodeMock); agent = require('../app')(nodeMock);
@ -77,19 +68,7 @@ describe('BitcoreHTTP v1 addresses routes', function() {
it('works with valid address ' + addr, function(cb) { it('works with valid address ' + addr, function(cb) {
agent.get('/v1/addresses/' + addr) agent.get('/v1/addresses/' + addr)
.expect(200) .expect(200)
.expect(JSON.stringify(info.summary), cb); .expect(info.summary, cb);
});
});
});
describe('/addresses/:address/transactions', function() {
it('fails with invalid address', function(cb) {
failsWithInvalidAddress(agent, '/v1/addresses/1BpbpfLdY7oBS9gK7aDXgvMgr1DpvNH3B2/transactions', cb);
});
_.keys(mockAddresses).forEach(function(addr) {
it('works with valid address ' + addr, function(cb) {
agent.get('/v1/addresses/' + addr + '/transactions')
.expect(200)
.expect(JSON.stringify(txs_for_addr(addr)), cb);
}); });
}); });
}); });
@ -104,7 +83,7 @@ describe('BitcoreHTTP v1 addresses routes', function() {
it('works with valid address ' + addr, function(cb) { it('works with valid address ' + addr, function(cb) {
agent.get('/v1/addresses/' + addr + '/utxos') agent.get('/v1/addresses/' + addr + '/utxos')
.expect(200) .expect(200)
.expect(JSON.stringify(utxos_for_addrs([addr])), cb); .expect(utxos_for_addrs([addr]), cb);
}); });
}); });
}); });
@ -118,7 +97,7 @@ describe('BitcoreHTTP v1 addresses routes', function() {
var path = '/v1/addresses/' + list + '/utxos'; var path = '/v1/addresses/' + list + '/utxos';
agent.get(path) agent.get(path)
.expect(200) .expect(200)
.expect(JSON.stringify(utxos_for_addrs(addresses)), cb); .expect(utxos_for_addrs(addresses), cb);
}); });
}); });
}); });

View File

@ -3,7 +3,6 @@
var Promise = require('bluebird'); var Promise = require('bluebird');
var bitcore = require('bitcore'); var bitcore = require('bitcore');
var TransactionService = require('./transaction'); var TransactionService = require('./transaction');
var RPC = require('bitcoind-rpc');
var _ = bitcore.deps._; var _ = bitcore.deps._;
var $ = bitcore.util.preconditions; var $ = bitcore.util.preconditions;
@ -15,8 +14,8 @@ function AddressService(opts) {
opts = _.extend({}, opts); opts = _.extend({}, opts);
this.transactionService = opts.transactionService; this.transactionService = opts.transactionService;
this.blockService = opts.blockService; this.blockService = opts.blockService;
this.database = opts.database || Promise.promisifyAll(new LevelUp(config.get('LevelUp'))); this.database = opts.database;
this.rpc = opts.rpc || Promise.promisifyAll(new RPC(config.get('RPC'))); this.rpc = opts.rpc;
} }
AddressService.prototype.getSummary = function(address, confirmations) { AddressService.prototype.getSummary = function(address, confirmations) {

View File

@ -6,7 +6,6 @@ var events = require('events');
var Promise = require('bluebird'); var Promise = require('bluebird');
var bitcore = require('bitcore'); var bitcore = require('bitcore');
var _ = bitcore.deps._;
var AddressService = require('../../lib/services/address'); var AddressService = require('../../lib/services/address');
@ -43,7 +42,9 @@ describe('AddressService', function() {
beforeEach(initialize); beforeEach(initialize);
it('calls internal functions as expected', function(done) { it('calls internal functions as expected', function(done) {
service.blockService = { getLatest: sinon.mock() }; service.blockService = {
getLatest: sinon.mock()
};
service.getAllOutputs = sinon.mock(); service.getAllOutputs = sinon.mock();
service.getSpent = sinon.mock(); service.getSpent = sinon.mock();
service.buildAddressSummary = sinon.mock(); service.buildAddressSummary = sinon.mock();
@ -105,17 +106,16 @@ describe('AddressService', function() {
AddressService.processOutput = sinon.stub(AddressService, 'processOutput'); AddressService.processOutput = sinon.stub(AddressService, 'processOutput');
AddressService.processOutput.onFirstCall().returns('processed'); AddressService.processOutput.onFirstCall().returns('processed');
var element = {key: 'key', value: 'value'}; var element = {
key: 'key',
value: 'value'
};
var address = '12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S'; var address = '12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S';
service.getAllOutputs(address).then(function(arg) { service.getAllOutputs(address).then(function(arg) {
service.database.createReadStream.firstCall.args[0].should.deep.equal( service.database.createReadStream.firstCall.args[0].should.deep.equal({
{ gte: 'txa-12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S-' + '0000000000000000000000000000000000000000000000000000000000000000-0',
gte: 'txa-12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S-' lte: 'txa-12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S-' + 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff-4294967295'
+ '0000000000000000000000000000000000000000000000000000000000000000-0', });
lte: 'txa-12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S-'
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff-4294967295'
}
);
AddressService.processOutput.firstCall.args[0].should.equal(element); AddressService.processOutput.firstCall.args[0].should.equal(element);
AddressService.processOutput.reset(); AddressService.processOutput.reset();
arg[0].should.equal('processed'); arg[0].should.equal('processed');
@ -131,20 +131,23 @@ describe('AddressService', function() {
var dataCall = new events.EventEmitter(); var dataCall = new events.EventEmitter();
service.database.createReadStream.onFirstCall().returns(dataCall); service.database.createReadStream.onFirstCall().returns(dataCall);
var element = {key: 'key', value: JSON.stringify({a: 'b'})}; var element = {
key: 'key',
value: JSON.stringify({
a: 'b'
})
};
var address = '12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S'; var address = '12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S';
service.getSpent(address).then(function(arg) { service.getSpent(address)
service.database.createReadStream.firstCall.args[0].should.deep.equal( .then(function(arg) {
{ service.database.createReadStream.firstCall.args[0].should.deep.equal({
gte: 'txas-12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S-' gte: 'txas-12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S-' + '0000000000000000000000000000000000000000000000000000000000000000-0',
+ '0000000000000000000000000000000000000000000000000000000000000000-0', lte: 'txas-12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S-' + 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff-4294967295'
lte: 'txas-12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S-' });
+ 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff-4294967295' console.log(arguments);
} arg[0].should.deep.equal('processed');
); done();
arg[0].should.deep.equal({a: 'b'}); });
done();
});
dataCall.emit('data', element); dataCall.emit('data', element);
dataCall.emit('end'); dataCall.emit('end');
@ -158,107 +161,203 @@ describe('AddressService', function() {
var tip = { var tip = {
height: 10 height: 10
}; };
var allOutputs = [ var allOutputs = [{
{ satoshis: 10,
txId: 'A',
outputIndex: 1,
heightConfirmed: 1
}];
it('calculates balance correctly for confirmed balance', function() {
var allOutputs = [{
satoshis: 10, satoshis: 10,
txId: 'A', txId: 'A',
outputIndex: 1, outputIndex: 1,
heightConfirmed: 1 heightConfirmed: 1
} }];
];
it('calculates balance correctly for confirmed balance', function() {
var allOutputs = [ { satoshis: 10, txId: 'A', outputIndex: 1, heightConfirmed: 1 } ];
var spendOutputs = []; var spendOutputs = [];
service.buildAddressSummary(address, tip, allOutputs, spendOutputs).should.deep.equal({ service.buildAddressSummary(address, tip, allOutputs, spendOutputs).should.deep.equal({
address: address.toString(), address: address.toString(),
transactions: ['A'], transactions: ['A'],
confirmed: { balance: 10, sent: 0, received: 10 }, confirmed: {
unconfirmed: { balance: 10, sent: 0, received: 10 } balance: 10,
sent: 0,
received: 10
},
unconfirmed: {
balance: 10,
sent: 0,
received: 10
}
}); });
}); });
it('calculates balance correctly for unconfirmed balance', function() { it('calculates balance correctly for unconfirmed balance', function() {
var allOutputs = [ var allOutputs = [{
{ satoshis: 20, txId: 'B', outputIndex: 1, heightConfirmed: 10 } satoshis: 20,
]; txId: 'B',
var spendOutputs = [ ]; outputIndex: 1,
heightConfirmed: 10
}];
var spendOutputs = [];
service.buildAddressSummary(address, tip, allOutputs, spendOutputs).should.deep.equal({ service.buildAddressSummary(address, tip, allOutputs, spendOutputs).should.deep.equal({
address: address.toString(), address: address.toString(),
transactions: ['B'], transactions: ['B'],
confirmed: { balance: 0, sent: 0, received: 0 }, confirmed: {
unconfirmed: { balance: 20, sent: 0, received: 20 } balance: 0,
sent: 0,
received: 0
},
unconfirmed: {
balance: 20,
sent: 0,
received: 20
}
}); });
}); });
it('works with multiple transactions', function() { it('works with multiple transactions', function() {
var allOutputs = [ var allOutputs = [{
{ satoshis: 10, txId: 'A', outputIndex: 1, heightConfirmed: 1 }, satoshis: 10,
{ satoshis: 20, txId: 'B', outputIndex: 1, heightConfirmed: 10 } txId: 'A',
]; outputIndex: 1,
var spendOutputs = [ heightConfirmed: 1
{ spendInput: { prevTxId: 'A', outputIndex: 1 }, spentTx: 'A', heightSpent: 10 } }, {
]; satoshis: 20,
txId: 'B',
outputIndex: 1,
heightConfirmed: 10
}];
var spendOutputs = [{
spendInput: {
prevTxId: 'A',
outputIndex: 1
},
spentTx: 'A',
heightSpent: 10
}];
service.buildAddressSummary(address, tip, allOutputs, spendOutputs).should.deep.equal({ service.buildAddressSummary(address, tip, allOutputs, spendOutputs).should.deep.equal({
address: address.toString(), address: address.toString(),
transactions: ['A', 'B'], transactions: ['A', 'B'],
confirmed: { balance: 10, sent: 0, received: 10 }, confirmed: {
unconfirmed: { balance: 20, sent: 10, received: 30 } balance: 10,
sent: 0,
received: 10
},
unconfirmed: {
balance: 20,
sent: 10,
received: 30
}
}); });
}); });
it('works with a medium amount of transactions', function() { it('works with a medium amount of transactions', function() {
var allOutputs = [ var allOutputs = [{
{ satoshis: 10, txId: 'A', outputIndex: 1, heightConfirmed: 1 }, satoshis: 10,
{ satoshis: 20, txId: 'B', outputIndex: 1, heightConfirmed: 5 }, txId: 'A',
{ satoshis: 30, txId: 'C', outputIndex: 1, heightConfirmed: 10 } outputIndex: 1,
]; heightConfirmed: 1
var spendOutputs = [ }, {
{ spendInput: { prevTxId: 'A', outputIndex: 1 }, spentTx: 'D', heightSpent: 10 } satoshis: 20,
]; txId: 'B',
outputIndex: 1,
heightConfirmed: 5
}, {
satoshis: 30,
txId: 'C',
outputIndex: 1,
heightConfirmed: 10
}];
var spendOutputs = [{
spendInput: {
prevTxId: 'A',
outputIndex: 1
},
spentTx: 'D',
heightSpent: 10
}];
service.buildAddressSummary(address, tip, allOutputs, spendOutputs).should.deep.equal({ service.buildAddressSummary(address, tip, allOutputs, spendOutputs).should.deep.equal({
address: address.toString(), address: address.toString(),
transactions: ['A', 'B', 'C', 'D'], transactions: ['A', 'B', 'C', 'D'],
confirmed: { balance: 30, sent: 0, received: 30 }, confirmed: {
unconfirmed: { balance: 50, sent: 10, received: 60 } balance: 30,
sent: 0,
received: 30
},
unconfirmed: {
balance: 50,
sent: 10,
received: 60
}
}); });
}); });
it('works with a transaction that includes twice the same address', function() { it('works with a transaction that includes twice the same address', function() {
var allOutputs = [ var allOutputs = [{
{ satoshis: 10, txId: 'A', outputIndex: 0, heightConfirmed: 1 }, satoshis: 10,
{ satoshis: 10, txId: 'A', outputIndex: 1, heightConfirmed: 1 }, txId: 'A',
]; outputIndex: 0,
heightConfirmed: 1
}, {
satoshis: 10,
txId: 'A',
outputIndex: 1,
heightConfirmed: 1
}, ];
var spendOutputs = []; var spendOutputs = [];
service.buildAddressSummary(address, tip, allOutputs, spendOutputs).should.deep.equal({ service.buildAddressSummary(address, tip, allOutputs, spendOutputs).should.deep.equal({
address: address.toString(), address: address.toString(),
transactions: ['A'], transactions: ['A'],
confirmed: { balance: 20, sent: 0, received: 20 }, confirmed: {
unconfirmed: { balance: 20, sent: 0, received: 20 } balance: 20,
sent: 0,
received: 20
},
unconfirmed: {
balance: 20,
sent: 0,
received: 20
}
}); });
}); });
it('confirmed spent transactions change the balance', function() { it('confirmed spent transactions change the balance', function() {
var allOutputs = [ var allOutputs = [{
{ satoshis: 10, txId: 'A', outputIndex: 0, heightConfirmed: 1 }, satoshis: 10,
]; txId: 'A',
var spendOutputs = [ outputIndex: 0,
{ spendInput: { prevTxId: 'A', outputIndex: 0 }, spentTx: 'D', heightSpent: 2 } heightConfirmed: 1
]; }, ];
var spendOutputs = [{
spendInput: {
prevTxId: 'A',
outputIndex: 0
},
spentTx: 'D',
heightSpent: 2
}];
service.buildAddressSummary(address, tip, allOutputs, spendOutputs).should.deep.equal({ service.buildAddressSummary(address, tip, allOutputs, spendOutputs).should.deep.equal({
address: address.toString(), address: address.toString(),
transactions: ['A', 'D'], transactions: ['A', 'D'],
confirmed: { balance: 0, sent: 10, received: 10 }, confirmed: {
unconfirmed: { balance: 0, sent: 10, received: 10 } balance: 0,
sent: 10,
received: 10
},
unconfirmed: {
balance: 0,
sent: 10,
received: 10
}
}); });
}); });
}); });
}); });