diff --git a/js/controllers/importProfile.js b/js/controllers/importProfile.js index b9f07e7cb..1c36c934a 100644 --- a/js/controllers/importProfile.js +++ b/js/controllers/importProfile.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('copayApp.controllers').controller('ImportProfileController', - function($scope, $rootScope, $location, notification, isMobile, pluginManager, identityService) { + function($scope, $rootScope, $location, notification, isMobile, identityService) { $scope.title = 'Import a backup'; $scope.importStatus = 'Importing wallet - Reading backup...'; $scope.hideAdv = true; @@ -18,6 +18,8 @@ angular.module('copayApp.controllers').controller('ImportProfileController', var password = $scope.password; updateStatus('Importing profile - Setting things up...'); + identityService.importProfile(str,password, function(err){ + }) copay.Identity.importFromEncryptedFullJson(str, password, { pluginManager: pluginManager, network: config.network, @@ -55,10 +57,8 @@ angular.module('copayApp.controllers').controller('ImportProfileController', }; $scope.import = function(form) { - $scope.loading = true; if (form.$invalid) { - $scope.loading = false; $scope.error = 'Please enter the required fields'; return; } @@ -67,11 +67,11 @@ angular.module('copayApp.controllers').controller('ImportProfileController', var password = form.password.$modelValue; if (!backupFile && !backupText) { - $scope.loading = false; $scope.error = 'Please, select your backup file'; return; } + $scope.loading = true; if (backupFile) { reader.readAsBinaryString(backupFile); } else { diff --git a/js/controllers/receive.js b/js/controllers/receive.js index 9401aa1e2..39cfac733 100644 --- a/js/controllers/receive.js +++ b/js/controllers/receive.js @@ -5,16 +5,14 @@ angular.module('copayApp.controllers').controller('ReceiveController', $rootScope.title = 'Receive'; $scope.loading = false; $scope.showAll = false; - $scope.isNewAddr = false; $scope.newAddr = function() { var w = $rootScope.wallet; $scope.loading = true; - $scope.isNewAddr = false; w.generateAddress(null); + $scope.setAddressList(); $timeout(function() { $scope.loading = false; - $scope.isNewAddr = true; }, 1); }; @@ -39,55 +37,32 @@ angular.module('copayApp.controllers').controller('ReceiveController', }); }; - $rootScope.$watch('addrInfos', function() { - if ($rootScope.updatingBalance) return; - $scope.addressList(); - }); - $scope.toggleShowAll = function() { $scope.showAll = !$scope.showAll; - $scope.addressList(); + $scope.setAddressList(); }; - $scope.limitAddress = function(elements, isNewAddr) { - - if(!isNewAddr){ - elements = elements.sort(function(a, b) { - return (+a.isChange - +b.isChange); - }); - } - - if (elements.length <= 1 || $scope.showAll) { - return elements; - } - - // Show last 3 non-change addresses plus those with balance - var addrs = elements.filter(function(e, i) { - return (!e.isChange && i < 3) || (e.balance && e.balance > 0); - }); - - return addrs; - }; - - $scope.addressList = function() { - $scope.addresses = []; + $scope.setAddressList = function() { var w = $rootScope.wallet; var balance = $rootScope.balanceByAddr; - var addresses = w.getAddresses(); + var addresses = w.getAddressesOrderer(); if (addresses) { $scope.addrLength = addresses.length; + + if (!$scope.showAll) + addresses = addresses.slice(0,3); + + var list = []; _.each(addresses, function(address, index){ - $scope.addresses.push({ + list.push({ 'index': index, 'address': address, 'balance': balance ? balance[address] : 0, 'isChange': w.addressIsChange(address), - // TODO - 'owned': w.addressIsOwn(address), }); }); - $scope.addresses = $scope.limitAddress($scope.addresses, $scope.isNewAddr); + $scope.addresses = list; } }; } diff --git a/js/models/PublicKeyRing.js b/js/models/PublicKeyRing.js index 083708bac..b4ee1529f 100644 --- a/js/models/PublicKeyRing.js +++ b/js/models/PublicKeyRing.js @@ -49,8 +49,7 @@ function PublicKeyRing(opts) { PublicKeyRing.prototype.resetCache = function() { this.cache = {}; this.cache.addressToPath = {}; - this.cache.receiveAddresses = []; - this.cache.changeAddresses = []; + this.cache.pathToAddress = {}; // Non persistent cache this._isChange = {}; @@ -110,14 +109,26 @@ PublicKeyRing.fromObj = function(opts) { pkr.addCopayer(opts.copayersExtPubKeys[k]); } - if (opts.cache) { - log.debug('PublicKeyRing: Using address cache'); - pkr.cache = opts.cache; + if (opts.cache && opts.cache.addressToPath) { + log.info('PublicKeyRing: Using address cache'); + pkr.cache.addressToPath = opts.cache.addressToPath; + pkr.rebuildCache(); } return pkr; }; + +PublicKeyRing.prototype.rebuildCache = function() { + if (!this.cache.addressToPath) + return; + + var self = this; + _.each(this.cache.addressToPath, function(path, address) { + self.cache.pathToAddress[path] = address; + }); +}; + PublicKeyRing.fromUntrustedObj = function(opts) { return PublicKeyRing.fromObj(PublicKeyRing.trim(opts)); }; @@ -140,7 +151,11 @@ PublicKeyRing.prototype.toObj = function() { return b.extendedPublicKeyString(); }), nicknameFor: this.nicknameFor, - cache: this.cache, + + // We only store addressToPath and derive the reset from it + cache: { + addressToPath: this.cache.addressToPath + }, }; }; @@ -314,7 +329,7 @@ PublicKeyRing.prototype.getPubKeys = function(index, isChange, copayerIndex) { log.warn('Slow pubkey derivation...'); var path = HDPath.Branch(index, isChange, copayerIndex); var pubKeys = _.map(this.copayersHK, function(hdKey) { - return hdKey.derive(path).eckey.public; + return hdKey.derive(path).eckey.public; }); return pubKeys; @@ -353,6 +368,8 @@ PublicKeyRing.prototype.getRedeemScript = function(index, isChange, copayerIndex PublicKeyRing.prototype._getAddress = function(index, isChange, id) { var copayerIndex = this.getCosigner(id); var path = HDPath.FullBranch(index, isChange, copayerIndex); + if (this.cache.pathToAddress[path]) + return this.cache.pathToAddress[path]; log.info('Generating Address:', index, isChange, copayerIndex); var script = this.getRedeemScript(index, isChange, copayerIndex); @@ -364,10 +381,7 @@ PublicKeyRing.prototype._getAddress = function(index, isChange, id) { PublicKeyRing.prototype._cacheAddress = function(address, path, isChange) { this.cache.addressToPath[address] = path; - if (isChange) - this.cache.changeAddresses.push(address); - else - this.cache.receiveAddresses.push(address); + this.cache.pathToAddress[path] = address; }; /** @@ -397,7 +411,7 @@ PublicKeyRing.prototype.getHDParams = function(id) { * @return {HDPath} */ PublicKeyRing.prototype.pathForAddress = function(address) { - this._checkAndRebuildCache(); + this._checkCache(); var path = this.cache.addressToPath[address]; if (!path) throw new Error('Couldn\'t find path for address ' + address); return path; @@ -439,20 +453,20 @@ PublicKeyRing.prototype.addressIsOwn = function(address) { * @return {boolean} */ PublicKeyRing.prototype.addressIsChange = function(address) { - this._checkAndRebuildCache(); + this._checkCache(); - if (!this.cache.addressToPath[address]) + var path = this.cache.addressToPath[address]; + if (!path) return null; + var p = HDPath.indexesForPath(path); + //Memoization Only, never stored. - if (_.isUndefined(this._isChange[address])) { - this._isChange[address] = _.indexOf(this.cache.changeAddresses, address) >= 0; - } + this._isChange[address] = p.isChange; return !!this._isChange[address]; }; - /** * @desc * Maps a copayer's public key to his index in the keyring @@ -497,11 +511,20 @@ PublicKeyRing.prototype.buildAddressCache = function() { }; -PublicKeyRing.prototype._checkAndRebuildCache = function(opts) { - // If cache exists, it has to be updated +PublicKeyRing.prototype.size = function(opts) { + var self = this; + return _.reduce(this.indexes, function(sum, index) { + return sum + index.receiveIndex + index.changeIndex + }, 0); +}; + +PublicKeyRing.prototype._checkCache = function(opts) { if (_.isEmpty(this.cache.addressToPath)) { this.buildAddressCache(); } + if (_.size(this.cache.addressToPath) !== this.size()) { + this.buildAddressCache(); + } }; @@ -513,11 +536,39 @@ PublicKeyRing.prototype._checkAndRebuildCache = function(opts) { * @returns {AddressInfo[]} */ PublicKeyRing.prototype.getAddresses = function() { - this._checkAndRebuildCache(); - var ret = this.cache.receiveAddresses.concat(this.cache.changeAddresses); - return ret; + this._checkCache(); + return _.keys(this.cache.addressToPath); }; +/** + * getAddressesOrderer + * {@link Wallet#getAddressesOrderer} + * + * @param pubkey + * @return {string[]} + */ +PublicKeyRing.prototype.getAddressesOrderer = function(pubkey) { + this._checkCache(); + + var info = _.map(this.cache.addressToPath, function(path, addr) { + var p = HDPath.indexesForPath(path); + p.address = addr; + return p; + }); + + var copayerIndex = this.getCosigner(pubkey); + var l = info.length; + + var sortedInfo = _.sortBy(info, function(i) { + var goodness = ( (i.copayerIndex !== copayerIndex) ? 2 * l : 0 ) +( i.isChange ? l : 0 ) + l - i.addressIndex; + return goodness; + }); + + return _.pluck(sortedInfo, 'address'); +}; + + + /** * @desc * Gets information about addresses for a copayer @@ -526,9 +577,12 @@ PublicKeyRing.prototype.getAddresses = function() { * @returns {AddressInfo[]} */ PublicKeyRing.prototype.getReceiveAddresses = function() { - this._checkAndRebuildCache(); - var ret = this.cache.receiveAddresses; - return ret; + this._checkCache(); + + var self = this; + return _.filter(this.getAddresses(), function(addr) { + return !self.addressIsChange(addr); + }); }; diff --git a/js/models/Wallet.js b/js/models/Wallet.js index e2315a425..395f00639 100644 --- a/js/models/Wallet.js +++ b/js/models/Wallet.js @@ -1961,6 +1961,17 @@ Wallet.prototype.getAddresses = function() { return this.publicKeyRing.getAddresses(); }; + +/** + * @desc gets the list of addresses, orderder for the caller: + * 1) himselfs first + * 2) receive address first + * 3) last created first + */ +Wallet.prototype.getAddressesOrderer = function() { + return this.publicKeyRing.getAddressesOrderer(this.publicKey); +}; + /** * @desc Alias for {@link PublicKeyRing#getAddresses} * @return {Buffer[]} diff --git a/views/receive.html b/views/receive.html index 9801885b1..709218c26 100644 --- a/views/receive.html +++ b/views/receive.html @@ -1,4 +1,4 @@ -
+

{{$root.title}}

@@ -8,8 +8,8 @@
-
-
+
+