From 9d5b26f52606ae6b377441942d2f71f49873837a Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Mon, 6 Oct 2014 18:51:45 -0300 Subject: [PATCH 1/3] Preserve sent timestamp for incoming proposals --- js/models/TxProposal.js | 4 +++- js/models/Wallet.js | 8 +++++--- test/Wallet.js | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/js/models/TxProposal.js b/js/models/TxProposal.js index 1c50459c9..7131bbe05 100644 --- a/js/models/TxProposal.js +++ b/js/models/TxProposal.js @@ -255,7 +255,9 @@ TxProposal.prototype.setSent = function(sentTxid) { this.sentTs = Date.now(); }; - +TxProposal.prototype.getSent = function(sentTxid) { + return !!this.sentTxid; +} TxProposal.prototype._allSignatures = function() { var ret = {}; diff --git a/js/models/Wallet.js b/js/models/Wallet.js index 0f26b9e4f..54b87dde9 100644 --- a/js/models/Wallet.js +++ b/js/models/Wallet.js @@ -405,9 +405,11 @@ Wallet.prototype._onTxProposal = function(senderId, data) { if (tx.isComplete()) { this._checkSentTx(m.ntxid, function(ret) { if (ret) { - m.txp.setSent(m.ntxid); - self.emit('txProposalsUpdated'); - self.store(); + if (!m.txp.getSent()) { + m.txp.setSent(m.ntxid); + self.emit('txProposalsUpdated'); + self.store(); + } } }); } else { diff --git a/test/Wallet.js b/test/Wallet.js index 2155eca83..8fd2fa218 100644 --- a/test/Wallet.js +++ b/test/Wallet.js @@ -1564,6 +1564,7 @@ describe('Wallet model', function() { var txp = { getSeen: sinon.stub().returns(true), setCopayers: sinon.stub().returns(['new copayer']), + getSent: sinon.stub().returns(false), setSent: sinon.spy(), builder: { build: sinon.stub().returns({ @@ -1595,6 +1596,7 @@ describe('Wallet model', function() { var txp = { getSeen: sinon.stub().returns(true), setCopayers: sinon.stub().returns(['new copayer']), + getSent: sinon.stub().returns(false), setSent: sinon.spy(), builder: { build: sinon.stub().returns({ @@ -1618,6 +1620,38 @@ describe('Wallet model', function() { done(); }); + it('should not overwrite sent info', function(done) { + var data = { + txProposal: { + dummy: 1, + }, + }; + var txp = { + getSeen: sinon.stub().returns(true), + setCopayers: sinon.stub().returns(['new copayer']), + getSent: sinon.stub().returns(true), + setSent: sinon.spy(), + builder: { + build: sinon.stub().returns({ + isComplete: sinon.stub().returns(true), + }), + }, + }; + + w.txProposals.merge = sinon.stub().returns({ + ntxid: 1, + txp: txp, + new: false, + hasChanged: false, + }); + w._checkSentTx = sinon.stub().yields(true); + + w._onTxProposal('senderID', data); + txp.setSent.called.should.be.false; + w.sendTxProposal.called.should.be.false; + done(); + }); + it('should resend when not complete only if changed', function(done) { var data = { txProposal: { From 7053c322c9116d6cca56405c6c12371f5b195580 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Mon, 6 Oct 2014 18:58:45 -0300 Subject: [PATCH 2/3] Only update TXs & balance once after changes to proposals --- js/services/controllerUtils.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/js/services/controllerUtils.js b/js/services/controllerUtils.js index 408ee22fc..b85ea766a 100644 --- a/js/services/controllerUtils.js +++ b/js/services/controllerUtils.js @@ -100,17 +100,17 @@ angular.module('copayApp.services') $rootScope.$digest(); }); - w.on('txProposalsUpdated', function(dontDigest) { + var updateTxsAndBalance = _.debounce(function() { root.updateTxs(); - // give sometime to the tx to propagate. - $timeout(function() { - root.updateBalance(function() { - if (!dontDigest) { - $rootScope.$digest(); - } - }); - }, 3000); + root.updateBalance(function() { + $rootScope.$digest(); + }) + }, 3000); + + w.on('txProposalsUpdated', function(dontDigest) { + updateTxsAndBalance(); }); + w.on('txProposalEvent', function(e) { var user = w.publicKeyRing.nicknameForCopayer(e.cId); From 807e7754a3811345aea1ee5978f58db9c8cd0313 Mon Sep 17 00:00:00 2001 From: Ivan Socolsky Date: Tue, 7 Oct 2014 12:17:27 -0300 Subject: [PATCH 3/3] Refactored TxProposal#getSent & tests --- js/models/TxProposal.js | 4 ++-- test/TxProposal.js | 42 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/js/models/TxProposal.js b/js/models/TxProposal.js index 7131bbe05..6570db64e 100644 --- a/js/models/TxProposal.js +++ b/js/models/TxProposal.js @@ -255,8 +255,8 @@ TxProposal.prototype.setSent = function(sentTxid) { this.sentTs = Date.now(); }; -TxProposal.prototype.getSent = function(sentTxid) { - return !!this.sentTxid; +TxProposal.prototype.getSent = function() { + return this.sentTs; } TxProposal.prototype._allSignatures = function() { diff --git a/test/TxProposal.js b/test/TxProposal.js index 4a2d857a0..c74f0ffcd 100644 --- a/test/TxProposal.js +++ b/test/TxProposal.js @@ -112,7 +112,11 @@ describe('TxProposal', function() { }); it('sets force opts', function() { var b = new FakeBuilder(); - b.opts={juan:1, pepe:1, fee:1000}; + b.opts = { + juan: 1, + pepe: 1, + fee: 1000 + }; var txp; var o = { creator: 1, @@ -121,9 +125,16 @@ describe('TxProposal', function() { inputChainPaths: ['m/1'], }; (function() { - txp = TxProposal.fromObj(o,{pepe:100}); + txp = TxProposal.fromObj(o, { + pepe: 100 + }); }).should.throw('Invalid tx proposal: no ins'); - o.builderObj.opts.should.deep.equal({juan:1, pepe:100, feeSat:undefined, fee:undefined}); + o.builderObj.opts.should.deep.equal({ + juan: 1, + pepe: 100, + feeSat: undefined, + fee: undefined + }); }); }); @@ -131,13 +142,36 @@ describe('TxProposal', function() { describe('#setSent', function() { it('should set txid and timestamp', function() { var now = Date.now(); - var txp = dummyProposal; + var txp = new TxProposal({ + creator: 1, + createdTs: 1, + builder: new FakeBuilder(), + inputChainPaths: ['m/1'], + }); txp.setSent('3a42'); txp.sentTs.should.gte(now); txp.sentTxid.should.equal('3a42'); }); }); + describe('#getSent', function() { + it('should get sent timestamp', function() { + var now = Date.now(); + var txp = new TxProposal({ + creator: 1, + createdTs: 1, + builder: new FakeBuilder(), + inputChainPaths: ['m/1'], + }); + + var sentTs = txp.getSent(); + should.not.exist(sentTs); + + txp.setSent('3a42'); + sentTs = txp.getSent(); + sentTs.should.gte(now); + }); + }); describe('Signature verification', function() { var validScriptSig = new bitcore.Script(FakeBuilder.VALID_SCRIPTSIG_BUF);