2015-08-21 08:17:26 -07:00
|
|
|
'use strict';
|
|
|
|
|
2016-04-08 06:56:08 -07:00
|
|
|
// To run the tests: $ mocha -R spec regtest/node.js
|
2015-08-21 08:17:26 -07:00
|
|
|
|
2016-04-08 11:44:24 -07:00
|
|
|
var path = require('path');
|
2015-08-26 12:18:58 -07:00
|
|
|
var index = require('..');
|
2015-08-24 06:56:38 -07:00
|
|
|
var async = require('async');
|
2015-08-26 12:18:58 -07:00
|
|
|
var log = index.log;
|
2015-08-24 06:56:38 -07:00
|
|
|
log.debug = function() {};
|
2015-08-21 08:17:26 -07:00
|
|
|
|
|
|
|
var chai = require('chai');
|
2015-10-16 21:56:29 -07:00
|
|
|
var bitcore = require('bitcore-lib');
|
2015-08-21 08:17:26 -07:00
|
|
|
var rimraf = require('rimraf');
|
|
|
|
var node;
|
|
|
|
|
|
|
|
var should = chai.should();
|
|
|
|
|
|
|
|
var BitcoinRPC = require('bitcoind-rpc');
|
2015-08-31 06:00:00 -07:00
|
|
|
var index = require('..');
|
2015-09-09 16:45:49 -07:00
|
|
|
var Transaction = index.Transaction;
|
2015-08-31 06:00:00 -07:00
|
|
|
var BitcoreNode = index.Node;
|
2015-08-31 06:00:00 -07:00
|
|
|
var BitcoinService = index.services.Bitcoin;
|
2015-08-21 08:17:26 -07:00
|
|
|
var testWIF = 'cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG';
|
|
|
|
var testKey;
|
|
|
|
var client;
|
|
|
|
|
2015-09-18 12:31:09 -07:00
|
|
|
var outputForIsSpentTest1;
|
2015-10-01 13:06:44 -07:00
|
|
|
var unspentOutputSpentTxId;
|
2015-09-18 12:31:09 -07:00
|
|
|
|
2015-08-21 08:17:26 -07:00
|
|
|
describe('Node Functionality', function() {
|
|
|
|
|
2015-09-09 16:45:49 -07:00
|
|
|
var regtest;
|
|
|
|
|
2015-08-21 08:17:26 -07:00
|
|
|
before(function(done) {
|
2016-04-08 11:44:24 -07:00
|
|
|
this.timeout(20000);
|
2015-08-21 08:17:26 -07:00
|
|
|
|
|
|
|
var datadir = __dirname + '/data';
|
|
|
|
|
|
|
|
testKey = bitcore.PrivateKey(testWIF);
|
|
|
|
|
|
|
|
rimraf(datadir + '/regtest', function(err) {
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
|
|
|
|
var configuration = {
|
2015-08-31 06:00:00 -07:00
|
|
|
network: 'regtest',
|
2015-08-31 06:00:00 -07:00
|
|
|
services: [
|
2015-08-31 06:00:00 -07:00
|
|
|
{
|
2015-08-31 06:00:00 -07:00
|
|
|
name: 'bitcoind',
|
2015-08-31 06:00:00 -07:00
|
|
|
module: BitcoinService,
|
2016-04-08 11:44:24 -07:00
|
|
|
config: {
|
|
|
|
spawn: {
|
|
|
|
datadir: datadir,
|
|
|
|
exec: path.resolve(__dirname, '../bin/bitcoind')
|
|
|
|
}
|
|
|
|
}
|
2015-08-31 06:00:00 -07:00
|
|
|
}
|
|
|
|
]
|
2015-08-21 08:17:26 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
node = new BitcoreNode(configuration);
|
|
|
|
|
2016-01-11 15:45:51 -08:00
|
|
|
regtest = bitcore.Networks.get('regtest');
|
|
|
|
should.exist(regtest);
|
|
|
|
|
2015-08-21 08:17:26 -07:00
|
|
|
node.on('error', function(err) {
|
|
|
|
log.error(err);
|
|
|
|
});
|
|
|
|
|
|
|
|
node.on('ready', function() {
|
|
|
|
|
|
|
|
client = new BitcoinRPC({
|
2016-04-08 11:44:24 -07:00
|
|
|
protocol: 'http',
|
2015-08-21 08:17:26 -07:00
|
|
|
host: '127.0.0.1',
|
2016-04-08 11:44:24 -07:00
|
|
|
port: 30331,
|
2015-08-21 08:17:26 -07:00
|
|
|
user: 'bitcoin',
|
2015-08-26 11:39:33 -07:00
|
|
|
pass: 'local321',
|
|
|
|
rejectUnauthorized: false
|
2015-08-21 08:17:26 -07:00
|
|
|
});
|
|
|
|
|
2015-08-24 06:56:38 -07:00
|
|
|
var syncedHandler = function() {
|
2016-04-08 11:44:24 -07:00
|
|
|
if (node.services.bitcoind.height === 150) {
|
|
|
|
node.services.bitcoind.removeListener('synced', syncedHandler);
|
2015-08-21 08:17:26 -07:00
|
|
|
done();
|
|
|
|
}
|
2015-08-24 06:56:38 -07:00
|
|
|
};
|
|
|
|
|
2016-04-08 11:44:24 -07:00
|
|
|
node.services.bitcoind.on('synced', syncedHandler);
|
2015-08-21 08:17:26 -07:00
|
|
|
|
2016-04-08 11:44:24 -07:00
|
|
|
client.generate(150, function(err) {
|
2015-08-21 08:17:26 -07:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-09-04 12:05:32 -07:00
|
|
|
node.start(function(err) {
|
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2015-08-21 08:17:26 -07:00
|
|
|
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
after(function(done) {
|
|
|
|
this.timeout(20000);
|
2015-08-31 06:00:00 -07:00
|
|
|
node.stop(function(err, result) {
|
|
|
|
if(err) {
|
|
|
|
throw err;
|
|
|
|
}
|
2015-08-21 08:17:26 -07:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-09-08 11:04:14 -07:00
|
|
|
var invalidatedBlockHash;
|
|
|
|
|
2016-04-08 11:44:24 -07:00
|
|
|
it.skip('will handle a reorganization', function(done) {
|
2015-08-21 08:17:26 -07:00
|
|
|
|
2015-08-24 06:56:38 -07:00
|
|
|
var count;
|
|
|
|
var blockHash;
|
|
|
|
|
|
|
|
async.series([
|
|
|
|
function(next) {
|
|
|
|
client.getBlockCount(function(err, response) {
|
|
|
|
if (err) {
|
|
|
|
return next(err);
|
|
|
|
}
|
|
|
|
count = response.result;
|
|
|
|
next();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
function(next) {
|
2015-08-21 08:17:26 -07:00
|
|
|
client.getBlockHash(count, function(err, response) {
|
|
|
|
if (err) {
|
2015-08-24 06:56:38 -07:00
|
|
|
return next(err);
|
2015-08-21 08:17:26 -07:00
|
|
|
}
|
2015-09-08 11:04:14 -07:00
|
|
|
invalidatedBlockHash = response.result;
|
2015-08-24 06:56:38 -07:00
|
|
|
next();
|
2015-08-21 08:17:26 -07:00
|
|
|
});
|
2015-08-24 06:56:38 -07:00
|
|
|
},
|
|
|
|
function(next) {
|
2015-09-08 11:04:14 -07:00
|
|
|
client.invalidateBlock(invalidatedBlockHash, next);
|
2015-08-24 06:56:38 -07:00
|
|
|
},
|
|
|
|
function(next) {
|
|
|
|
client.getBlockCount(function(err, response) {
|
|
|
|
if (err) {
|
|
|
|
return next(err);
|
|
|
|
}
|
|
|
|
response.result.should.equal(count - 1);
|
|
|
|
next();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
], function(err) {
|
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
var blocksRemoved = 0;
|
|
|
|
var blocksAdded = 0;
|
2015-08-21 08:17:26 -07:00
|
|
|
|
2015-08-24 06:56:38 -07:00
|
|
|
var removeBlock = function() {
|
|
|
|
blocksRemoved++;
|
|
|
|
};
|
2015-08-21 08:17:26 -07:00
|
|
|
|
2015-08-31 06:00:00 -07:00
|
|
|
node.services.db.on('removeblock', removeBlock);
|
2015-08-24 06:56:38 -07:00
|
|
|
|
|
|
|
var addBlock = function() {
|
|
|
|
blocksAdded++;
|
|
|
|
if (blocksAdded === 2 && blocksRemoved === 1) {
|
2015-08-31 06:00:00 -07:00
|
|
|
node.services.db.removeListener('addblock', addBlock);
|
|
|
|
node.services.db.removeListener('removeblock', removeBlock);
|
2015-08-24 06:56:38 -07:00
|
|
|
done();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-08-31 06:00:00 -07:00
|
|
|
node.services.db.on('addblock', addBlock);
|
2015-08-21 08:17:26 -07:00
|
|
|
|
|
|
|
// We need to add a transaction to the mempool so that the next block will
|
|
|
|
// have a different hash as the hash has been invalidated.
|
2016-01-11 15:45:51 -08:00
|
|
|
client.sendToAddress(testKey.toAddress(regtest).toString(), 10, function(err) {
|
2015-08-21 08:17:26 -07:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
client.generate(2, function(err, response) {
|
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-08-24 06:56:38 -07:00
|
|
|
});
|
2015-09-08 11:04:14 -07:00
|
|
|
|
2015-09-10 10:18:39 -07:00
|
|
|
describe('Bus Functionality', function() {
|
|
|
|
it('subscribes and unsubscribes to an event on the bus', function(done) {
|
|
|
|
var bus = node.openBus();
|
2016-04-08 11:44:24 -07:00
|
|
|
var blockExpected;
|
|
|
|
var blockReceived;
|
2016-04-15 07:29:35 -07:00
|
|
|
bus.subscribe('bitcoind/hashblock');
|
|
|
|
bus.on('bitcoind/hashblock', function(data) {
|
|
|
|
bus.unsubscribe('bitcoind/hashblock');
|
2016-04-08 11:44:24 -07:00
|
|
|
if (blockExpected) {
|
|
|
|
data.should.be.equal(blockExpected);
|
|
|
|
done();
|
|
|
|
} else {
|
|
|
|
blockReceived = data;
|
|
|
|
}
|
2015-09-10 10:18:39 -07:00
|
|
|
});
|
|
|
|
client.generate(1, function(err, response) {
|
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
2016-04-08 11:44:24 -07:00
|
|
|
if (blockReceived) {
|
|
|
|
blockReceived.should.be.equal(response.result[0]);
|
|
|
|
done();
|
|
|
|
} else {
|
|
|
|
blockExpected = response.result[0];
|
|
|
|
}
|
2015-09-10 10:18:39 -07:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2015-09-09 16:45:49 -07:00
|
|
|
|
|
|
|
describe('Address Functionality', function() {
|
|
|
|
var address;
|
|
|
|
var unspentOutput;
|
2016-04-08 11:44:24 -07:00
|
|
|
before(function(done) {
|
2016-01-11 15:45:51 -08:00
|
|
|
address = testKey.toAddress(regtest).toString();
|
2016-04-08 11:44:24 -07:00
|
|
|
var startHeight = node.services.bitcoind.height;
|
|
|
|
node.services.bitcoind.on('tip', function(height) {
|
|
|
|
if (height === startHeight + 3) {
|
|
|
|
done();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
client.sendToAddress(testKey.toAddress(regtest).toString(), 10, function(err) {
|
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
client.generate(3, function(err) {
|
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2015-09-09 16:45:49 -07:00
|
|
|
});
|
|
|
|
it('should be able to get the balance of the test address', function(done) {
|
2016-04-08 11:44:24 -07:00
|
|
|
node.getAddressBalance(address, false, function(err, data) {
|
2015-09-09 16:45:49 -07:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
2016-04-08 11:44:24 -07:00
|
|
|
data.balance.should.equal(10 * 1e8);
|
2015-09-09 16:45:49 -07:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
it('can get unspent outputs for address', function(done) {
|
2016-04-08 11:44:24 -07:00
|
|
|
node.getAddressUnspentOutputs(address, false, function(err, results) {
|
2015-09-09 16:45:49 -07:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
results.length.should.equal(1);
|
2015-09-18 12:31:09 -07:00
|
|
|
unspentOutput = outputForIsSpentTest1 = results[0];
|
2015-09-09 16:45:49 -07:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
it('correctly give the history for the address', function(done) {
|
|
|
|
var options = {
|
|
|
|
from: 0,
|
|
|
|
to: 10,
|
|
|
|
queryMempool: false
|
|
|
|
};
|
2016-04-08 11:44:24 -07:00
|
|
|
node.getAddressHistory(address, options, function(err, results) {
|
2015-09-09 16:45:49 -07:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
2015-09-15 10:17:15 -07:00
|
|
|
var items = results.items;
|
|
|
|
items.length.should.equal(1);
|
|
|
|
var info = items[0];
|
2015-09-14 18:03:06 -07:00
|
|
|
should.exist(info.addresses[address]);
|
|
|
|
info.addresses[address].outputIndexes.length.should.equal(1);
|
|
|
|
info.addresses[address].outputIndexes[0].should.be.within(0, 1);
|
|
|
|
info.addresses[address].inputIndexes.should.deep.equal([]);
|
2015-09-09 16:45:49 -07:00
|
|
|
info.satoshis.should.equal(10 * 1e8);
|
|
|
|
info.confirmations.should.equal(3);
|
|
|
|
info.timestamp.should.be.a('number');
|
2016-04-08 11:44:24 -07:00
|
|
|
info.fees.should.be.within(950, 4000);
|
2015-09-09 16:45:49 -07:00
|
|
|
info.tx.should.be.an.instanceof(Transaction);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2015-09-18 08:27:08 -07:00
|
|
|
it('correctly give the summary for the address', function(done) {
|
|
|
|
var options = {
|
|
|
|
queryMempool: false
|
|
|
|
};
|
2016-04-08 11:44:24 -07:00
|
|
|
node.getAddressSummary(address, options, function(err, results) {
|
2015-09-18 08:27:08 -07:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
results.totalReceived.should.equal(1000000000);
|
|
|
|
results.totalSpent.should.equal(0);
|
|
|
|
results.balance.should.equal(1000000000);
|
2016-04-08 11:44:24 -07:00
|
|
|
should.not.exist(results.unconfirmedBalance);
|
2015-09-18 08:27:08 -07:00
|
|
|
results.appearances.should.equal(1);
|
2016-04-08 11:44:24 -07:00
|
|
|
should.not.exist(results.unconfirmedAppearances);
|
2015-09-18 08:27:08 -07:00
|
|
|
results.txids.length.should.equal(1);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
2015-09-09 16:45:49 -07:00
|
|
|
describe('History', function() {
|
|
|
|
|
|
|
|
this.timeout(20000);
|
|
|
|
|
|
|
|
var testKey2;
|
|
|
|
var address2;
|
|
|
|
var testKey3;
|
|
|
|
var address3;
|
|
|
|
var testKey4;
|
|
|
|
var address4;
|
|
|
|
var testKey5;
|
|
|
|
var address5;
|
|
|
|
var testKey6;
|
|
|
|
var address6;
|
|
|
|
|
|
|
|
before(function(done) {
|
|
|
|
/* jshint maxstatements: 50 */
|
|
|
|
|
2016-04-08 11:44:24 -07:00
|
|
|
// Finished once all blocks have been mined
|
|
|
|
var startHeight = node.services.bitcoind.height;
|
|
|
|
node.services.bitcoind.on('tip', function(height) {
|
|
|
|
if (height === startHeight + 5) {
|
|
|
|
done();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2015-09-09 16:45:49 -07:00
|
|
|
testKey2 = bitcore.PrivateKey.fromWIF('cNfF4jXiLHQnFRsxaJyr2YSGcmtNYvxQYSakNhuDGxpkSzAwn95x');
|
2016-01-11 15:45:51 -08:00
|
|
|
address2 = testKey2.toAddress(regtest).toString();
|
2015-09-09 16:45:49 -07:00
|
|
|
|
|
|
|
testKey3 = bitcore.PrivateKey.fromWIF('cVTYQbaFNetiZcvxzXcVMin89uMLC43pEBMy2etgZHbPPxH5obYt');
|
2016-01-11 15:45:51 -08:00
|
|
|
address3 = testKey3.toAddress(regtest).toString();
|
2015-09-09 16:45:49 -07:00
|
|
|
|
|
|
|
testKey4 = bitcore.PrivateKey.fromWIF('cPNQmfE31H2oCUFqaHpfSqjDibkt7XoT2vydLJLDHNTvcddCesGw');
|
2016-01-11 15:45:51 -08:00
|
|
|
address4 = testKey4.toAddress(regtest).toString();
|
2015-09-09 16:45:49 -07:00
|
|
|
|
|
|
|
testKey5 = bitcore.PrivateKey.fromWIF('cVrzm9gCmnzwEVMGeCxY6xLVPdG3XWW97kwkFH3H3v722nb99QBF');
|
2016-01-11 15:45:51 -08:00
|
|
|
address5 = testKey5.toAddress(regtest).toString();
|
2015-09-09 16:45:49 -07:00
|
|
|
|
|
|
|
testKey6 = bitcore.PrivateKey.fromWIF('cPfMesNR2gsQEK69a6xe7qE44CZEZavgMUak5hQ74XDgsRmmGBYF');
|
2016-01-11 15:45:51 -08:00
|
|
|
address6 = testKey6.toAddress(regtest).toString();
|
2015-09-09 16:45:49 -07:00
|
|
|
|
|
|
|
var tx = new Transaction();
|
|
|
|
tx.from(unspentOutput);
|
|
|
|
tx.to(address, 1 * 1e8);
|
|
|
|
tx.to(address, 2 * 1e8);
|
|
|
|
tx.to(address, 0.5 * 1e8);
|
|
|
|
tx.to(address, 3 * 1e8);
|
|
|
|
tx.fee(10000);
|
|
|
|
tx.change(address);
|
|
|
|
tx.sign(testKey);
|
|
|
|
|
2015-10-01 13:06:44 -07:00
|
|
|
unspentOutputSpentTxId = tx.id;
|
|
|
|
|
2015-09-09 16:45:49 -07:00
|
|
|
function mineBlock(next) {
|
|
|
|
client.generate(1, function(err, response) {
|
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
should.exist(response);
|
|
|
|
next();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-04-08 11:44:24 -07:00
|
|
|
node.sendTransaction(tx.serialize(), function(err, hash) {
|
2015-09-09 16:45:49 -07:00
|
|
|
if (err) {
|
2016-04-08 11:44:24 -07:00
|
|
|
return done(err);
|
2015-09-09 16:45:49 -07:00
|
|
|
}
|
2016-04-08 11:44:24 -07:00
|
|
|
|
|
|
|
client.generate(1, function(err, response) {
|
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
should.exist(response);
|
|
|
|
|
|
|
|
node.getAddressUnspentOutputs(address, false, function(err, results) {
|
2015-09-09 16:45:49 -07:00
|
|
|
/* jshint maxstatements: 50 */
|
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
results.length.should.equal(5);
|
|
|
|
|
|
|
|
async.series([
|
|
|
|
function(next) {
|
|
|
|
var tx2 = new Transaction();
|
|
|
|
tx2.from(results[0]);
|
|
|
|
tx2.to(address2, results[0].satoshis - 10000);
|
|
|
|
tx2.change(address);
|
|
|
|
tx2.sign(testKey);
|
2016-04-08 11:44:24 -07:00
|
|
|
node.sendTransaction(tx2.serialize(), function(err) {
|
|
|
|
if (err) {
|
|
|
|
return next(err);
|
|
|
|
}
|
|
|
|
mineBlock(next);
|
|
|
|
});
|
2015-09-09 16:45:49 -07:00
|
|
|
}, function(next) {
|
|
|
|
var tx3 = new Transaction();
|
|
|
|
tx3.from(results[1]);
|
|
|
|
tx3.to(address3, results[1].satoshis - 10000);
|
|
|
|
tx3.change(address);
|
|
|
|
tx3.sign(testKey);
|
2016-04-08 11:44:24 -07:00
|
|
|
node.sendTransaction(tx3.serialize(), function(err) {
|
|
|
|
if (err) {
|
|
|
|
return next(err);
|
|
|
|
}
|
|
|
|
mineBlock(next);
|
|
|
|
});
|
2015-09-09 16:45:49 -07:00
|
|
|
}, function(next) {
|
|
|
|
var tx4 = new Transaction();
|
|
|
|
tx4.from(results[2]);
|
|
|
|
tx4.to(address4, results[2].satoshis - 10000);
|
|
|
|
tx4.change(address);
|
|
|
|
tx4.sign(testKey);
|
2016-04-08 11:44:24 -07:00
|
|
|
node.sendTransaction(tx4.serialize(), function(err) {
|
|
|
|
if (err) {
|
|
|
|
return next(err);
|
|
|
|
}
|
|
|
|
mineBlock(next);
|
|
|
|
});
|
2015-09-09 16:45:49 -07:00
|
|
|
}, function(next) {
|
|
|
|
var tx5 = new Transaction();
|
|
|
|
tx5.from(results[3]);
|
|
|
|
tx5.from(results[4]);
|
|
|
|
tx5.to(address5, results[3].satoshis - 10000);
|
|
|
|
tx5.to(address6, results[4].satoshis - 10000);
|
|
|
|
tx5.change(address);
|
|
|
|
tx5.sign(testKey);
|
2016-04-08 11:44:24 -07:00
|
|
|
node.sendTransaction(tx5.serialize(), function(err) {
|
|
|
|
if (err) {
|
|
|
|
return next(err);
|
|
|
|
}
|
|
|
|
mineBlock(next);
|
|
|
|
});
|
2015-09-09 16:45:49 -07:00
|
|
|
}
|
|
|
|
], function(err) {
|
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2016-04-08 11:44:24 -07:00
|
|
|
|
2015-09-09 16:45:49 -07:00
|
|
|
});
|
2016-04-08 11:44:24 -07:00
|
|
|
|
2015-09-09 16:45:49 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
it('five addresses', function(done) {
|
|
|
|
var addresses = [
|
|
|
|
address2,
|
|
|
|
address3,
|
|
|
|
address4,
|
|
|
|
address5,
|
|
|
|
address6
|
|
|
|
];
|
|
|
|
var options = {};
|
2016-04-08 11:44:24 -07:00
|
|
|
node.getAddressHistory(addresses, options, function(err, results) {
|
2015-09-09 16:45:49 -07:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
2015-09-15 10:17:15 -07:00
|
|
|
results.totalCount.should.equal(4);
|
|
|
|
var history = results.items;
|
2015-09-14 18:03:06 -07:00
|
|
|
history.length.should.equal(4);
|
2016-04-08 11:44:24 -07:00
|
|
|
history[0].height.should.equal(159);
|
2015-09-09 16:45:49 -07:00
|
|
|
history[0].confirmations.should.equal(1);
|
2016-04-08 11:44:24 -07:00
|
|
|
history[1].height.should.equal(158);
|
2015-09-14 18:03:06 -07:00
|
|
|
should.exist(history[1].addresses[address4]);
|
2016-04-08 11:44:24 -07:00
|
|
|
history[2].height.should.equal(157);
|
2015-09-14 18:03:06 -07:00
|
|
|
should.exist(history[2].addresses[address3]);
|
2016-04-08 11:44:24 -07:00
|
|
|
history[3].height.should.equal(156);
|
2015-09-14 18:03:06 -07:00
|
|
|
should.exist(history[3].addresses[address2]);
|
|
|
|
history[3].satoshis.should.equal(99990000);
|
|
|
|
history[3].confirmations.should.equal(4);
|
2015-09-09 16:45:49 -07:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-04-12 15:05:26 -07:00
|
|
|
it('five addresses (limited by height)', function(done) {
|
2015-09-09 16:45:49 -07:00
|
|
|
var addresses = [
|
|
|
|
address2,
|
|
|
|
address3,
|
|
|
|
address4,
|
|
|
|
address5,
|
|
|
|
address6
|
|
|
|
];
|
|
|
|
var options = {
|
2016-04-12 15:05:26 -07:00
|
|
|
start: 158,
|
|
|
|
end: 157
|
2015-09-09 16:45:49 -07:00
|
|
|
};
|
2016-04-08 11:44:24 -07:00
|
|
|
node.getAddressHistory(addresses, options, function(err, results) {
|
2015-09-09 16:45:49 -07:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
2015-09-15 10:17:15 -07:00
|
|
|
results.totalCount.should.equal(2);
|
|
|
|
var history = results.items;
|
2015-09-14 18:03:06 -07:00
|
|
|
history.length.should.equal(2);
|
2016-04-12 15:05:26 -07:00
|
|
|
history[0].height.should.equal(158);
|
|
|
|
history[0].confirmations.should.equal(2);
|
|
|
|
history[1].height.should.equal(157);
|
|
|
|
should.exist(history[1].addresses[address3]);
|
2015-09-09 16:45:49 -07:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-04-12 15:05:26 -07:00
|
|
|
it('five addresses (limited by height 155 to 154)', function(done) {
|
2015-09-14 14:30:10 -07:00
|
|
|
var addresses = [
|
|
|
|
address2,
|
|
|
|
address3,
|
|
|
|
address4,
|
|
|
|
address5,
|
|
|
|
address6
|
|
|
|
];
|
|
|
|
var options = {
|
2016-04-12 15:05:26 -07:00
|
|
|
start: 157,
|
|
|
|
end: 156
|
2015-09-14 14:30:10 -07:00
|
|
|
};
|
2016-04-08 11:44:24 -07:00
|
|
|
node.getAddressHistory(addresses, options, function(err, results) {
|
2015-09-14 14:30:10 -07:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
2015-09-15 10:17:15 -07:00
|
|
|
results.totalCount.should.equal(2);
|
|
|
|
var history = results.items;
|
2015-09-14 14:30:10 -07:00
|
|
|
history.length.should.equal(2);
|
2016-04-12 15:05:26 -07:00
|
|
|
history[0].height.should.equal(157);
|
|
|
|
history[1].height.should.equal(156);
|
2015-09-14 14:30:10 -07:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-04-12 15:05:26 -07:00
|
|
|
it('five addresses (paginated by index)', function(done) {
|
2015-09-09 16:45:49 -07:00
|
|
|
var addresses = [
|
|
|
|
address2,
|
|
|
|
address3,
|
|
|
|
address4,
|
|
|
|
address5,
|
|
|
|
address6
|
|
|
|
];
|
|
|
|
var options = {
|
|
|
|
from: 0,
|
|
|
|
to: 3
|
|
|
|
};
|
2016-04-08 11:44:24 -07:00
|
|
|
node.getAddressHistory(addresses, options, function(err, results) {
|
2015-09-09 16:45:49 -07:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
2015-09-15 10:17:15 -07:00
|
|
|
results.totalCount.should.equal(4);
|
|
|
|
var history = results.items;
|
2015-09-09 16:45:49 -07:00
|
|
|
history.length.should.equal(3);
|
2016-04-12 15:05:26 -07:00
|
|
|
history[0].height.should.equal(159);
|
2015-09-09 16:45:49 -07:00
|
|
|
history[0].confirmations.should.equal(1);
|
2016-04-12 15:05:26 -07:00
|
|
|
history[1].height.should.equal(158);
|
2015-09-14 18:03:06 -07:00
|
|
|
should.exist(history[1].addresses[address4]);
|
2015-09-09 16:45:49 -07:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('one address with sending and receiving', function(done) {
|
|
|
|
var addresses = [
|
|
|
|
address
|
|
|
|
];
|
|
|
|
var options = {};
|
2016-04-08 11:44:24 -07:00
|
|
|
node.getAddressHistory(addresses, options, function(err, results) {
|
2015-09-09 16:45:49 -07:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
2015-09-15 10:17:15 -07:00
|
|
|
results.totalCount.should.equal(6);
|
|
|
|
var history = results.items;
|
2015-09-09 16:45:49 -07:00
|
|
|
history.length.should.equal(6);
|
2016-04-08 11:44:24 -07:00
|
|
|
history[0].height.should.equal(159);
|
2015-09-14 18:03:06 -07:00
|
|
|
history[0].addresses[address].inputIndexes.should.deep.equal([0, 1]);
|
|
|
|
history[0].addresses[address].outputIndexes.should.deep.equal([2]);
|
2015-09-09 16:45:49 -07:00
|
|
|
history[0].confirmations.should.equal(1);
|
2016-04-08 11:44:24 -07:00
|
|
|
history[1].height.should.equal(158);
|
|
|
|
history[2].height.should.equal(157);
|
|
|
|
history[3].height.should.equal(156);
|
|
|
|
history[4].height.should.equal(155);
|
2015-09-09 16:45:49 -07:00
|
|
|
history[4].satoshis.should.equal(-10000);
|
2015-09-14 18:03:06 -07:00
|
|
|
history[4].addresses[address].outputIndexes.should.deep.equal([0, 1, 2, 3, 4]);
|
|
|
|
history[4].addresses[address].inputIndexes.should.deep.equal([0]);
|
2016-04-08 11:44:24 -07:00
|
|
|
history[5].height.should.equal(152);
|
2015-09-09 16:45:49 -07:00
|
|
|
history[5].satoshis.should.equal(10 * 1e8);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2015-09-21 14:02:11 -07:00
|
|
|
it('summary for an address (sending and receiving)', function(done) {
|
2016-04-08 11:44:24 -07:00
|
|
|
node.getAddressSummary(address, {}, function(err, results) {
|
2015-09-21 14:02:11 -07:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
results.totalReceived.should.equal(2000000000);
|
|
|
|
results.totalSpent.should.equal(1999990000);
|
|
|
|
results.balance.should.equal(10000);
|
2015-10-21 14:45:06 -07:00
|
|
|
results.unconfirmedBalance.should.equal(0);
|
2015-09-21 14:02:11 -07:00
|
|
|
results.appearances.should.equal(6);
|
|
|
|
results.unconfirmedAppearances.should.equal(0);
|
|
|
|
results.txids.length.should.equal(6);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2015-09-14 13:48:28 -07:00
|
|
|
it('total transaction count (sending and receiving)', function(done) {
|
|
|
|
var addresses = [
|
|
|
|
address
|
|
|
|
];
|
|
|
|
var options = {};
|
2016-04-08 11:44:24 -07:00
|
|
|
node.getAddressHistory(addresses, options, function(err, results) {
|
2015-09-14 13:48:28 -07:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
2015-09-15 10:17:15 -07:00
|
|
|
results.totalCount.should.equal(6);
|
2015-09-14 13:48:28 -07:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-04-12 14:22:37 -07:00
|
|
|
describe('Pagination', function() {
|
2015-09-09 16:45:49 -07:00
|
|
|
it('from 0 to 1', function(done) {
|
|
|
|
var options = {
|
|
|
|
from: 0,
|
|
|
|
to: 1
|
|
|
|
};
|
2016-04-08 11:44:24 -07:00
|
|
|
node.getAddressHistory(address, options, function(err, results) {
|
2015-09-09 16:45:49 -07:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
2015-09-15 10:17:15 -07:00
|
|
|
var history = results.items;
|
2015-09-09 16:45:49 -07:00
|
|
|
history.length.should.equal(1);
|
2016-04-12 14:22:37 -07:00
|
|
|
history[0].height.should.equal(159);
|
2015-09-09 16:45:49 -07:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
it('from 1 to 2', function(done) {
|
|
|
|
var options = {
|
|
|
|
from: 1,
|
|
|
|
to: 2
|
|
|
|
};
|
2016-04-08 11:44:24 -07:00
|
|
|
node.getAddressHistory(address, options, function(err, results) {
|
2015-09-09 16:45:49 -07:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
2015-09-15 10:17:15 -07:00
|
|
|
var history = results.items;
|
2015-09-09 16:45:49 -07:00
|
|
|
history.length.should.equal(1);
|
2016-04-12 14:22:37 -07:00
|
|
|
history[0].height.should.equal(158);
|
2015-09-09 16:45:49 -07:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
it('from 2 to 3', function(done) {
|
|
|
|
var options = {
|
|
|
|
from: 2,
|
|
|
|
to: 3
|
|
|
|
};
|
2016-04-08 11:44:24 -07:00
|
|
|
node.getAddressHistory(address, options, function(err, results) {
|
2015-09-09 16:45:49 -07:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
2015-09-15 10:17:15 -07:00
|
|
|
var history = results.items;
|
2015-09-09 16:45:49 -07:00
|
|
|
history.length.should.equal(1);
|
2016-04-12 14:22:37 -07:00
|
|
|
history[0].height.should.equal(157);
|
2015-09-09 16:45:49 -07:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
it('from 3 to 4', function(done) {
|
|
|
|
var options = {
|
|
|
|
from: 3,
|
|
|
|
to: 4
|
|
|
|
};
|
2016-04-08 11:44:24 -07:00
|
|
|
node.getAddressHistory(address, options, function(err, results) {
|
2015-09-09 16:45:49 -07:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
2015-09-15 10:17:15 -07:00
|
|
|
var history = results.items;
|
2015-09-09 16:45:49 -07:00
|
|
|
history.length.should.equal(1);
|
2016-04-12 14:22:37 -07:00
|
|
|
history[0].height.should.equal(156);
|
2015-09-09 16:45:49 -07:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
it('from 4 to 5', function(done) {
|
|
|
|
var options = {
|
|
|
|
from: 4,
|
|
|
|
to: 5
|
|
|
|
};
|
2016-04-08 11:44:24 -07:00
|
|
|
node.getAddressHistory(address, options, function(err, results) {
|
2015-09-09 16:45:49 -07:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
2015-09-15 10:17:15 -07:00
|
|
|
var history = results.items;
|
2015-09-09 16:45:49 -07:00
|
|
|
history.length.should.equal(1);
|
2016-04-12 14:22:37 -07:00
|
|
|
history[0].height.should.equal(155);
|
2015-09-09 16:45:49 -07:00
|
|
|
history[0].satoshis.should.equal(-10000);
|
2015-09-14 18:03:06 -07:00
|
|
|
history[0].addresses[address].outputIndexes.should.deep.equal([0, 1, 2, 3, 4]);
|
|
|
|
history[0].addresses[address].inputIndexes.should.deep.equal([0]);
|
2015-09-09 16:45:49 -07:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
it('from 5 to 6', function(done) {
|
|
|
|
var options = {
|
|
|
|
from: 5,
|
|
|
|
to: 6
|
|
|
|
};
|
2016-04-08 11:44:24 -07:00
|
|
|
node.getAddressHistory(address, options, function(err, results) {
|
2015-09-09 16:45:49 -07:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
2015-09-15 10:17:15 -07:00
|
|
|
var history = results.items;
|
2015-09-09 16:45:49 -07:00
|
|
|
history.length.should.equal(1);
|
2016-04-12 14:22:37 -07:00
|
|
|
history[0].height.should.equal(152);
|
2015-09-09 16:45:49 -07:00
|
|
|
history[0].satoshis.should.equal(10 * 1e8);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
});
|
2015-09-16 10:35:54 -07:00
|
|
|
|
|
|
|
describe('Mempool Index', function() {
|
|
|
|
var unspentOutput;
|
|
|
|
before(function(done) {
|
2016-04-08 11:44:24 -07:00
|
|
|
node.getAddressUnspentOutputs(address, false, function(err, results) {
|
2015-09-16 10:35:54 -07:00
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
results.length.should.equal(1);
|
|
|
|
unspentOutput = results[0];
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('will update the mempool index after new tx', function(done) {
|
2016-04-08 11:44:24 -07:00
|
|
|
var memAddress = bitcore.PrivateKey().toAddress(node.network).toString();
|
2015-09-16 10:35:54 -07:00
|
|
|
var tx = new Transaction();
|
|
|
|
tx.from(unspentOutput);
|
2016-04-08 11:44:24 -07:00
|
|
|
tx.to(memAddress, unspentOutput.satoshis - 1000);
|
2015-09-16 10:35:54 -07:00
|
|
|
tx.fee(1000);
|
|
|
|
tx.sign(testKey);
|
|
|
|
|
2016-04-08 11:44:24 -07:00
|
|
|
node.services.bitcoind.sendTransaction(tx.serialize(), function(err, hash) {
|
|
|
|
node.getAddressTxids(memAddress, {}, function(err, txids) {
|
2015-10-30 13:57:01 -07:00
|
|
|
if (err) {
|
2016-04-08 11:44:24 -07:00
|
|
|
return done(err);
|
2015-10-30 13:57:01 -07:00
|
|
|
}
|
2016-04-08 11:44:24 -07:00
|
|
|
txids.length.should.equal(1);
|
|
|
|
txids[0].should.equal(hash);
|
2015-10-30 13:57:01 -07:00
|
|
|
done();
|
|
|
|
});
|
2015-09-16 10:35:54 -07:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
2015-09-18 12:31:09 -07:00
|
|
|
|
2015-09-09 16:45:49 -07:00
|
|
|
});
|
2016-03-04 10:47:22 -08:00
|
|
|
|
|
|
|
describe('Orphaned Transactions', function() {
|
2016-04-08 11:49:58 -07:00
|
|
|
this.timeout(8000);
|
2016-03-04 10:47:22 -08:00
|
|
|
var orphanedTransaction;
|
|
|
|
|
|
|
|
before(function(done) {
|
|
|
|
var count;
|
|
|
|
var invalidatedBlockHash;
|
|
|
|
|
|
|
|
async.series([
|
2016-04-08 11:44:24 -07:00
|
|
|
function(next) {
|
|
|
|
client.sendToAddress(testKey.toAddress(regtest).toString(), 10, function(err) {
|
|
|
|
if (err) {
|
|
|
|
return next(err);
|
|
|
|
}
|
|
|
|
client.generate(1, next);
|
|
|
|
});
|
|
|
|
},
|
2016-03-04 10:47:22 -08:00
|
|
|
function(next) {
|
|
|
|
client.getBlockCount(function(err, response) {
|
|
|
|
if (err) {
|
|
|
|
return next(err);
|
|
|
|
}
|
|
|
|
count = response.result;
|
|
|
|
next();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
function(next) {
|
|
|
|
client.getBlockHash(count, function(err, response) {
|
|
|
|
if (err) {
|
|
|
|
return next(err);
|
|
|
|
}
|
|
|
|
invalidatedBlockHash = response.result;
|
|
|
|
next();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
function(next) {
|
|
|
|
client.getBlock(invalidatedBlockHash, function(err, response) {
|
|
|
|
if (err) {
|
|
|
|
return next(err);
|
|
|
|
}
|
|
|
|
orphanedTransaction = response.result.tx[1];
|
2016-04-08 11:44:24 -07:00
|
|
|
should.exist(orphanedTransaction);
|
2016-03-04 10:47:22 -08:00
|
|
|
next();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
function(next) {
|
|
|
|
client.invalidateBlock(invalidatedBlockHash, next);
|
|
|
|
}
|
|
|
|
], function(err) {
|
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('will not show confirmation count for orphaned transaction', function(done) {
|
|
|
|
// This test verifies that in the situation that the transaction is not in the mempool and
|
|
|
|
// is included in an orphaned block transaction index that the confirmation count will be unconfirmed.
|
2016-04-08 13:16:41 -07:00
|
|
|
node.getTransactionWithBlockInfo(orphanedTransaction, function(err, data) {
|
2016-03-04 10:47:22 -08:00
|
|
|
if (err) {
|
|
|
|
return done(err);
|
|
|
|
}
|
2016-04-08 11:44:24 -07:00
|
|
|
should.exist(data);
|
|
|
|
should.exist(data.__height);
|
|
|
|
data.__height.should.equal(-1);
|
2016-03-04 10:47:22 -08:00
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
2015-08-21 08:17:26 -07:00
|
|
|
});
|