fix order in receive

This commit is contained in:
Matias Alejo Garcia 2014-11-30 03:23:15 -03:00
commit abaf5b8f13
5 changed files with 109 additions and 69 deletions

View file

@ -1,7 +1,7 @@
'use strict'; 'use strict';
angular.module('copayApp.controllers').controller('ImportProfileController', 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.title = 'Import a backup';
$scope.importStatus = 'Importing wallet - Reading backup...'; $scope.importStatus = 'Importing wallet - Reading backup...';
$scope.hideAdv = true; $scope.hideAdv = true;
@ -18,6 +18,8 @@ angular.module('copayApp.controllers').controller('ImportProfileController',
var password = $scope.password; var password = $scope.password;
updateStatus('Importing profile - Setting things up...'); updateStatus('Importing profile - Setting things up...');
identityService.importProfile(str,password, function(err){
})
copay.Identity.importFromEncryptedFullJson(str, password, { copay.Identity.importFromEncryptedFullJson(str, password, {
pluginManager: pluginManager, pluginManager: pluginManager,
network: config.network, network: config.network,
@ -55,10 +57,8 @@ angular.module('copayApp.controllers').controller('ImportProfileController',
}; };
$scope.import = function(form) { $scope.import = function(form) {
$scope.loading = true;
if (form.$invalid) { if (form.$invalid) {
$scope.loading = false;
$scope.error = 'Please enter the required fields'; $scope.error = 'Please enter the required fields';
return; return;
} }
@ -67,11 +67,11 @@ angular.module('copayApp.controllers').controller('ImportProfileController',
var password = form.password.$modelValue; var password = form.password.$modelValue;
if (!backupFile && !backupText) { if (!backupFile && !backupText) {
$scope.loading = false;
$scope.error = 'Please, select your backup file'; $scope.error = 'Please, select your backup file';
return; return;
} }
$scope.loading = true;
if (backupFile) { if (backupFile) {
reader.readAsBinaryString(backupFile); reader.readAsBinaryString(backupFile);
} else { } else {

View file

@ -5,16 +5,14 @@ angular.module('copayApp.controllers').controller('ReceiveController',
$rootScope.title = 'Receive'; $rootScope.title = 'Receive';
$scope.loading = false; $scope.loading = false;
$scope.showAll = false; $scope.showAll = false;
$scope.isNewAddr = false;
$scope.newAddr = function() { $scope.newAddr = function() {
var w = $rootScope.wallet; var w = $rootScope.wallet;
$scope.loading = true; $scope.loading = true;
$scope.isNewAddr = false;
w.generateAddress(null); w.generateAddress(null);
$scope.setAddressList();
$timeout(function() { $timeout(function() {
$scope.loading = false; $scope.loading = false;
$scope.isNewAddr = true;
}, 1); }, 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.toggleShowAll = function() {
$scope.showAll = !$scope.showAll; $scope.showAll = !$scope.showAll;
$scope.addressList(); $scope.setAddressList();
}; };
$scope.limitAddress = function(elements, isNewAddr) { $scope.setAddressList = function() {
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 = [];
var w = $rootScope.wallet; var w = $rootScope.wallet;
var balance = $rootScope.balanceByAddr; var balance = $rootScope.balanceByAddr;
var addresses = w.getAddresses(); var addresses = w.getAddressesOrderer();
if (addresses) { if (addresses) {
$scope.addrLength = addresses.length; $scope.addrLength = addresses.length;
if (!$scope.showAll)
addresses = addresses.slice(0,3);
var list = [];
_.each(addresses, function(address, index){ _.each(addresses, function(address, index){
$scope.addresses.push({ list.push({
'index': index, 'index': index,
'address': address, 'address': address,
'balance': balance ? balance[address] : 0, 'balance': balance ? balance[address] : 0,
'isChange': w.addressIsChange(address), 'isChange': w.addressIsChange(address),
// TODO
'owned': w.addressIsOwn(address),
}); });
}); });
$scope.addresses = $scope.limitAddress($scope.addresses, $scope.isNewAddr); $scope.addresses = list;
} }
}; };
} }

View file

@ -49,8 +49,7 @@ function PublicKeyRing(opts) {
PublicKeyRing.prototype.resetCache = function() { PublicKeyRing.prototype.resetCache = function() {
this.cache = {}; this.cache = {};
this.cache.addressToPath = {}; this.cache.addressToPath = {};
this.cache.receiveAddresses = []; this.cache.pathToAddress = {};
this.cache.changeAddresses = [];
// Non persistent cache // Non persistent cache
this._isChange = {}; this._isChange = {};
@ -110,14 +109,26 @@ PublicKeyRing.fromObj = function(opts) {
pkr.addCopayer(opts.copayersExtPubKeys[k]); pkr.addCopayer(opts.copayersExtPubKeys[k]);
} }
if (opts.cache) { if (opts.cache && opts.cache.addressToPath) {
log.debug('PublicKeyRing: Using address cache'); log.info('PublicKeyRing: Using address cache');
pkr.cache = opts.cache; pkr.cache.addressToPath = opts.cache.addressToPath;
pkr.rebuildCache();
} }
return pkr; 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) { PublicKeyRing.fromUntrustedObj = function(opts) {
return PublicKeyRing.fromObj(PublicKeyRing.trim(opts)); return PublicKeyRing.fromObj(PublicKeyRing.trim(opts));
}; };
@ -140,7 +151,11 @@ PublicKeyRing.prototype.toObj = function() {
return b.extendedPublicKeyString(); return b.extendedPublicKeyString();
}), }),
nicknameFor: this.nicknameFor, 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...'); log.warn('Slow pubkey derivation...');
var path = HDPath.Branch(index, isChange, copayerIndex); var path = HDPath.Branch(index, isChange, copayerIndex);
var pubKeys = _.map(this.copayersHK, function(hdKey) { var pubKeys = _.map(this.copayersHK, function(hdKey) {
return hdKey.derive(path).eckey.public; return hdKey.derive(path).eckey.public;
}); });
return pubKeys; return pubKeys;
@ -353,6 +368,8 @@ PublicKeyRing.prototype.getRedeemScript = function(index, isChange, copayerIndex
PublicKeyRing.prototype._getAddress = function(index, isChange, id) { PublicKeyRing.prototype._getAddress = function(index, isChange, id) {
var copayerIndex = this.getCosigner(id); var copayerIndex = this.getCosigner(id);
var path = HDPath.FullBranch(index, isChange, copayerIndex); var path = HDPath.FullBranch(index, isChange, copayerIndex);
if (this.cache.pathToAddress[path])
return this.cache.pathToAddress[path];
log.info('Generating Address:', index, isChange, copayerIndex); log.info('Generating Address:', index, isChange, copayerIndex);
var script = this.getRedeemScript(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) { PublicKeyRing.prototype._cacheAddress = function(address, path, isChange) {
this.cache.addressToPath[address] = path; this.cache.addressToPath[address] = path;
if (isChange) this.cache.pathToAddress[path] = address;
this.cache.changeAddresses.push(address);
else
this.cache.receiveAddresses.push(address);
}; };
/** /**
@ -397,7 +411,7 @@ PublicKeyRing.prototype.getHDParams = function(id) {
* @return {HDPath} * @return {HDPath}
*/ */
PublicKeyRing.prototype.pathForAddress = function(address) { PublicKeyRing.prototype.pathForAddress = function(address) {
this._checkAndRebuildCache(); this._checkCache();
var path = this.cache.addressToPath[address]; var path = this.cache.addressToPath[address];
if (!path) throw new Error('Couldn\'t find path for address ' + address); if (!path) throw new Error('Couldn\'t find path for address ' + address);
return path; return path;
@ -439,20 +453,20 @@ PublicKeyRing.prototype.addressIsOwn = function(address) {
* @return {boolean} * @return {boolean}
*/ */
PublicKeyRing.prototype.addressIsChange = function(address) { PublicKeyRing.prototype.addressIsChange = function(address) {
this._checkAndRebuildCache(); this._checkCache();
if (!this.cache.addressToPath[address]) var path = this.cache.addressToPath[address];
if (!path)
return null; return null;
var p = HDPath.indexesForPath(path);
//Memoization Only, never stored. //Memoization Only, never stored.
if (_.isUndefined(this._isChange[address])) { this._isChange[address] = p.isChange;
this._isChange[address] = _.indexOf(this.cache.changeAddresses, address) >= 0;
}
return !!this._isChange[address]; return !!this._isChange[address];
}; };
/** /**
* @desc * @desc
* Maps a copayer's public key to his index in the keyring * 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) { PublicKeyRing.prototype.size = function(opts) {
// If cache exists, it has to be updated 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)) { if (_.isEmpty(this.cache.addressToPath)) {
this.buildAddressCache(); this.buildAddressCache();
} }
if (_.size(this.cache.addressToPath) !== this.size()) {
this.buildAddressCache();
}
}; };
@ -513,11 +536,39 @@ PublicKeyRing.prototype._checkAndRebuildCache = function(opts) {
* @returns {AddressInfo[]} * @returns {AddressInfo[]}
*/ */
PublicKeyRing.prototype.getAddresses = function() { PublicKeyRing.prototype.getAddresses = function() {
this._checkAndRebuildCache(); this._checkCache();
var ret = this.cache.receiveAddresses.concat(this.cache.changeAddresses); return _.keys(this.cache.addressToPath);
return ret;
}; };
/**
* 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 * @desc
* Gets information about addresses for a copayer * Gets information about addresses for a copayer
@ -526,9 +577,12 @@ PublicKeyRing.prototype.getAddresses = function() {
* @returns {AddressInfo[]} * @returns {AddressInfo[]}
*/ */
PublicKeyRing.prototype.getReceiveAddresses = function() { PublicKeyRing.prototype.getReceiveAddresses = function() {
this._checkAndRebuildCache(); this._checkCache();
var ret = this.cache.receiveAddresses;
return ret; var self = this;
return _.filter(this.getAddresses(), function(addr) {
return !self.addressIsChange(addr);
});
}; };

View file

@ -1961,6 +1961,17 @@ Wallet.prototype.getAddresses = function() {
return this.publicKeyRing.getAddresses(); 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} * @desc Alias for {@link PublicKeyRing#getAddresses}
* @return {Buffer[]} * @return {Buffer[]}

View file

@ -1,4 +1,4 @@
<div class="addresses" ng-controller="ReceiveController"> <div class="addresses" ng-controller="ReceiveController" ng-init="setAddressList()">
<div class="row"> <div class="row">
<div class="large-12 medium-12 small-12 columns"> <div class="large-12 medium-12 small-12 columns">
<h1 class="hide-for-large-up">{{$root.title}}</h1> <h1 class="hide-for-large-up">{{$root.title}}</h1>
@ -8,8 +8,8 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="large-12 columns" ng-if="!!(addresses|removeEmpty).length"> <div class="large-12 columns" ng-if="addresses.length">
<div ng-repeat="addr in addresses|removeEmpty|orderBy:'-index':true"> <div ng-repeat="addr in addresses">
<div class="panel"> <div class="panel">
<div class="row show-for-large-up"> <div class="row show-for-large-up">
<div class="large-7 medium-9 columns"> <div class="large-7 medium-9 columns">