Added wallet regtest.

This commit is contained in:
Chris Kleeschulte 2017-04-27 07:57:59 -04:00
parent 2140c0ce4d
commit 5dfadf9d2b
2 changed files with 117 additions and 40 deletions

View File

@ -397,10 +397,9 @@ WalletService.prototype._loadAllBalances = function(callback) {
WalletService.prototype._endpointUTXOs = function() { WalletService.prototype._endpointUTXOs = function() {
var self = this; var self = this;
return function(req, res) { return function(req, res) {
req.setTimeout(600000);
var walletId = req.params.walletId; var walletId = req.params.walletId;
var queryMempool = req.query.queryMempool !== false; var queryMempool = req.query.queryMempool !== false;
var height = null; var height = self.node.services.db.tip.__height;
var options = { var options = {
queryMempool: queryMempool queryMempool: queryMempool
}; };
@ -435,7 +434,11 @@ WalletService.prototype._endpointGetBalance= function() {
if(err) { if(err) {
return utils.sendError(err, res); return utils.sendError(err, res);
} }
res.status(200).jsonp(result); res.status(200).jsonp({
satoshis: result,
height: self.node.services.db.tip.__height,
hash: self.node.services.db.tip.hash
});
}); });
}; };
}; };
@ -699,13 +702,12 @@ WalletService.prototype._getUtxos = function(walletId, options, callback) {
stream.on('data', function(data) { stream.on('data', function(data) {
var key = self._encoding.decodeWalletUtxoKey(data.key); var key = self._encoding.decodeWalletUtxoKey(data.key);
var value = self._encoding.decodeWalletUtxoValue(data.value); var value = self._encoding.decodeWalletUtxoValue(data.value);
utxos.push({ utxos.push({
txid: key.txid, txid: key.txid,
vout: key.outputIndex, vout: key.outputIndex,
height: value.height, height: value.height,
satoshis: value.satoshis, satoshis: value.satoshis,
scriptPubKey: value.script._scriptBuffer scriptPubKey: value.script.toString('hex')
}); });
}); });
@ -727,7 +729,6 @@ WalletService.prototype._getBalance = function(walletId, options, callback) {
if(err) { if(err) {
return callback(err); return callback(err);
} }
callback(null, self._encoding.decodeWalletBalanceValue(buffer)); callback(null, self._encoding.decodeWalletBalanceValue(buffer));
}); });
}; };

View File

