From 431a66eeb2c502f2058f0f90071647cecdbf2267 Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Fri, 7 Nov 2014 12:22:05 -0300 Subject: [PATCH 1/2] Refresh list of pending transactions proposals after any events --- js/controllers/history.js | 23 +----- js/controllers/send.js | 7 +- js/controllers/sidebar.js | 4 -- js/models/Wallet.js | 71 ++++++++++++++++++- js/services/controllerUtils.js | 124 +++++++++------------------------ views/send.html | 8 +-- 6 files changed, 108 insertions(+), 129 deletions(-) diff --git a/js/controllers/history.js b/js/controllers/history.js index 01868c399..72a1e5b93 100644 --- a/js/controllers/history.js +++ b/js/controllers/history.js @@ -16,24 +16,10 @@ angular.module('copayApp.controllers').controller('HistoryController', $scope.blockchain_txs = []; $scope.alternativeCurrency = []; - var satToUnit = 1 / w.settings.unitToSatoshi; - - $scope.update = function() { - $scope.loading = true; - var from = ($scope.txpCurrentPage - 1) * $scope.txpItemsPerPage; - var opts = { - pending: false, - skip: [from, from + $scope.txpItemsPerPage] - }; - controllerUtils.updateTxs(opts); - setTimeout(function() { - $rootScope.$digest(); - }, 0); + $scope.getTransactions(); }; - - $scope.show = function() { $scope.loading = true; setTimeout(function() { @@ -61,9 +47,6 @@ angular.module('copayApp.controllers').controller('HistoryController', _.each(res, function(r) { r.ts = r.minedTs || r.sentTs; - if (r.action === 'sent' && r.peerActions) { - r.actionList = controllerUtils.getActionList(r.peerActions); - } }); $scope.blockchain_txs = w.cached_txs = res; $scope.loading = false; @@ -76,13 +59,11 @@ angular.module('copayApp.controllers').controller('HistoryController', $scope.hasAction = function(actions, action) { return actions.hasOwnProperty('create'); - } + }; $scope.getShortNetworkName = function() { var w = $rootScope.wallet; return w.getNetworkName().substring(0, 4); }; - // Autoload transactions - $scope.getTransactions(); }); diff --git a/js/controllers/send.js b/js/controllers/send.js index 46eb1d7cb..7461609a6 100644 --- a/js/controllers/send.js +++ b/js/controllers/send.js @@ -72,11 +72,8 @@ angular.module('copayApp.controllers').controller('SendController', }); $scope.loadTxs = function() { - var opts = { - pending: true, - skip: null - }; - controllerUtils.updateTxs(opts); + controllerUtils.updateTxs(); + setTimeout(function() { $scope.loading = false; $rootScope.$digest(); diff --git a/js/controllers/sidebar.js b/js/controllers/sidebar.js index 97eb4ea50..bf42dce01 100644 --- a/js/controllers/sidebar.js +++ b/js/controllers/sidebar.js @@ -72,10 +72,6 @@ angular.module('copayApp.controllers').controller('SidebarController', function( if (controllerUtils.isFocusedWallet(wid)) return; var w = $rootScope.iden.getWalletById(wid); $scope.wallets.push(w); - controllerUtils.updateTxs({ - wallet: w, - pending: true - }); controllerUtils.updateBalance(w, function() { $rootScope.$digest(); }) diff --git a/js/models/Wallet.js b/js/models/Wallet.js index 6f66162f6..1f961434e 100644 --- a/js/models/Wallet.js +++ b/js/models/Wallet.js @@ -361,7 +361,7 @@ Wallet.prototype._processProposalEvents = function(senderId, m) { } else { ev = { type: 'corrupt', - cId: senderId, + cId: senderId }; } if (ev) @@ -513,7 +513,7 @@ Wallet.prototype._onReject = function(senderId, data) { this.emitAndKeepAlive('txProposalEvent', { type: 'rejected', cId: senderId, - txId: data.ntxid, + txId: data.ntxid }); }; @@ -536,7 +536,7 @@ Wallet.prototype._onSeen = function(senderId, data) { this.emitAndKeepAlive('txProposalEvent', { type: 'seen', cId: senderId, - txId: data.ntxid, + txId: data.ntxid }); }; @@ -1281,6 +1281,64 @@ Wallet.prototype.getTxProposals = function() { return ret; }; +/** + * @desc get list of actions (see {@link getPendingTxProposals}) + */ +Wallet.prototype._getActionList = function(actions) { + if (!actions) return; + var peers = Object.keys(actions).map(function(i) { + return { + cId: i, + actions: actions[i] + } + }); + + return peers.sort(function(a, b) { + return !!b.actions.create - !!a.actions.create; + }); +}; + +/** + * @desc Retrieve Pendings Transaction proposals (see {@link TxProposals}) + * @return {Object[]} each object returned represents a transaction proposal + */ +Wallet.prototype.getPendingTxProposals = function() { + var that = this; + var ret = []; + ret.txs = []; + var pendingForUs = 0; + var txps = this.getTxProposals(); + var satToUnit = 1 / this.settings.unitToSatoshi; + + _.find(txps, function(txp) { + if (txp.isPending) { + pendingForUs++; + var tx = txp.builder.build(); + var outs = []; + tx.outs.forEach(function(o) { + var addr = bitcore.Address.fromScriptPubKey(o.getScript(), that.getNetworkName())[0].toString(); + if (!that.addressIsOwn(addr, { + excludeMain: true + })) { + outs.push({ + address: addr, + value: bitcore.util.valueToBigInt(o.getValue()) * satToUnit, + }); + } + }); + // extra fields + txp.outs = outs; + txp.fee = txp.builder.feeSat * satToUnit; + txp.missingSignatures = tx.countInputMissingSignatures(0); + txp.actionList = that._getActionList(txp.peerActions); + ret.txs.push(txp); + } + }); + + ret.pendingForUs = pendingForUs; + return ret; +}; + /** * @desc Removes old transactions * @param {boolean} deleteAll - if true, remove all the transactions @@ -2882,6 +2940,13 @@ Wallet.prototype.getTransactionHistory = function(cb) { tx.merchant = proposal.merchant; tx.peerActions = proposal.peerActions; tx.finallyRejected = proposal.finallyRejected; + tx.merchant = proposal.merchant; + tx.peerActions = proposal.peerActions; + tx.finallyRejected = proposal.finallyRejected; + + if (tx.peerActions) { + tx.actionList = self._getActionList(tx.peerActions); + } } }; diff --git a/js/services/controllerUtils.js b/js/services/controllerUtils.js index ee5129272..610e331ee 100644 --- a/js/services/controllerUtils.js +++ b/js/services/controllerUtils.js @@ -63,13 +63,10 @@ angular.module('copayApp.services') root.updateTxsAndBalance = _.debounce(function(w) { - root.updateTxs({ - wallet: w, - pending: true, - }); + root.updateTxs(); root.updateBalance(w, function() { $rootScope.$digest(); - }) + }); }, 3000); root.installWalletHandlers = function($scope, w) { @@ -139,19 +136,29 @@ angular.module('copayApp.services') w.on('txProposalEvent', function(e) { + root.updateTxsAndBalance(w); // TODO: add wallet name notification var user = w.publicKeyRing.nicknameForCopayer(e.cId); + var name = w.getName(); switch (e.type) { + case 'new': + notification.info('['+ name +'] New Transaction', + $filter('translate')('You received a transaction proposal from') + ' ' + user); + break; case 'signed': - notification.info('Transaction Update', $filter('translate')('A transaction was signed by') + ' ' + user); + notification.info('['+ name +'] Transaction Signed', + $filter('translate')('A transaction was signed by') + ' ' + user); break; case 'rejected': - notification.info('Transaction Update', $filter('translate')('A transaction was rejected by') + ' ' + user); + notification.info('['+ name +'] Transaction Rejected', + $filter('translate')('A transaction was rejected by') + ' ' + user); break; case 'corrupt': - notification.error('Transaction Error', $filter('translate')('Received corrupt transaction from') + ' ' + user); + notification.error('['+ name +'] Transaction Error', + $filter('translate')('Received corrupt transaction from') + ' ' + user); break; } + $rootScope.$digest(); }); w.on('addressBookUpdated', function(dontDigest) { if (root.isFocusedWallet(wid)) { @@ -210,6 +217,7 @@ angular.module('copayApp.services') $rootScope.wallet = w; w.updateFocusedTimestamp(Date.now()); root.redirIfLogged(); + root.updateTxs(); root.updateBalance(w, function() { $rootScope.$digest(); }) @@ -323,75 +331,26 @@ angular.module('copayApp.services') }); }; - root.updateTxs = function(opts) { - function computeAlternativeAmount(w, tx, cb) { - rateService.whenAvailable(function() { - _.each(tx.outs, function(out) { - var valueSat = out.value * w.settings.unitToSatoshi; - out.alternativeAmount = rateService.toFiat(valueSat, w.settings.alternativeIsoCode); - out.alternativeIsoCode = w.settings.alternativeIsoCode; - }); - if (cb) return cb(); + root.computeAlternativeAmount = function(w, tx, cb) { + rateService.whenAvailable(function() { + _.each(tx.outs, function(out) { + var valueSat = out.value * w.settings.unitToSatoshi; + out.alternativeAmount = rateService.toFiat(valueSat, w.settings.alternativeIsoCode); + out.alternativeIsoCode = w.settings.alternativeIsoCode; }); - }; - - var w = opts.wallet || $rootScope.wallet; - if (!w) return; - opts = opts || $rootScope.txsOpts || {}; - - var satToUnit = 1 / w.settings.unitToSatoshi; - var myCopayerId = w.getMyCopayerId(); - var pendingForUs = 0; - var inT = w.getTxProposals().sort(function(t1, t2) { - return t2.createdTs - t1.createdTs + if (cb) return cb(tx); }); - var txs = []; + }; - inT.forEach(function(i, index) { - if (opts.skip && (index < opts.skip[0] || index >= opts.skip[1])) { - return txs.push(null); - } - - if (i.isPending && myCopayerId != i.creator && !i.rejectedByUs && !i.signedByUs) { - pendingForUs++; - } - - if (!!opts.pending == !!i.isPending) { - var tx = i.builder.build(); - var outs = []; - tx.outs.forEach(function(o) { - var addr = bitcore.Address.fromScriptPubKey(o.getScript(), w.getNetworkName())[0].toString(); - if (!w.addressIsOwn(addr, { - excludeMain: true - })) { - outs.push({ - address: addr, - value: bitcore.util.valueToBigInt(o.getValue()) * satToUnit, - }); - } - }); - // extra fields - i.outs = outs; - i.fee = i.builder.feeSat * satToUnit; - i.missingSignatures = tx.countInputMissingSignatures(0); - i.actionList = getActionList(i.peerActions); - if (i.isPending) { - computeAlternativeAmount(w, i); - } - txs.push(i); - } - }); - - // Disabling this as discrepancies in local time on copayer machines is causing - // valid TXPs to get removed - //w.removeTxWithSpentInputs(); - - $rootScope.txs = txs; - $rootScope.txsOpts = opts; - if ($rootScope.pendingTxCount < pendingForUs) { - $rootScope.txAlertCount = pendingForUs; + root.updateTxs = function() { + var w = $rootScope.wallet; + if (!w) return root.onErrorDigest(); + var res = w.getPendingTxProposals(); + $rootScope.txps = res.txs; + if ($rootScope.pendingTxCount < res.pendingForUs) { + $rootScope.txAlertCount = res.pendingForUs; } - $rootScope.pendingTxCount = pendingForUs; + $rootScope.pendingTxCount = res.pendingForUs; }; root.deleteWallet = function($scope, w) { @@ -404,24 +363,5 @@ angular.module('copayApp.services') }); }; - root.getActionList = function(actions) { - return getActionList(actions); - }; - - function getActionList(actions) { - var peers = Object.keys(actions).map(function(i) { - return { - cId: i, - actions: actions[i] - } - }); - - return peers.sort(function(a, b) { - return !!b.actions.create - !!a.actions.create; - }); - } - - - return root; }); diff --git a/views/send.html b/views/send.html index 3ee7db97d..6a49ed54f 100644 --- a/views/send.html +++ b/views/send.html @@ -1,15 +1,15 @@ -
+
-
+

Pending Transactions Proposals

-
+

{{$root.title}}

From 49792d9485975a5f82c5acb2d1fc50df03a3e97d Mon Sep 17 00:00:00 2001 From: Gustavo Maximiliano Cortez Date: Fri, 7 Nov 2014 13:59:55 -0300 Subject: [PATCH 2/2] fix test --- test/unit/controllers/controllersSpec.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/unit/controllers/controllersSpec.js b/test/unit/controllers/controllersSpec.js index 13a990411..ecbe640ea 100644 --- a/test/unit/controllers/controllersSpec.js +++ b/test/unit/controllers/controllersSpec.js @@ -43,6 +43,7 @@ describe("Unit: Controllers", function() { scope = $rootScope.$new(); $rootScope.iden = sinon.stub(); $rootScope.safeUnspentCount = 1; + $rootScope.pendingTxCount = 0; var w = {}; w.isReady = sinon.stub().returns(true); @@ -72,7 +73,10 @@ describe("Unit: Controllers", function() { w.sendTx = sinon.stub().yields(null); w.requiresMultipleSignatures = sinon.stub().returns(true); w.getTxProposals = sinon.stub().returns([1, 2, 3]); - + w.getPendingTxProposals = sinon.stub().returns({ + txs : [{ isPending : true }], + pendingForUs: 1 + }); $rootScope.wallet = w; }));