From f87381577c7f8eded22f89e3cb637995fb2e44c8 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Mon, 16 Feb 2015 11:18:28 -0300 Subject: [PATCH 1/4] remove console.log --- lib/server.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/server.js b/lib/server.js index e6d0114..2b432be 100644 --- a/lib/server.js +++ b/lib/server.js @@ -317,7 +317,7 @@ CopayServer.prototype._getBlockExplorer = function(provider, network) { url = 'https://test-insight.bitpay.com:443' break; } -console.log('[server.js.320:url:]',url); //TODO + console.log('[server.js.320:url:]', url); //TODO return new Explorers.Insight(url, network); break; } @@ -650,7 +650,6 @@ CopayServer.prototype.signTx = function(opts, cb) { txid: txid }); -console.log('[server.js.653:txp:]',txp); //TODO return cb(null, txp); }); }); From 787a3376be9019814a9f5570e06f286cc3d38580 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Mon, 16 Feb 2015 14:27:01 -0300 Subject: [PATCH 2/4] test minimum fee --- lib/model/txproposal.js | 10 +++++----- lib/server.js | 25 +++++++++++++++++++------ package.json | 2 +- test/integration.js | 40 +++++++++++++++++++++++++++++++++++----- 4 files changed, 60 insertions(+), 17 deletions(-) diff --git a/lib/model/txproposal.js b/lib/model/txproposal.js index 6035cd0..eac5480 100644 --- a/lib/model/txproposal.js +++ b/lib/model/txproposal.js @@ -151,7 +151,7 @@ TxProposal.prototype._addSignaturesToBitcoreTx = function(t, signatures, xpub) { var self = this; if (signatures.length != this.inputs.length) - return false; + throw new Error('Number of signatures does not match number of inputs'); var oks = 0, i = 0, @@ -176,16 +176,16 @@ TxProposal.prototype._addSignaturesToBitcoreTx = function(t, signatures, xpub) { }); if (oks != t.inputs.length) - throw new Error('wrong signatures'); + throw new Error('Wrong signatures'); }; TxProposal.prototype.sign = function(copayerId, signatures, xpub) { - - // Tests signatures are OK - var t = this._getBitcoreTx(); try { + // Tests signatures are OK + var t = this._getBitcoreTx(); this._addSignaturesToBitcoreTx(t, signatures, xpub); + this.addAction(copayerId, 'accept', null, signatures, xpub); return true; } catch (e) { diff --git a/lib/server.js b/lib/server.js index 2b432be..a7755d5 100644 --- a/lib/server.js +++ b/lib/server.js @@ -25,6 +25,7 @@ var Address = require('./model/address'); var TxProposal = require('./model/txproposal'); var Notification = require('./model/Notification'); +var MINIMUM_FEE_SAT = 10000; var initialized = false; var storage; @@ -425,13 +426,20 @@ CopayServer.prototype._selectUtxos = function(txp, utxos) { selected.push(inputs[i]); total += this._inputSatoshis(inputs[i]); - if (total >= txp.amount) { - - break; + if (total >= txp.amount + MINIMUM_FEE_SAT) { + try { + // Check if there are enough fees + txp.inputs = selected; + var raw = txp.getRawTx(); + return; + } catch (ex) { + //if (ex.name != 'bitcore.ErrorTransactionFeeError') {} + } } i++; }; - return total >= txp.amount ? selected : null; + txp.inputs = null; + return; }; @@ -488,7 +496,7 @@ CopayServer.prototype.createTx = function(opts, cb) { requiredRejections: Math.min(wallet.m, wallet.n - wallet.m + 1), }); - txp.inputs = self._selectUtxos(txp, utxos); + self._selectUtxos(txp, utxos); if (!txp.inputs) { return cb(new ClientError('INSUFFICIENTFUNDS', 'Insufficient funds')); } @@ -584,7 +592,12 @@ CopayServer.prototype.removePendingTx = function(opts, cb) { CopayServer.prototype._broadcastTx = function(txp, cb) { - var raw = txp.getRawTx(); + var raw; + try { + raw = txp.getRawTx(); + } catch (ex) { + return cb(ex); + } var bc = this._getBlockExplorer('insight', txp.getNetworkName()); bc.broadcast(raw, function(err, txid) { return cb(err, txid); diff --git a/package.json b/package.json index 33c4327..7c56271 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ }, "dependencies": { "async": "^0.9.0", - "bitcore": "^0.10.3", + "bitcore": "git+https://github.com/eordano/bitcore.git#7e88167891811163071ae35dc3dbb705ab6ccff8", "bitcore-explorers": "^0.9.1", "body-parser": "^1.11.0", "commander": "^2.6.0", diff --git a/test/integration.js b/test/integration.js index e05ad37..40c117c 100644 --- a/test/integration.js +++ b/test/integration.js @@ -728,7 +728,7 @@ describe('Copay server', function() { server.createTx(txOpts, function(err, tx) { should.not.exist(tx); - err.should.exist; + should.exist(err); err.code.should.equal('INVALIDADDRESS'); err.message.should.equal('Incorrect address network'); done(); @@ -741,6 +741,7 @@ describe('Copay server', function() { helpers.stubBlockExplorer(server, utxos); var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 120, null, TestData.copayers[0].privKey); server.createTx(txOpts, function(err, tx) { + should.exist(err); err.code.should.equal('INSUFFICIENTFUNDS'); err.message.should.equal('Insufficient funds'); server.getPendingTxs({}, function(err, txs) { @@ -757,7 +758,18 @@ describe('Copay server', function() { }); }); - it.skip('should fail to create tx when insufficient funds for fee', function(done) {}); + it('should fail to create tx when insufficient funds for fee', function(done) { + helpers.createUtxos(server, wallet, [100], function(utxos) { + helpers.stubBlockExplorer(server, utxos); + var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 100, null, TestData.copayers[0].privKey); + server.createTx(txOpts, function(err, tx) { + should.exist(err); + err.code.should.equal('INSUFFICIENTFUNDS'); + err.message.should.equal('Insufficient funds'); + done(); + }); + }); + }); it.skip('should fail to create tx for dust amount', function(done) {}); @@ -911,7 +923,7 @@ describe('Copay server', function() { var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 10, null, TestData.copayers[0].privKey); server.createTx(txOpts, function(err, tx) { should.not.exist(err); - tx.should.exist; + should.exist(tx); txid = tx.id; done(); }); @@ -986,12 +998,30 @@ describe('Copay server', function() { var tx = txs[0]; tx.id.should.equal(txid); - var signatures = ['11', '22', '33', '44']; + var signatures = ['11', '22', '33', '44', '55']; server.signTx({ txProposalId: txid, signatures: signatures, }, function(err) { - err.message.should.contain('signatures'); + should.exist(err); + err.message.should.contain('Bad signatures'); + done(); + }); + }); + }); + + it('should fail on wrong number of invalid signatures', function(done) { + server.getPendingTxs({}, function(err, txs) { + var tx = txs[0]; + tx.id.should.equal(txid); + + var signatures = _.take(helpers.clientSign(tx, TestData.copayers[0].xPrivKey), 2); + server.signTx({ + txProposalId: txid, + signatures: signatures, + }, function(err) { + should.exist(err); + err.message.should.contain('Bad signatures'); done(); }); }); From 8cf28b220084bad8931c09db569a13656a090b99 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Mon, 16 Feb 2015 14:41:12 -0300 Subject: [PATCH 3/4] test for dust amount --- lib/server.js | 6 ++++++ test/integration.js | 13 ++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/server.js b/lib/server.js index a7755d5..839f4f0 100644 --- a/lib/server.js +++ b/lib/server.js @@ -26,6 +26,7 @@ var TxProposal = require('./model/txproposal'); var Notification = require('./model/Notification'); var MINIMUM_FEE_SAT = 10000; +var DUST_THRESHOLD = 5430; var initialized = false; var storage; @@ -434,6 +435,8 @@ CopayServer.prototype._selectUtxos = function(txp, utxos) { return; } catch (ex) { //if (ex.name != 'bitcore.ErrorTransactionFeeError') {} + //if (ex.name != 'bitcore.ErrorTransactionDustOutputs') {} + console.log(ex); } } i++; @@ -477,6 +480,9 @@ CopayServer.prototype.createTx = function(opts, cb) { if (toAddress.network != wallet.getNetworkName()) return cb(new ClientError('INVALIDADDRESS', 'Incorrect address network')); + if (opts.amount < DUST_THRESHOLD) + return cb(new ClientError('DUSTAMOUNT', 'Amount below dust threshold')); + self._getUtxos(function(err, utxos) { if (err) return cb(err); diff --git a/test/integration.js b/test/integration.js index 40c117c..c525c2b 100644 --- a/test/integration.js +++ b/test/integration.js @@ -771,7 +771,18 @@ describe('Copay server', function() { }); }); - it.skip('should fail to create tx for dust amount', function(done) {}); + it('should fail to create tx for dust amount', function(done) { + helpers.createUtxos(server, wallet, [1], function(utxos) { + helpers.stubBlockExplorer(server, utxos); + var txOpts = helpers.createProposalOpts('18PzpUFkFZE8zKWUPvfykkTxmB9oMR8qP7', 0.00000001, null, TestData.copayers[0].privKey); + server.createTx(txOpts, function(err, tx) { + should.exist(err); + err.code.should.equal('DUSTAMOUNT'); + err.message.should.equal('Amount below dust threshold'); + done(); + }); + }); + }); it('should create tx when there is a pending tx and enough UTXOs', function(done) { helpers.createUtxos(server, wallet, [10.1, 10.2, 10.3], function(utxos) { From 51e453730fc6f7e453cecc45662284bd2fcfc4e4 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Mon, 16 Feb 2015 15:00:41 -0300 Subject: [PATCH 4/4] use constants from Bitcore --- lib/server.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/server.js b/lib/server.js index 839f4f0..66b1985 100644 --- a/lib/server.js +++ b/lib/server.js @@ -25,9 +25,6 @@ var Address = require('./model/address'); var TxProposal = require('./model/txproposal'); var Notification = require('./model/Notification'); -var MINIMUM_FEE_SAT = 10000; -var DUST_THRESHOLD = 5430; - var initialized = false; var storage; @@ -427,16 +424,16 @@ CopayServer.prototype._selectUtxos = function(txp, utxos) { selected.push(inputs[i]); total += this._inputSatoshis(inputs[i]); - if (total >= txp.amount + MINIMUM_FEE_SAT) { + if (total >= txp.amount + Bitcore.Transaction.FEE_PER_KB) { try { // Check if there are enough fees txp.inputs = selected; var raw = txp.getRawTx(); return; } catch (ex) { - //if (ex.name != 'bitcore.ErrorTransactionFeeError') {} - //if (ex.name != 'bitcore.ErrorTransactionDustOutputs') {} - console.log(ex); + if (ex.name != 'bitcore.ErrorTransactionFeeError') { + throw ex.message; + } } } i++; @@ -480,7 +477,7 @@ CopayServer.prototype.createTx = function(opts, cb) { if (toAddress.network != wallet.getNetworkName()) return cb(new ClientError('INVALIDADDRESS', 'Incorrect address network')); - if (opts.amount < DUST_THRESHOLD) + if (opts.amount < Bitcore.Transaction.DUST_AMOUNT) return cb(new ClientError('DUSTAMOUNT', 'Amount below dust threshold')); self._getUtxos(function(err, utxos) { @@ -502,11 +499,15 @@ CopayServer.prototype.createTx = function(opts, cb) { requiredRejections: Math.min(wallet.m, wallet.n - wallet.m + 1), }); - self._selectUtxos(txp, utxos); - if (!txp.inputs) { - return cb(new ClientError('INSUFFICIENTFUNDS', 'Insufficient funds')); + try { + self._selectUtxos(txp, utxos); + } catch (ex) { + return cb(new ClientError(ex)); } + if (!txp.inputs) + return cb(new ClientError('INSUFFICIENTFUNDS', 'Insufficient funds')); + txp.inputPaths = _.pluck(txp.inputs, 'path'); self.storage.storeAddressAndWallet(wallet, changeAddress, function(err) {