Merge pull request #306 from isocolsky/improve_fees
Support legacy clients
This commit is contained in:
commit
362d1a42bb
|
@ -9,7 +9,7 @@ var Address = Bitcore.Address;
|
|||
var TxProposalAction = require('./txproposalaction');
|
||||
|
||||
function TxProposal() {
|
||||
this.version = '1.0.1';
|
||||
this.version = '2.0.0';
|
||||
};
|
||||
|
||||
TxProposal.Types = {
|
||||
|
|
|
@ -865,6 +865,13 @@ WalletService.prototype._selectTxInputs = function(txp, cb) {
|
|||
var inputs = sortUtxos(utxos);
|
||||
|
||||
var bitcoreTx, bitcoreError;
|
||||
var serializationOpts = {
|
||||
disableIsFullySigned: true,
|
||||
};
|
||||
if (!_.startsWith(txp.version, '1.')) {
|
||||
serializationOpts.disableSmallFees = true;
|
||||
serializationOpts.disableLargeFees = true;
|
||||
}
|
||||
|
||||
while (i < inputs.length) {
|
||||
selected.push(inputs[i]);
|
||||
|
@ -876,11 +883,7 @@ WalletService.prototype._selectTxInputs = function(txp, cb) {
|
|||
txp.setInputs(selected);
|
||||
txp.estimateFee();
|
||||
bitcoreTx = txp.getBitcoreTx();
|
||||
bitcoreError = bitcoreTx.getSerializationError({
|
||||
disableIsFullySigned: true,
|
||||
disableSmallFees: true,
|
||||
disableLargeFees: true,
|
||||
});
|
||||
bitcoreError = bitcoreTx.getSerializationError(serializationOpts);
|
||||
if (!bitcoreError) {
|
||||
txp.fee = bitcoreTx.getFee();
|
||||
return cb();
|
||||
|
@ -1052,6 +1055,10 @@ WalletService.prototype.createTx = function(opts, cb) {
|
|||
excludeUnconfirmedUtxos: !!opts.excludeUnconfirmedUtxos,
|
||||
});
|
||||
|
||||
if (!self.clientVersion || _.startsWith(self.clientVersion, 'bwc-0.0.')) {
|
||||
txp.version = '1.0.1';
|
||||
}
|
||||
|
||||
self._selectTxInputs(txp, function(err) {
|
||||
if (err) return cb(err);
|
||||
|
||||
|
@ -1384,6 +1391,14 @@ WalletService.prototype.getPendingTxs = function(opts, cb) {
|
|||
self.storage.fetchPendingTxs(self.walletId, function(err, txps) {
|
||||
if (err) return cb(err);
|
||||
|
||||
if (_.startsWith(self.clientVersion, 'bwc-0.0.')) {
|
||||
var allLegacy = _.all(txps, function(txp) {
|
||||
return _.startsWith(txp.version, '1.');
|
||||
});
|
||||
|
||||
if (!allLegacy) return cb(new Error('Some spend proposals were created using a newer version. Please upgrade your client app.'))
|
||||
}
|
||||
|
||||
_.each(txps, function(txp) {
|
||||
txp.deleteLockTime = self.getRemainingDeleteLockTime(txp);
|
||||
});
|
||||
|
@ -1534,7 +1549,12 @@ WalletService.prototype.getTxHistory = function(opts, cb) {
|
|||
amount = 0;
|
||||
}
|
||||
|
||||
function outputMap(o) { return { amount: o.amount, address: o.address } };
|
||||
function outputMap(o) {
|
||||
return {
|
||||
amount: o.amount,
|
||||
address: o.address
|
||||
}
|
||||
};
|
||||
var newTx = {
|
||||
txid: tx.txid,
|
||||
action: action,
|
||||
|
@ -1542,7 +1562,9 @@ WalletService.prototype.getTxHistory = function(opts, cb) {
|
|||
fees: tx.fees,
|
||||
time: tx.time,
|
||||
addressTo: addressTo,
|
||||
outputs: _.map(_.filter(outputs, { isChange: false }), outputMap),
|
||||
outputs: _.map(_.filter(outputs, {
|
||||
isChange: false
|
||||
}), outputMap),
|
||||
confirmations: tx.confirmations,
|
||||
};
|
||||
|
||||
|
@ -1556,11 +1578,13 @@ WalletService.prototype.getTxHistory = function(opts, cb) {
|
|||
return _.pick(action, ['createdOn', 'type', 'copayerId', 'copayerName', 'comment']);
|
||||
});
|
||||
_.each(newTx.outputs, function(output) {
|
||||
var query = { toAddress: output.address, amount: output.amount };
|
||||
var query = {
|
||||
toAddress: output.address,
|
||||
amount: output.amount
|
||||
};
|
||||
var txpOut = _.find(proposal.outputs, query);
|
||||
output.message = txpOut ? txpOut.message : null;
|
||||
}
|
||||
);
|
||||
});
|
||||
// newTx.sentTs = proposal.sentTs;
|
||||
// newTx.merchant = proposal.merchant;
|
||||
//newTx.paymentAckMemo = proposal.paymentAckMemo;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "bitcore-wallet-service",
|
||||
"description": "A service for Mutisig HD Bitcoin Wallets",
|
||||
"author": "BitPay Inc",
|
||||
"version": "0.0.47",
|
||||
"version": "0.1.0",
|
||||
"keywords": [
|
||||
"bitcoin",
|
||||
"copay",
|
||||
|
@ -20,7 +20,7 @@
|
|||
"dependencies": {
|
||||
"async": "^0.9.0",
|
||||
"bitcore": "^0.12.9",
|
||||
"bitcore-wallet-utils": "^0.0.23",
|
||||
"bitcore-wallet-utils": "^0.1.0",
|
||||
"body-parser": "^1.11.0",
|
||||
"coveralls": "^2.11.2",
|
||||
"email-validator": "^1.0.1",
|
||||
|
|
|
@ -35,6 +35,7 @@ helpers.getAuthServer = function(copayerId, cb) {
|
|||
copayerId: copayerId,
|
||||
message: 'dummy',
|
||||
signature: 'dummy',
|
||||
clientVersion: 'bwc-0.1.0',
|
||||
}, function(err, server) {
|
||||
verifyStub.restore();
|
||||
if (err || !server) throw new Error('Could not login as copayerId ' + copayerId);
|
||||
|
@ -4249,4 +4250,144 @@ describe('Wallet service', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('Legacy', function() {
|
||||
describe('Fees', function() {
|
||||
var server, wallet;
|
||||
beforeEach(function(done) {
|
||||
helpers.createAndJoinWallet(2, 3, function(s, w) {
|
||||
server = s;
|
||||
wallet = w;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should create a tx from legacy (bwc-0.0.*) client', function(done) {
|
||||
helpers.stubUtxos(server, wallet, [100, 200], function() {
|
||||
var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, 'some message', TestData.copayers[0].privKey_1H_0);
|
||||
|
||||
var verifyStub = sinon.stub(WalletService.prototype, '_verifySignature');
|
||||
verifyStub.returns(true);
|
||||
WalletService.getInstanceWithAuth({
|
||||
copayerId: wallet.copayers[0].id,
|
||||
message: 'dummy',
|
||||
signature: 'dummy',
|
||||
clientVersion: 'bwc-0.0.40',
|
||||
}, function(err, server) {
|
||||
should.not.exist(err);
|
||||
should.exist(server);
|
||||
verifyStub.restore();
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
should.not.exist(err);
|
||||
should.exist(tx);
|
||||
tx.amount.should.equal(helpers.toSatoshi(80));
|
||||
tx.fee.should.equal(WalletUtils.DEFAULT_FEE_PER_KB);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
it('should return error when fetching new txps from legacy (bwc-0.0.*) client', function(done) {
|
||||
helpers.stubUtxos(server, wallet, [100, 200], function() {
|
||||
var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, 'some message', TestData.copayers[0].privKey_1H_0);
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
should.not.exist(err);
|
||||
should.exist(tx);
|
||||
|
||||
var verifyStub = sinon.stub(WalletService.prototype, '_verifySignature');
|
||||
verifyStub.returns(true);
|
||||
WalletService.getInstanceWithAuth({
|
||||
copayerId: wallet.copayers[0].id,
|
||||
message: 'dummy',
|
||||
signature: 'dummy',
|
||||
clientVersion: 'bwc-0.0.40',
|
||||
}, function(err, server) {
|
||||
should.not.exist(err);
|
||||
should.exist(server);
|
||||
verifyStub.restore();
|
||||
server.getPendingTxs({}, function(err, txps) {
|
||||
should.exist(err);
|
||||
should.not.exist(txps);
|
||||
err.toString().should.contain('created by a newer version');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
it('should create a tx from legacy (bwc-0.0.*) client and sign it from newer client', function(done) {
|
||||
helpers.stubUtxos(server, wallet, [100, 200], function() {
|
||||
var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 80, 'some message', TestData.copayers[0].privKey_1H_0);
|
||||
|
||||
var verifyStub = sinon.stub(WalletService.prototype, '_verifySignature');
|
||||
verifyStub.returns(true);
|
||||
WalletService.getInstanceWithAuth({
|
||||
copayerId: wallet.copayers[0].id,
|
||||
message: 'dummy',
|
||||
signature: 'dummy',
|
||||
clientVersion: 'bwc-0.0.40',
|
||||
}, function(err, server) {
|
||||
should.not.exist(err);
|
||||
should.exist(server);
|
||||
verifyStub.restore();
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
should.not.exist(err);
|
||||
should.exist(tx);
|
||||
tx.amount.should.equal(helpers.toSatoshi(80));
|
||||
tx.fee.should.equal(WalletUtils.DEFAULT_FEE_PER_KB);
|
||||
helpers.getAuthServer(wallet.copayers[0].id, function(server) {
|
||||
var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey);
|
||||
server.signTx({
|
||||
txProposalId: tx.id,
|
||||
signatures: signatures,
|
||||
}, function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
it('should fail with insufficient fee when invoked from legacy (bwc-0.0.*) client', function(done) {
|
||||
helpers.stubUtxos(server, wallet, 1, function() {
|
||||
var verifyStub = sinon.stub(WalletService.prototype, '_verifySignature');
|
||||
verifyStub.returns(true);
|
||||
WalletService.getInstanceWithAuth({
|
||||
copayerId: wallet.copayers[0].id,
|
||||
message: 'dummy',
|
||||
signature: 'dummy',
|
||||
clientVersion: 'bwc-0.0.40',
|
||||
}, function(err, server) {
|
||||
should.not.exist(err);
|
||||
should.exist(server);
|
||||
verifyStub.restore();
|
||||
var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.99995, null, TestData.copayers[0].privKey_1H_0);
|
||||
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
should.exist(err);
|
||||
err.code.should.equal('INSUFFICIENTFUNDS');
|
||||
var txOpts = helpers.createSimpleProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.99995, null, TestData.copayers[0].privKey_1H_0, 5000);
|
||||
server.createTx(txOpts, function(err, tx) {
|
||||
should.not.exist(err);
|
||||
tx.fee.should.equal(5000);
|
||||
|
||||
// Sign it to make sure Bitcore doesn't complain about the fees
|
||||
var signatures = helpers.clientSign(tx, TestData.copayers[0].xPrivKey);
|
||||
server.signTx({
|
||||
txProposalId: tx.id,
|
||||
signatures: signatures,
|
||||
}, function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -153,18 +153,8 @@ var aTxpOpts = function(type) {
|
|||
};
|
||||
|
||||
var aTXP = function(type) {
|
||||
var version;
|
||||
switch (type) {
|
||||
case TxProposal.Types.MULTIPLEOUTPUTS:
|
||||
version = '1.0.1';
|
||||
break;
|
||||
default:
|
||||
version = '1.0.0';
|
||||
break
|
||||
}
|
||||
|
||||
var txp = {
|
||||
"version": version,
|
||||
"version": '2.0.0',
|
||||
"type": type,
|
||||
"createdOn": 1423146231,
|
||||
"id": "75c34f49-1ed6-255f-e9fd-0c71ae75ed1e",
|
||||
|
|
Loading…
Reference in New Issue