@ -17,6 +17,7 @@ var fs = require('fs');
var http = require('http'); var http = require('http');
var crypto = require('crypto'); var crypto = require('crypto');
var debug = false;
var bitcoreDataDir = '/tmp/bitcore'; var bitcoreDataDir = '/tmp/bitcore';
var bitcoinDataDir = '/tmp/bitcoin'; var bitcoinDataDir = '/tmp/bitcoin';
@ -93,12 +94,15 @@ var bitcore = {
var rpc = new BitcoinRPC(rpcConfig); var rpc = new BitcoinRPC(rpcConfig);
var walletPassphrase = 'test'; var walletPassphrase = 'test';
var numberOfStartingTxs = 50; var numberOfStartingTxs = 49; //this should be an even number of txs
var txCount = 0;
var blockHeight = 0;
var walletPrivKeys = []; var walletPrivKeys = [];
var initialTxs = []; var initialTxs = [];
var fee = 100000; var fee = 100000;
var walletId = crypto.createHash('sha256').update('test').digest('hex'); var walletId = crypto.createHash('sha256').update('test').digest('hex');
var satoshisReceived = 0;
describe('Wallet Operations', function() { describe('Wallet Operations', function() {
@ -123,11 +127,7 @@ describe('Wallet Operations', function() {
it('should register wallet', function(done) { it('should register wallet', function(done) {
var httpOpts = Object.assign({ var httpOpts = getHttpOpts({ path: '/wallet-api/wallets/' + walletId, method: 'POST' });
path: '/wallet-api/wallets/' + walletId,
method: 'POST'
}, bitcore.httpOpts);
queryBitcoreNode(httpOpts, function(err, res) { queryBitcoreNode(httpOpts, function(err, res) {
if (err) { if (err) {
return done(err); return done(err);
@ -143,15 +143,12 @@ describe('Wallet Operations', function() {
var addresses = JSON.stringify(walletPrivKeys.map(function(privKey) { var addresses = JSON.stringify(walletPrivKeys.map(function(privKey) {
return privKey.toAddress().toString(); return privKey.toAddress().toString();
})); }));
var httpOpts = Object.assign({ var httpOpts = getHttpOpts({
path: '/wallet-api/wallets/' + walletId + '/addresses', path: '/wallet-api/wallets/' + walletId + '/addresses',
method: 'POST', method: 'POST',
body: addresses, body: addresses,
headers: { length: addresses.length
'Content-Type': 'application/json', });
'Content-Length': addresses.length
}
}, bitcore.httpOpts);
async.waterfall([ queryBitcoreNode.bind(this, httpOpts) ], function(err, res) { async.waterfall([ queryBitcoreNode.bind(this, httpOpts) ], function(err, res) {
if (err) { if (err) {
return done(err); return done(err);
@ -160,10 +157,7 @@ describe('Wallet Operations', function() {
Object.keys(job).should.deep.equal(['jobId']); Object.keys(job).should.deep.equal(['jobId']);
var httpOpts = Object.assign({ var httpOpts = getHttpOpts({ path: '/wallet-api/jobs/' + job.jobId });
path: '/wallet-api/jobs/' + job.jobId,
method: 'GET'
}, bitcore.httpOpts);
async.retry({ times: 10, interval: 1000 }, function(next) { async.retry({ times: 10, interval: 1000 }, function(next) {
queryBitcoreNode(httpOpts, function(err, res) { queryBitcoreNode(httpOpts, function(err, res) {
@ -187,27 +181,89 @@ describe('Wallet Operations', function() {
}); });
it('should get a list of transactions', function(done) { it('should get a list of transactions', function(done) {
var httpOpts = Object.assign({ var httpOpts = getHttpOpts({ path: '/wallet-api/wallets/' + walletId + '/transactions' });
path: '/wallet-api/wallets/' + walletId + '/transactions',
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}, bitcore.httpOpts);
queryBitcoreNode(httpOpts, function(err, res) { queryBitcoreNode(httpOpts, function(err, res) {
if(err) { if(err) {
return done(err); return done(err);
} }
var results = res.split('\n').slice(0, -1); //jsonl is returned, so there will be a newline at the end
results.length.should.equal(numberOfStartingTxs); var results = res.split('\n').filter(function(result) {
return result.length > 0;
});
var map = initialTxs.map(function(tx) { var map = initialTxs.map(function(tx) {
return tx.serialize(); return tx.serialize();
}); });
for(var i = 0; i < results.length; i++) { for(var i = 0; i < results.length; i++) {
var result = results[i]; var result = results[i];
var tx = new Transaction(JSON.parse(result)); var tx = new Transaction(JSON.parse(result));
tx.uncheckedSerialize().should.equal(initialTxs[i].serialize()); map.splice(map.indexOf(tx.uncheckedSerialize()), 1);
} }
map.length.should.equal(0);
results.length.should.equal(numberOfStartingTxs);
done();
});
});
it('should get the balance of a wallet', function(done) {
var httpOpts = getHttpOpts({ path: '/wallet-api/wallets/' + walletId + '/balance' });
queryBitcoreNode(httpOpts, function(err, res) {
if(err) {
return done(err);
}
var results = JSON.parse(res);
results.satoshis.should.equal(satoshisReceived);
done();
});
});
it('should get the set of utxos for the wallet', function(done) {
var httpOpts = getHttpOpts({ path: '/wallet-api/wallets/' + walletId + '/utxos' });
queryBitcoreNode(httpOpts, function(err, res) {
if(err) {
return done(err);
}
var results = JSON.parse(res);
// all starting txs were spending to our wallet
results.utxos.length.should.equal(numberOfStartingTxs);
var map = initialTxs.map(function(tx) {
return tx.txid;
});
var balance = 0;
for(var i = 0; i < results.utxos.length; i++) {
var result = results.utxos[i];
balance += result.satoshis;
map.splice(map.indexOf(result.txid), 1);
}
map.length.should.equal(0);
results.height.should.equal(blockHeight);
balance.should.equal(satoshisReceived);
done();
});
});
it('should get the list of jobs', function(done) {
var httpOpts = getHttpOpts({ path: '/wallet-api/jobs' });
queryBitcoreNode(httpOpts, function(err, res) {
if(err) {
return done(err);
}
var results = JSON.parse(res);
results.jobCount.should.equal(1);
done();
});
});
it('should remove all wallets', function(done) {
var httpOpts = getHttpOpts({ path: '/wallet-api/wallets', method: 'DELETE' });
queryBitcoreNode(httpOpts, function(err, res) {
if(err) {
return done(err);
}
//walletTransactionKey = 1, walletUtxoKey = 1, walletUtxoSatoshis = 1 <-- multiples of numberOfStartingTxs
//walletAddresses = 1, walletBalance = 1 <-- one record per index
var results = JSON.parse(res);
results.numberRemoved.should.equal((numberOfStartingTxs * 3) + 2);
done(); done();
}); });
}); });
@ -273,7 +329,9 @@ function queryBitcoreNode(httpOpts, next) {
function waitForBitcoreNode(next) { function waitForBitcoreNode(next) {
bitcore.process.stdout.on('data', function(data) { bitcore.process.stdout.on('data', function(data) {
console.log(data.toString()); if (debug) {
console.log(data.toString());
}
}); });
bitcore.process.stderr.on('data', function(data) { bitcore.process.stderr.on('data', function(data) {
console.log(data.toString()); console.log(data.toString());
@ -284,11 +342,7 @@ function waitForBitcoreNode(next) {
} }
}; };
var httpOpts = Object.assign({ var httpOpts = getHttpOpts({ path: '/wallet-api/issynced', errorFilter: errorFilter });
path: '/wallet-api/issynced',
errorFilter: errorFilter,
method: 'GET'
}, bitcore.httpOpts);
waitForService(queryBitcoreNode.bind(this, httpOpts), next); waitForService(queryBitcoreNode.bind(this, httpOpts), next);
} }
@ -299,6 +353,7 @@ function waitForBitcoinReady(next) {
if (err || (res && res.error)) { if (err || (res && res.error)) {
return next('keep trying'); return next('keep trying');
} }
blockHeight += 150;
next(); next();
}); });
}, function(err) { }, function(err) {
@ -372,7 +427,7 @@ function getPrivateKeyWithABalance(next) {
} }
function generateSpendingTx(privKey, utxo) { function generateSpendingTx(privKey, utxo) {
txCount++;
var toPrivKey = new PrivateKey('testnet'); //external addresses var toPrivKey = new PrivateKey('testnet'); //external addresses
var changePrivKey = new PrivateKey('testnet'); //our wallet keys var changePrivKey = new PrivateKey('testnet'); //our wallet keys
var utxoSatoshis = Unit.fromBTC(utxo.amount).satoshis; var utxoSatoshis = Unit.fromBTC(utxo.amount).satoshis;
@ -386,6 +441,7 @@ function generateSpendingTx(privKey, utxo) {
tx.sign(privKey); tx.sign(privKey);
walletPrivKeys.push(changePrivKey); walletPrivKeys.push(changePrivKey);
satoshisReceived += Unit.fromBTC(utxo.amount).toSatoshis() - (satsToPrivKey + fee);
return tx; return tx;
} }
@ -406,7 +462,13 @@ function setupInitialTx(index, next) {
} }
function setupInitialTxs(next) { function setupInitialTxs(next) {
async.timesSeries(numberOfStartingTxs, setupInitialTx, next); async.timesSeries(numberOfStartingTxs, setupInitialTx, function(err) {
if(err) {
return next(err);
}
blockHeight++;
rpc.generate(1, next);
});
} }
function sendTx(tx, generateBlocks, next) { function sendTx(tx, generateBlocks, next) {
@ -415,6 +477,7 @@ function sendTx(tx, generateBlocks, next) {
return next(err); return next(err);
} }
if (generateBlocks) { if (generateBlocks) {
blockHeight += generateBlocks;
rpc.generate(generateBlocks, function(err) { rpc.generate(generateBlocks, function(err) {
if(err) { if(err) {
return next(err); return next(err);
@ -426,3 +489,16 @@ function sendTx(tx, generateBlocks, next) {
} }
}); });
} }
function getHttpOpts(opts) {
return Object.assign({
path: opts.path,
method: opts.method || 'GET',
body: opts.body,
headers: {
'Content-Type': 'application/json',
'Content-Length': opts.length || 0
},
errorFilter: opts.errorFilter
}, bitcore.httpOpts);
}