545 lines
19 KiB
JavaScript
545 lines
19 KiB
JavaScript
'use strict';
|
|
|
|
var should = require('chai').should();
|
|
var sinon = require('sinon');
|
|
var bitcore = require('bitcore-lib');
|
|
var Transaction = require('../../../lib/transaction');
|
|
var AddressHistory = require('../../../lib/services/address/history');
|
|
|
|
describe('Address Service History', function() {
|
|
|
|
var address = '12c6DSiU4Rq3P4ZxziKxzrL5LmMBrzjrJX';
|
|
|
|
describe('@constructor', function() {
|
|
it('will construct a new instance', function() {
|
|
var node = {};
|
|
var options = {};
|
|
var addresses = [address];
|
|
var history = new AddressHistory({
|
|
node: node,
|
|
options: options,
|
|
addresses: addresses
|
|
});
|
|
history.should.be.instanceof(AddressHistory);
|
|
history.node.should.equal(node);
|
|
history.options.should.equal(options);
|
|
history.addresses.should.equal(addresses);
|
|
history.detailedArray.should.deep.equal([]);
|
|
});
|
|
it('will set addresses an array if only sent a string', function() {
|
|
var history = new AddressHistory({
|
|
node: {},
|
|
options: {},
|
|
addresses: address
|
|
});
|
|
history.addresses.should.deep.equal([address]);
|
|
});
|
|
});
|
|
|
|
describe('#get', function() {
|
|
it('will give an error if length of addresses is too long', function(done) {
|
|
var node = {};
|
|
var options = {};
|
|
var addresses = [];
|
|
for (var i = 0; i < 101; i++) {
|
|
addresses.push(address);
|
|
}
|
|
var history = new AddressHistory({
|
|
node: node,
|
|
options: options,
|
|
addresses: addresses
|
|
});
|
|
history.maxAddressesQuery = 100;
|
|
history.get(function(err) {
|
|
should.exist(err);
|
|
err.message.match(/Maximum/);
|
|
done();
|
|
});
|
|
});
|
|
it('give error from getAddressSummary with one address', function(done) {
|
|
var node = {
|
|
services: {
|
|
address: {
|
|
getAddressSummary: sinon.stub().callsArgWith(2, new Error('test'))
|
|
}
|
|
}
|
|
};
|
|
var options = {};
|
|
var addresses = [address];
|
|
var history = new AddressHistory({
|
|
node: node,
|
|
options: options,
|
|
addresses: addresses
|
|
});
|
|
history.get(function(err) {
|
|
should.exist(err);
|
|
err.message.should.equal('test');
|
|
done();
|
|
});
|
|
});
|
|
it('give error from getAddressSummary with multiple addresses', function(done) {
|
|
var node = {
|
|
services: {
|
|
address: {
|
|
getAddressSummary: sinon.stub().callsArgWith(2, new Error('test2'))
|
|
}
|
|
}
|
|
};
|
|
var options = {};
|
|
var addresses = [address, address];
|
|
var history = new AddressHistory({
|
|
node: node,
|
|
options: options,
|
|
addresses: addresses
|
|
});
|
|
history.get(function(err) {
|
|
should.exist(err);
|
|
err.message.should.equal('test2');
|
|
done();
|
|
});
|
|
});
|
|
it('will query get address summary directly with one address', function(done) {
|
|
var txids = [];
|
|
var summary = {
|
|
txids: txids
|
|
};
|
|
var node = {
|
|
services: {
|
|
address: {
|
|
getAddressSummary: sinon.stub().callsArgWith(2, null, summary)
|
|
}
|
|
}
|
|
};
|
|
var options = {};
|
|
var addresses = [address];
|
|
var history = new AddressHistory({
|
|
node: node,
|
|
options: options,
|
|
addresses: addresses
|
|
});
|
|
history._mergeAndSortTxids = sinon.stub();
|
|
history._paginateWithDetails = sinon.stub().callsArg(1);
|
|
history.get(function() {
|
|
history.node.services.address.getAddressSummary.callCount.should.equal(1);
|
|
history.node.services.address.getAddressSummary.args[0][0].should.equal(address);
|
|
history.node.services.address.getAddressSummary.args[0][1].should.deep.equal({
|
|
noBalance: true
|
|
});
|
|
history._paginateWithDetails.callCount.should.equal(1);
|
|
history._paginateWithDetails.args[0][0].should.equal(txids);
|
|
history._mergeAndSortTxids.callCount.should.equal(0);
|
|
done();
|
|
});
|
|
});
|
|
it('will merge multiple summaries with multiple addresses', function(done) {
|
|
var txids = [];
|
|
var summary = {
|
|
txids: txids
|
|
};
|
|
var node = {
|
|
services: {
|
|
address: {
|
|
getAddressSummary: sinon.stub().callsArgWith(2, null, summary)
|
|
}
|
|
}
|
|
};
|
|
var options = {};
|
|
var addresses = [address, address];
|
|
var history = new AddressHistory({
|
|
node: node,
|
|
options: options,
|
|
addresses: addresses
|
|
});
|
|
history._mergeAndSortTxids = sinon.stub().returns(txids);
|
|
history._paginateWithDetails = sinon.stub().callsArg(1);
|
|
history.get(function() {
|
|
history.node.services.address.getAddressSummary.callCount.should.equal(2);
|
|
history.node.services.address.getAddressSummary.args[0][0].should.equal(address);
|
|
history.node.services.address.getAddressSummary.args[0][1].should.deep.equal({
|
|
fullTxList: true,
|
|
noBalance: true
|
|
});
|
|
history._paginateWithDetails.callCount.should.equal(1);
|
|
history._paginateWithDetails.args[0][0].should.equal(txids);
|
|
history._mergeAndSortTxids.callCount.should.equal(1);
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('#_paginateWithDetails', function() {
|
|
it('slice txids based on "from" and "to" (3 to 30)', function() {
|
|
var node = {};
|
|
var options = {
|
|
from: 3,
|
|
to: 30
|
|
};
|
|
var addresses = [address];
|
|
var history = new AddressHistory({
|
|
node: node,
|
|
options: options,
|
|
addresses: addresses
|
|
});
|
|
var txids = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
sinon.stub(history, 'getDetailedInfo', function(txid, next) {
|
|
this.detailedArray.push(txid);
|
|
next();
|
|
});
|
|
history._paginateWithDetails(txids, function(err, result) {
|
|
result.totalCount.should.equal(11);
|
|
result.items.should.deep.equal([7, 6, 5, 4, 3, 2, 1, 0]);
|
|
});
|
|
});
|
|
it('slice txids based on "from" and "to" (0 to 3)', function() {
|
|
var node = {};
|
|
var options = {
|
|
from: 0,
|
|
to: 3
|
|
};
|
|
var addresses = [address];
|
|
var history = new AddressHistory({
|
|
node: node,
|
|
options: options,
|
|
addresses: addresses
|
|
});
|
|
var txids = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
sinon.stub(history, 'getDetailedInfo', function(txid, next) {
|
|
this.detailedArray.push(txid);
|
|
next();
|
|
});
|
|
history._paginateWithDetails(txids, function(err, result) {
|
|
result.totalCount.should.equal(11);
|
|
result.items.should.deep.equal([10, 9, 8]);
|
|
});
|
|
});
|
|
it('will given an error if the full details is too long', function() {
|
|
var node = {};
|
|
var options = {
|
|
from: 0,
|
|
to: 3
|
|
};
|
|
var addresses = [address];
|
|
var history = new AddressHistory({
|
|
node: node,
|
|
options: options,
|
|
addresses: addresses
|
|
});
|
|
var txids = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
sinon.stub(history, 'getDetailedInfo', function(txid, next) {
|
|
this.detailedArray.push(txid);
|
|
next();
|
|
});
|
|
history.maxHistoryQueryLength = 1;
|
|
history._paginateWithDetails(txids, function(err) {
|
|
should.exist(err);
|
|
err.message.match(/Maximum/);
|
|
});
|
|
});
|
|
it('will give full result without pagination options', function() {
|
|
var node = {};
|
|
var options = {};
|
|
var addresses = [address];
|
|
var history = new AddressHistory({
|
|
node: node,
|
|
options: options,
|
|
addresses: addresses
|
|
});
|
|
var txids = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
sinon.stub(history, 'getDetailedInfo', function(txid, next) {
|
|
this.detailedArray.push(txid);
|
|
next();
|
|
});
|
|
history._paginateWithDetails(txids, function(err, result) {
|
|
result.totalCount.should.equal(11);
|
|
result.items.should.deep.equal([10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('#_mergeAndSortTxids', function() {
|
|
it('will merge and sort multiple summaries', function() {
|
|
var summaries = [
|
|
{
|
|
totalReceived: 10000000,
|
|
totalSpent: 0,
|
|
balance: 10000000,
|
|
appearances: 2,
|
|
unconfirmedBalance: 20000000,
|
|
unconfirmedAppearances: 2,
|
|
appearanceIds: {
|
|
'56fafeb01961831b926558d040c246b97709fd700adcaa916541270583e8e579': 154,
|
|
'e9dcf22807db77ac0276b03cc2d3a8b03c4837db8ac6650501ef45af1c807cce': 120
|
|
},
|
|
unconfirmedAppearanceIds: {
|
|
'ec94d845c603f292a93b7c829811ac624b76e52b351617ca5a758e9d61a11681': 1452898347406,
|
|
'ed11a08e3102f9610bda44c80c46781d97936a4290691d87244b1b345b39a693': 1452898331964
|
|
}
|
|
},
|
|
{
|
|
totalReceived: 59990000,
|
|
totalSpent: 0,
|
|
balance: 49990000,
|
|
appearances: 3,
|
|
unconfirmedBalance: 1000000,
|
|
unconfirmedAppearances: 3,
|
|
appearanceIds: {
|
|
'bc992ad772eb02864db07ef248d31fb3c6826d25f1153ebf8c79df9b7f70fcf2': 156,
|
|
'f3c1ba3ef86a0420d6102e40e2cfc8682632ab95d09d86a27f5d466b9fa9da47': 152,
|
|
'f637384e9f81f18767ea50e00bce58fc9848b6588a1130529eebba22a410155f': 151
|
|
},
|
|
unconfirmedAppearanceIds: {
|
|
'f71bccef3a8f5609c7f016154922adbfe0194a96fb17a798c24077c18d0a9345': 1452897902377,
|
|
'edc080f2084eed362aa488ccc873a24c378dc0979aa29b05767517b70569414a': 1452897971363,
|
|
'f35e7e2a2334e845946f3eaca76890d9a68f4393ccc9fe37a0c2fb035f66d2e9': 1452897923107
|
|
}
|
|
}
|
|
];
|
|
var node = {};
|
|
var options = {};
|
|
var addresses = [address];
|
|
var history = new AddressHistory({
|
|
node: node,
|
|
options: options,
|
|
addresses: addresses
|
|
});
|
|
var txids = history._mergeAndSortTxids(summaries);
|
|
txids.should.deep.equal([
|
|
'e9dcf22807db77ac0276b03cc2d3a8b03c4837db8ac6650501ef45af1c807cce',
|
|
'f637384e9f81f18767ea50e00bce58fc9848b6588a1130529eebba22a410155f',
|
|
'f3c1ba3ef86a0420d6102e40e2cfc8682632ab95d09d86a27f5d466b9fa9da47',
|
|
'56fafeb01961831b926558d040c246b97709fd700adcaa916541270583e8e579',
|
|
'bc992ad772eb02864db07ef248d31fb3c6826d25f1153ebf8c79df9b7f70fcf2',
|
|
'f71bccef3a8f5609c7f016154922adbfe0194a96fb17a798c24077c18d0a9345',
|
|
'f35e7e2a2334e845946f3eaca76890d9a68f4393ccc9fe37a0c2fb035f66d2e9',
|
|
'edc080f2084eed362aa488ccc873a24c378dc0979aa29b05767517b70569414a',
|
|
'ed11a08e3102f9610bda44c80c46781d97936a4290691d87244b1b345b39a693',
|
|
'ec94d845c603f292a93b7c829811ac624b76e52b351617ca5a758e9d61a11681'
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe('#getDetailedInfo', function() {
|
|
it('will add additional information to existing this.transactions', function(done) {
|
|
var txid = '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0';
|
|
var tx = {
|
|
populateInputs: sinon.stub().callsArg(2),
|
|
__height: 20,
|
|
__timestamp: 1453134151,
|
|
isCoinbase: sinon.stub().returns(false),
|
|
getFee: sinon.stub().returns(1000)
|
|
};
|
|
var history = new AddressHistory({
|
|
node: {
|
|
services: {
|
|
db: {
|
|
getTransactionWithBlockInfo: sinon.stub().callsArgWith(2, null, tx),
|
|
tip: {
|
|
__height: 300
|
|
}
|
|
}
|
|
}
|
|
},
|
|
options: {},
|
|
addresses: []
|
|
});
|
|
history.getAddressDetailsForTransaction = sinon.stub().returns({
|
|
addresses: {},
|
|
satoshis: 1000,
|
|
});
|
|
history.getDetailedInfo(txid, function(err) {
|
|
if (err) {
|
|
throw err;
|
|
}
|
|
history.node.services.db.getTransactionWithBlockInfo.callCount.should.equal(1);
|
|
done();
|
|
});
|
|
});
|
|
it('will handle error from getTransactionFromBlock', function(done) {
|
|
var txid = '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0';
|
|
var history = new AddressHistory({
|
|
node: {
|
|
services: {
|
|
db: {
|
|
getTransactionWithBlockInfo: sinon.stub().callsArgWith(2, new Error('test')),
|
|
}
|
|
}
|
|
},
|
|
options: {},
|
|
addresses: []
|
|
});
|
|
history.getDetailedInfo(txid, function(err) {
|
|
err.message.should.equal('test');
|
|
done();
|
|
});
|
|
});
|
|
it('will handle error from populateInputs', function(done) {
|
|
var txid = '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0';
|
|
var history = new AddressHistory({
|
|
node: {
|
|
services: {
|
|
db: {
|
|
getTransactionWithBlockInfo: sinon.stub().callsArgWith(2, null, {
|
|
populateInputs: sinon.stub().callsArgWith(2, new Error('test'))
|
|
}),
|
|
}
|
|
}
|
|
},
|
|
options: {},
|
|
addresses: []
|
|
});
|
|
history.getDetailedInfo(txid, function(err) {
|
|
err.message.should.equal('test');
|
|
done();
|
|
});
|
|
});
|
|
it('will set this.transactions with correct information', function(done) {
|
|
// block #314159
|
|
// txid 30169e8bf78bc27c4014a7aba3862c60e2e3cce19e52f1909c8255e4b7b3174e
|
|
// outputIndex 1
|
|
var txAddress = '1Cj4UZWnGWAJH1CweTMgPLQMn26WRMfXmo';
|
|
var txString = '0100000001a08ee59fcd5d86fa170abb6d925d62d5c5c476359681b70877c04f270c4ef246000000008a47304402203fb9b476bb0c37c9b9ed5784ebd67ae589492be11d4ae1612be29887e3e4ce750220741ef83781d1b3a5df8c66fa1957ad0398c733005310d7d9b1d8c2310ef4f74c0141046516ad02713e51ecf23ac9378f1069f9ae98e7de2f2edbf46b7836096e5dce95a05455cc87eaa1db64f39b0c63c0a23a3b8df1453dbd1c8317f967c65223cdf8ffffffff02b0a75fac000000001976a91484b45b9bf3add8f7a0f3daad305fdaf6b73441ea88ac20badc02000000001976a914809dc14496f99b6deb722cf46d89d22f4beb8efd88ac00000000';
|
|
var previousTxString = '010000000155532fad2869bb951b0bd646a546887f6ee668c4c0ee13bf3f1c4bce6d6e3ed9000000008c4930460221008540795f4ef79b1d2549c400c61155ca5abbf3089c84ad280e1ba6db2a31abce022100d7d162175483d51174d40bba722e721542c924202a0c2970b07e680b51f3a0670141046516ad02713e51ecf23ac9378f1069f9ae98e7de2f2edbf46b7836096e5dce95a05455cc87eaa1db64f39b0c63c0a23a3b8df1453dbd1c8317f967c65223cdf8ffffffff02f0af3caf000000001976a91484b45b9bf3add8f7a0f3daad305fdaf6b73441ea88ac80969800000000001976a91421277e65777760d1f3c7c982ba14ed8f934f005888ac00000000';
|
|
var transaction = new Transaction();
|
|
var previousTransaction = new Transaction();
|
|
previousTransaction.fromString(previousTxString);
|
|
var previousTransactionTxid = '46f24e0c274fc07708b781963576c4c5d5625d926dbb0a17fa865dcd9fe58ea0';
|
|
transaction.fromString(txString);
|
|
var txid = transaction.hash;
|
|
transaction.__blockHash = '00000000000000001bb82a7f5973618cfd3185ba1ded04dd852a653f92a27c45';
|
|
transaction.__height = 314159;
|
|
transaction.__timestamp = 1407292005;
|
|
var history = new AddressHistory({
|
|
node: {
|
|
services: {
|
|
db: {
|
|
tip: {
|
|
__height: 314159
|
|
},
|
|
getTransactionWithBlockInfo: sinon.stub().callsArgWith(2, null, transaction),
|
|
getTransaction: function(prevTxid, queryMempool, callback) {
|
|
prevTxid.should.equal(previousTransactionTxid);
|
|
setImmediate(function() {
|
|
callback(null, previousTransaction);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
},
|
|
options: {},
|
|
addresses: [txAddress]
|
|
});
|
|
var transactionInfo = {
|
|
addresses: {},
|
|
txid: txid,
|
|
timestamp: 1407292005,
|
|
satoshis: 48020000,
|
|
address: txAddress
|
|
};
|
|
transactionInfo.addresses[txAddress] = {};
|
|
transactionInfo.addresses[txAddress].outputIndexes = [1];
|
|
transactionInfo.addresses[txAddress].inputIndexes = [];
|
|
history.getDetailedInfo(txid, function(err) {
|
|
if (err) {
|
|
throw err;
|
|
}
|
|
var info = history.detailedArray[0];
|
|
info.addresses[txAddress].should.deep.equal({
|
|
outputIndexes: [1],
|
|
inputIndexes: []
|
|
});
|
|
info.satoshis.should.equal(48020000);
|
|
info.height.should.equal(314159);
|
|
info.confirmations.should.equal(1);
|
|
info.timestamp.should.equal(1407292005);
|
|
info.fees.should.equal(20000);
|
|
info.tx.should.equal(transaction);
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('#getAddressDetailsForTransaction', function() {
|
|
it('will calculate details for the transaction', function(done) {
|
|
/* jshint sub:true */
|
|
var tx = bitcore.Transaction({
|
|
'hash': 'b12b3ae8489c5a566b629a3c62ce4c51c3870af550fb5dc77d715b669a91343c',
|
|
'version': 1,
|
|
'inputs': [
|
|
{
|
|
'prevTxId': 'a2b7ea824a92f4a4944686e67ec1001bc8785348b8c111c226f782084077b543',
|
|
'outputIndex': 0,
|
|
'sequenceNumber': 4294967295,
|
|
'script': '47304402201b81c933297241960a57ae1b2952863b965ac8c9ec7466ff0b715712d27548d50220576e115b63864f003889443525f47c7cf0bc1e2b5108398da085b221f267ba2301210229766f1afa25ca499a51f8e01c292b0255a21a41bb6685564a1607a811ffe924',
|
|
'scriptString': '71 0x304402201b81c933297241960a57ae1b2952863b965ac8c9ec7466ff0b715712d27548d50220576e115b63864f003889443525f47c7cf0bc1e2b5108398da085b221f267ba2301 33 0x0229766f1afa25ca499a51f8e01c292b0255a21a41bb6685564a1607a811ffe924',
|
|
'output': {
|
|
'satoshis': 1000000000,
|
|
'script': '76a9140b2f0a0c31bfe0406b0ccc1381fdbe311946dadc88ac'
|
|
}
|
|
}
|
|
],
|
|
'outputs': [
|
|
{
|
|
'satoshis': 100000000,
|
|
'script': '76a9140b2f0a0c31bfe0406b0ccc1381fdbe311946dadc88ac'
|
|
},
|
|
{
|
|
'satoshis': 200000000,
|
|
'script': '76a9140b2f0a0c31bfe0406b0ccc1381fdbe311946dadc88ac'
|
|
},
|
|
{
|
|
'satoshis': 50000000,
|
|
'script': '76a9140b2f0a0c31bfe0406b0ccc1381fdbe311946dadc88ac'
|
|
},
|
|
{
|
|
'satoshis': 300000000,
|
|
'script': '76a9140b2f0a0c31bfe0406b0ccc1381fdbe311946dadc88ac'
|
|
},
|
|
{
|
|
'satoshis': 349990000,
|
|
'script': '76a9140b2f0a0c31bfe0406b0ccc1381fdbe311946dadc88ac'
|
|
}
|
|
],
|
|
'nLockTime': 0
|
|
});
|
|
var history = new AddressHistory({
|
|
node: {
|
|
network: bitcore.Networks.testnet
|
|
},
|
|
options: {},
|
|
addresses: ['mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW']
|
|
});
|
|
var details = history.getAddressDetailsForTransaction(tx);
|
|
should.exist(details.addresses['mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW']);
|
|
details.addresses['mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW'].inputIndexes.should.deep.equal([0]);
|
|
details.addresses['mgY65WSfEmsyYaYPQaXhmXMeBhwp4EcsQW'].outputIndexes.should.deep.equal([
|
|
0, 1, 2, 3, 4
|
|
]);
|
|
details.satoshis.should.equal(-10000);
|
|
done();
|
|
});
|
|
});
|
|
|
|
describe('#getConfirmationsDetail', function() {
|
|
it('the correct confirmations when included in the tip', function(done) {
|
|
var history = new AddressHistory({
|
|
node: {
|
|
services: {
|
|
db: {
|
|
tip: {
|
|
__height: 100
|
|
}
|
|
}
|
|
}
|
|
},
|
|
options: {},
|
|
addresses: []
|
|
});
|
|
var transaction = {
|
|
__height: 100
|
|
};
|
|
history.getConfirmationsDetail(transaction).should.equal(1);
|
|
done();
|
|
});
|
|
});
|
|
});
|