From 74d9f4d93b76551305d08471a84a929e4f745300 Mon Sep 17 00:00:00 2001
From: blavenie <benoit.lavenier@e-is.pro>
Date: Fri, 26 Aug 2016 14:57:28 +0200
Subject: [PATCH]  - TX : fix #120 TX must not create output base lower than
 input  - Account wizard : logout if failed - fix #98

---
 www/js/controllers/home-controllers.js   |  17 ++-
 www/js/controllers/wallet-controllers.js |  85 ++++--------
 www/js/services/wallet-services.js       | 168 ++++++++++++++++-------
 3 files changed, 161 insertions(+), 109 deletions(-)

diff --git a/www/js/controllers/home-controllers.js b/www/js/controllers/home-controllers.js
index 257f56f9e..b47d7861d 100644
--- a/www/js/controllers/home-controllers.js
+++ b/www/js/controllers/home-controllers.js
@@ -114,8 +114,16 @@ function NewAccountModalController($scope, $state, UIUtils, CryptoUtils, Wallet,
       return;
     }
 
+    var onErrorLogout = function(message) {
+      return function(err) {
+        Wallet.logout()
+        .then(function(){
+          UIUtils.onError(message)(err);
+        });
+      }
+    }
+
     UIUtils.loading.show();
-    $scope.closeModal();
 
     Wallet.login($scope.formData.username, $scope.formData.password)
     .then(function() {
@@ -131,12 +139,15 @@ function NewAccountModalController($scope, $state, UIUtils, CryptoUtils, Wallet,
           // Send membership IN
           Wallet.membership.inside()
           .then(function() {
+
+            $scope.closeModal();
+
             // Redirect to wallet
             $state.go('app.view_wallet');
           })
-          .catch(UIUtils.onError('ERROR.SEND_MEMBERSHIP_IN_FAILED'));
+          .catch(onErrorLogout('ERROR.SEND_MEMBERSHIP_IN_FAILED'));
         })
-        .catch(UIUtils.onError('ERROR.SEND_IDENTITY_FAILED'));
+        .catch(onErrorLogout('ERROR.SEND_IDENTITY_FAILED'));
     })
     .catch(function(err) {
       UIUtils.loading.hide();
diff --git a/www/js/controllers/wallet-controllers.js b/www/js/controllers/wallet-controllers.js
index 1396eb18d..a89431c35 100644
--- a/www/js/controllers/wallet-controllers.js
+++ b/www/js/controllers/wallet-controllers.js
@@ -135,58 +135,6 @@ function WalletController($scope, $q, $ionicPopup, $timeout,
     $scope.registerForm = registerForm;
   };
 
-  $scope.checkUidNotExists = function(uid, pubkey) {
-    return $q(function(resolve, reject) {
-      BMA.wot.lookup({ search: uid }) // search on uid
-        .then(function(res) {
-          var found = res.results &&
-              res.results.length > 0 &&
-              res.results.some(function(pub){
-                return pub.uids && pub.uids.length > 0 &&
-                    pub.uids.some(function(idty) {
-                      return ((idty.uid === uid) && // check Uid
-                              (pub.pubkey !== pubkey || !idty.revoked)); // check pubkey
-                    });
-              });
-          if (found) { // uid is already used : display a message and call failed callback
-            reject('ACCOUNT.NEW.MSG_UID_ALREADY_USED');
-          }
-          else {
-            resolve(uid);
-          }
-        })
-        .catch(function() {
-           resolve(uid);
-        });
-    });
-  };
-
-  $scope.checkPubkeyNotExists = function(uid, pubkey) {
-    return $q(function(resolve, reject) {
-      BMA.wot.lookup({ search: pubkey }) // search on pubkey
-        .then(function(res) {
-          var found = res.results &&
-              res.results.length > 0 &&
-              res.results.some(function(pub){
-                return pub.pubkey === pubkey &&
-                    pub.uids && pub.uids.length > 0 &&
-                    pub.uids.some(function(idty) {
-                      return (!idty.revoked); // excluded revoked uid
-                    });
-              });
-          if (found) { // uid is already used : display a message and reopen the popup
-            reject('ACCOUNT.NEW.MSG_PUBKEY_ALREADY_USED');
-          }
-          else {
-            resolve(uid);
-          }
-        })
-        .catch(function() {
-           resolve(uid);
-        });
-    });
-  };
-
   // Ask uid
   $scope.showUidPopup = function() {
     return $q(function(resolve, reject) {
@@ -231,16 +179,20 @@ function WalletController($scope, $q, $ionicPopup, $timeout,
 
   // Send self identity
   $scope.self= function() {
+    if ($scope.actionsPopover) {
+      $scope.actionsPopover.hide();
+    }
+
     $scope.showUidPopup()
     .then(function(uid) {
       UIUtils.loading.show();
 
       Wallet.self(uid)
       .then(function() {
-        $scope.doUpdate();
+        $scope.updateView();
+        UIUtils.loading.hide();
       })
       .catch(function(err){
-         UIUtils.loading.hide();
          UIUtils.onError('ERROR.SEND_IDENTITY_FAILED')(err)
          .then(function() {
            $scope.self(); // loop
@@ -251,8 +203,16 @@ function WalletController($scope, $q, $ionicPopup, $timeout,
 
   // Send membership IN
   $scope.membershipIn= function() {
+    if ($scope.actionsPopover) {
+      $scope.actionsPopover.hide();
+    }
+
     var doMembershipIn = function(retryCount) {
       Wallet.membership.inside()
+      .then(function() {
+        $scope.updateView();
+        UIUtils.loading.hide();
+      })
       .catch(function(err) {
         if (!retryCount || retryCount <= 2) {
           $timeout(function() {
@@ -260,7 +220,10 @@ function WalletController($scope, $q, $ionicPopup, $timeout,
           }, 1000);
         }
         else {
-          UIUtils.onError('ERROR.SEND_MEMBERSHIP_IN_FAILED')(err);
+          UIUtils.onError('ERROR.SEND_MEMBERSHIP_IN_FAILED')(err)
+            .then(function() {
+              $scope.membershipIn(); // loop
+            });
         }
       });
     };
@@ -276,7 +239,12 @@ function WalletController($scope, $q, $ionicPopup, $timeout,
         .then(function() {
           doMembershipIn();
         })
-        .catch(UIUtils.onError('ERROR.SEND_IDENTITY_FAILED'));
+        .catch(function(err){
+          UIUtils.onError('ERROR.SEND_IDENTITY_FAILED')(err)
+            .then(function() {
+              $scope.membershipIn(); // loop
+            });
+        });
       }
       else {
         doMembershipIn();
@@ -292,6 +260,11 @@ function WalletController($scope, $q, $ionicPopup, $timeout,
 
   // Send membership IN
   $scope.membershipOut = function() {
+    if ($scope.actionsPopover) {
+      $scope.actionsPopover.hide();
+    }
+    // TODO Add confirmation message
+
     UIUtils.loading.show();
     Wallet.membership.out()
     .catch(UIUtils.onError('ERROR.SEND_MEMBERSHIP_OUT_FAILED'));
diff --git a/www/js/services/wallet-services.js b/www/js/services/wallet-services.js
index a26a55fb8..fefbdb3e1 100644
--- a/www/js/services/wallet-services.js
+++ b/www/js/services/wallet-services.js
@@ -717,16 +717,18 @@ angular.module('cesium.wallet.services', ['ngResource', 'ngApi', 'cesium.bma.ser
             maxBase: block.unitbase + 1,
             sources : []
           };
+
+          // Get inputs, starting to use current base sources
           var amountBase = 0;
           while (inputs.amount < amount && amountBase <= block.unitbase) {
-
-            // Get inputs, starting to use current base sources
             inputs = getInputs(amount, block.unitbase);
 
-            // Reduce amount (remove last digits)
-            amountBase++;
-            if (inputs.amount < amount && amountBase <= block.unitbase) {
-              amount = truncBase(amount, amountBase);
+            if (inputs.amount < amount) {
+              // try to reduce amount (replace last digits to zero)
+              amountBase++;
+              if (amountBase <= block.unitbase) {
+                amount = truncBase(amount, amountBase);
+              }
             }
           }
 
@@ -763,11 +765,17 @@ angular.module('cesium.wallet.services', ['ngResource', 'ngApi', 'cesium.bma.ser
             }
             return;
           }
-          if (amountBase > 0) {
+          // Avoid to get outputs on lower base
+          if (amountBase < inputs.minBase && !isBase(amount, inputs.minBase)) {
+            amount = truncBase(amount, inputs.minBase);
             console.debug("[wallet] Amount has been truncate to " + amount);
           }
+          else if (amountBase > 0) {
+            console.debug("[wallet] Amount has been truncate to " + amount);
+          }
+
 
-          var tx = 'Version: 3\n' +
+            var tx = 'Version: 3\n' +
             'Type: Transaction\n' +
             'Currency: ' + data.currency + '\n' +
             'Blockstamp: ' + block.number + '-' + block.hash + '\n' +
@@ -852,59 +860,119 @@ angular.module('cesium.wallet.services', ['ngResource', 'ngApi', 'cesium.bma.ser
       });
     },
 
+    checkUidNotExists = function(uid, pubkey) {
+      return $q(function(resolve, reject) {
+        BMA.wot.lookup({ search: uid }) // search on uid
+          .then(function(res) {
+            var found = res.results &&
+              res.results.length > 0 &&
+              res.results.some(function(pub){
+                return pub.uids && pub.uids.length > 0 &&
+                  pub.uids.some(function(idty) {
+                    return ((idty.uid === uid) && // check Uid
+                    (pub.pubkey !== pubkey || !idty.revoked)); // check pubkey
+                  });
+              });
+            if (found) { // uid is already used : display a message and call failed callback
+              reject({message: 'ACCOUNT.NEW.MSG_UID_ALREADY_USED'});
+            }
+            else {
+              resolve(uid);
+            }
+          })
+          .catch(function() {
+            resolve(uid); // not found, so OK
+          });
+      });
+    },
+
+    checkPubkeyNotExists = function(uid, pubkey) {
+      return $q(function(resolve, reject) {
+        BMA.wot.lookup({ search: pubkey }) // search on pubkey
+          .then(function(res) {
+            var found = res.results &&
+              res.results.length > 0 &&
+              res.results.some(function(pub){
+                return pub.pubkey === pubkey &&
+                  pub.uids && pub.uids.length > 0 &&
+                  pub.uids.some(function(idty) {
+                    return (!idty.revoked); // excluded revoked uid
+                  });
+              });
+            if (found) { // uid is already used : display a message and reopen the popup
+              reject('ACCOUNT.NEW.MSG_PUBKEY_ALREADY_USED');
+            }
+            else {
+              resolve(uid);
+            }
+          })
+          .catch(function() {
+            resolve(uid); // not found, so OK
+          });
+      });
+    },
+
     /**
     * Send self identity
     */
-    self = function(uid, requirements) {
+    self = function(uid, needToLoadRequirements) {
 
       return $q(function(resolve, reject) {
         if (!BMA.regex.USER_ID.test(uid)){
           reject({message:'ERROR.INVALID_USER_ID'}); return;
         }
-        loadParameters()
-        .then(function() {
+        var block;
+        var identity;
+        $q.all([
+          // check uid used by another pubkey
+          checkUidNotExists(uid, data.pubkey),
+
+          // Load parameters (need to known the currency)
+          loadParameters(),
+
+          // Get th current block
           BMA.blockchain.current()
-            .then(function (block) {
-              // Create identity to sign
-              var identity = 'Version: 2\n' +
-                'Type: Identity\n' +
-                'Currency: ' + data.currency + '\n' +
-                'Issuer: ' + data.pubkey + '\n' +
-                'UniqueID: ' + uid + '\n' +
-                'Timestamp: ' + block.number + '-' + block.hash + '\n';
-
-              CryptoUtils.sign(identity, data.keypair)
-                .then(function (signature) {
-                  var signedIdentity = identity + signature + '\n';
-                  // Send signed identity
-                  BMA.wot.add({identity: signedIdentity})
-                  .then(function (result) {
-                    if (!!requirements) {
-                      // Refresh membership data
-                      loadRequirements()
-                        .then(function () {
-                          resolve();
-                        }).catch(function (err) {
-                        reject(err);
-                      });
-                    }
-                    else {
-                      data.uid = uid;
-                      data.blockUid = block.number + '-' + block.hash;
-                      resolve();
-                    }
-                  })
-                  .catch(function (err) {
-                    if (err && err.ucode === BMA.errorCodes.IDENTITY_SANDBOX_FULL) {
-                      reject({ucode: BMA.errorCodes.IDENTITY_SANDBOX_FULL, message: 'ERROR.IDENTITY_SANDBOX_FULL'});
-                      return;
-                    }
-                    reject(err);
-                  });
+            .then(function(current) {
+              block = current;
+            })
+        ])
+        // Create identity document to sign
+        .then(function() {
+          identity = 'Version: 2\n' +
+            'Type: Identity\n' +
+            'Currency: ' + data.currency + '\n' +
+            'Issuer: ' + data.pubkey + '\n' +
+            'UniqueID: ' + uid + '\n' +
+            'Timestamp: ' + block.number + '-' + block.hash + '\n';
+
+          return CryptoUtils.sign(identity, data.keypair);
+        })
+        // Add signature
+        .then(function (signature) {
+          var signedIdentity = identity + signature + '\n';
+          // Send to node
+          return BMA.wot.add({identity: signedIdentity})
+          .then(function (result) {
+            if (!!needToLoadRequirements) {
+              // Refresh membership data (if need)
+              loadRequirements()
+                .then(function () {
+                  resolve();
                 }).catch(function (err) {
                 reject(err);
               });
-            }).catch(function (err) {
+            }
+            else {
+              data.uid = uid;
+              data.blockUid = block.number + '-' + block.hash;
+              resolve();
+            }
+          })
+          .catch(function (err) {
+            if (err && err.ucode === BMA.errorCodes.IDENTITY_SANDBOX_FULL) {
+              reject({ucode: BMA.errorCodes.IDENTITY_SANDBOX_FULL, message: 'ERROR.IDENTITY_SANDBOX_FULL'});
+              return;
+            }
             reject(err);
           });
         }).catch(function (err) {
@@ -944,7 +1012,7 @@ angular.module('cesium.wallet.services', ['ngResource', 'ngApi', 'cesium.bma.ser
                       resolve();
                     })
                     .catch(function(err){reject(err);});
-                }, 200);
+                }, 1000); // waiting for node to process membership doc
               }).catch(function(err){reject(err);});
             }).catch(function(err){reject(err);});
           }).catch(function(err){reject(err);});
-- 
GitLab