From 26c829f6de84a101bc2737f6d4ac33be18f2ddad Mon Sep 17 00:00:00 2001 From: Yemel Jardi Date: Thu, 19 Jun 2014 10:30:53 -0300 Subject: [PATCH 1/3] Add validation and tests for spendUnconfirmed = false --- config.js | 2 +- js/models/core/Wallet.js | 3 ++- test/mocks/FakeBlockchain.js | 14 ++++++++++++++ test/test.Wallet.js | 35 ++++++++++++++++++++++++++++++----- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/config.js b/config.js index a15369429..5f33dfdfe 100644 --- a/config.js +++ b/config.js @@ -89,7 +89,7 @@ var defaultConfig = { wallet: { requiredCopayers: 2, totalCopayers: 3, - spendUnconfirmed: 1, + spendUnconfirmed: true, verbose: 1, reconnectDelay: 5000, }, diff --git a/js/models/core/Wallet.js b/js/models/core/Wallet.js index f0e94993d..6e437b1c4 100644 --- a/js/models/core/Wallet.js +++ b/js/models/core/Wallet.js @@ -647,7 +647,8 @@ Wallet.prototype.getUnspent = function(cb) { for (var i in unspentList) { var u = unspentList[i]; - if (!uu[u.txid + ',' + u.vout]) + var name = u.txid + ',' + u.vout; + if (!uu[name] && (self.spendUnconfirmed || u.confirmations >= 1)) safeUnspendList.push(u); } diff --git a/test/mocks/FakeBlockchain.js b/test/mocks/FakeBlockchain.js index 6a1c27a78..bfacb1924 100644 --- a/test/mocks/FakeBlockchain.js +++ b/test/mocks/FakeBlockchain.js @@ -30,6 +30,20 @@ FakeBlockchain.prototype.getUnspent = function(addresses, cb) { }]); }; +FakeBlockchain.prototype.getUnspent2 = function(addresses, cb) { + if (!addresses || !addresses.length) return cb(null, []); + return cb(null, this.u || [{ + 'address': 'mji7zocy8QzYywQakwWf99w9bCT6orY1C1', + 'txid': '0be0fb4579911be829e3077202e1ab47fcc12cf3ab8f8487ccceae768e1f95fa', + 'vout': 0, + 'ts': 1402323949, + 'scriptPubKey': '21032ca453c1d9a93b7de8cf3d44d7bb8d52a45dbdf8fff63f69de4e51b740bb1da3ac', + 'amount': 25.0001, + 'confirmations': 1, + 'confirmationsFromCache': false + }]); +}; + FakeBlockchain.prototype.sendRawTransaction = function(rawtx, cb) { var txid = '0be0fb4579911be829e3077202e1ab47fcc12cf3ab8f8487ccceae768e1f95fa'; return cb(txid); diff --git a/test/test.Wallet.js b/test/test.Wallet.js index 4c89a54b4..68aca9d9c 100644 --- a/test/test.Wallet.js +++ b/test/test.Wallet.js @@ -26,7 +26,7 @@ describe('Wallet model', function() { var config = { requiredCopayers: 3, totalCopayers: 5, - spendUnconfirmed: 1, + spendUnconfirmed: true, reconnectDelay: 100, networkName: 'testnet', }; @@ -42,9 +42,9 @@ describe('Wallet model', function() { w.getNetworkName().should.equal('testnet'); }); - var createW = function(netKey, N) { + var createW = function(netKey, N, conf) { - var c = JSON.parse(JSON.stringify(config)); + var c = JSON.parse(JSON.stringify(conf || config)); if (!N) N = c.totalCopayers; if (netKey) c.netKey = netKey; @@ -122,10 +122,10 @@ describe('Wallet model', function() { "confirmations": 7 }]; - var createW2 = function(privateKeys, N) { + var createW2 = function(privateKeys, N, conf) { if (!N) N = 3; var netKey = 'T0FbU2JLby0='; - var w = createW(netKey, N); + var w = createW(netKey, N, conf); should.exist(w); var pkr = w.publicKeyRing; @@ -467,6 +467,31 @@ describe('Wallet model', function() { }); }); + it('#getUnspent should honor spendUnconfirmed = false', function(done) { + var conf = JSON.parse(JSON.stringify(config)); + conf.spendUnconfirmed = false; + var w = createW2(null, null, conf); + w.getBalance(function(err, balance, balanceByAddr, safeBalance) { + balance.should.equal(2500010000); + safeBalance.should.equal(0); + balanceByAddr.mji7zocy8QzYywQakwWf99w9bCT6orY1C1.should.equal(2500010000); + done(); + }); + }); + + it('#getUnspent and spendUnconfirmed should count transactions with 1 confirmations', function(done) { + var conf = JSON.parse(JSON.stringify(config)); + conf.spendUnconfirmed = false; + var w = createW2(null, null, conf); + w.blockchain.getUnspent = w.blockchain.getUnspent2; + w.getBalance(function(err, balance, balanceByAddr, safeBalance) { + balance.should.equal(2500010000); + safeBalance.should.equal(2500010000); + balanceByAddr.mji7zocy8QzYywQakwWf99w9bCT6orY1C1.should.equal(2500010000); + done(); + }); + }); + var roundErrorChecks = [{ unspent: [1.0001], balance: 100010000 From e1dc275ddd73dba360a2528495c8e14e713b2af9 Mon Sep 17 00:00:00 2001 From: Yemel Jardi Date: Mon, 23 Jun 2014 14:57:23 -0300 Subject: [PATCH 2/3] Refresh balance on new block --- js/services/controllerUtils.js | 9 +++++++++ js/services/socket.js | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/js/services/controllerUtils.js b/js/services/controllerUtils.js index 2dac5eb13..4cfc731f5 100644 --- a/js/services/controllerUtils.js +++ b/js/services/controllerUtils.js @@ -292,6 +292,15 @@ angular.module('copayApp.services') }); }); }); + + if (!$rootScope.wallet.spendUnconfirmed && !Socket.isListeningBlocks()) { + Socket.emit('subscribe', 'inv'); + Socket.on('block', function(block) { + root.updateBalance(function() { + $rootScope.$digest(); + }); + }); + } }; return root; }); diff --git a/js/services/socket.js b/js/services/socket.js index dcbeabd95..10f843b6f 100644 --- a/js/services/socket.js +++ b/js/services/socket.js @@ -38,6 +38,7 @@ angular.module('copayApp.services').factory('Socket', var ret = {}; var addrList = listeners + .filter(function(i) { return i.event != 'block'; }) .map(function(i) {return i.event;}); for (var i in addrList) { @@ -45,6 +46,9 @@ angular.module('copayApp.services').factory('Socket', } return ret; }, + isListeningBlocks: function() { + return listeners.filter(function(i) { return i.event == 'block'; }).length > 0; + }, emit: function(event, data, callback) { socket.emit(event, data, function() { var args = arguments; From 970a6f3d3748bcaaa27710a05521880643d9c774 Mon Sep 17 00:00:00 2001 From: Yemel Jardi Date: Mon, 23 Jun 2014 15:05:06 -0300 Subject: [PATCH 3/3] Add tests for block events at Socket service --- test/unit/services/servicesSpec.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/unit/services/servicesSpec.js b/test/unit/services/servicesSpec.js index 8940bb70a..9e658c42b 100644 --- a/test/unit/services/servicesSpec.js +++ b/test/unit/services/servicesSpec.js @@ -41,6 +41,14 @@ describe("Unit: Socket Service", function() { expect(Object.keys(ret)).to.have.length(2); })); + it('Socket should support block event', inject(function(Socket) { + expect(Socket.isListeningBlocks()).to.be.false; + Socket.on('block', function() {}); + expect(Socket.isListeningBlocks()).to.be.true; + Socket.removeAllListeners(); + expect(Socket.isListeningBlocks()).to.be.false; + })); + it('Socket should support #removeAllListeners', inject(function(Socket) { Socket.on('a', function() {}); Socket.on('b', function() {});