better error messages
[electrum-nvc.git] / lib / wallet.py
index a45af9d..540110c 100644 (file)
 
 
 import sys, base64, os, re, hashlib, copy, operator, ast, threading, random
-
-try:
-    import ecdsa  
-    from ecdsa.util import string_to_number, number_to_string
-except:
-    print "python-ecdsa does not seem to be installed. Try 'sudo easy_install ecdsa'"
-    sys.exit(1)
-
-try:
-    import aes
-except:
-    print "AES does not seem to be installed. Try 'sudo easy_install slowaes'"
-    sys.exit(1)
-
+import aes, ecdsa
+from ecdsa.util import string_to_number, number_to_string
 
 ############ functions from pywallet ##################### 
 
@@ -225,10 +213,18 @@ def raw_tx( inputs, outputs, for_sig = None ):
 
 def format_satoshis(x, is_diff=False, num_zeros = 0):
     from decimal import Decimal
-    s = str( Decimal(x) /100000000 )
-    if is_diff and x>0:
+    s = Decimal(x)
+    sign, digits, exp = s.as_tuple()
+    digits = map(str, digits)
+    while len(digits) < 9:
+        digits.insert(0,'0')
+    digits.insert(-8,'.')
+    s = ''.join(digits).rstrip('0')
+    if sign: 
+        s = '-' + s
+    elif is_diff:
         s = "+" + s
-    if not '.' in s: s += '.'
+
     p = s.find('.')
     s += "0"*( 1 + num_zeros - ( len(s) - p ))
     s += " "*( 9 - ( len(s) - p ))
@@ -308,6 +304,7 @@ class Wallet:
             self.server = server
             self.save()
             self.interface.is_connected = False  # this exits the polling loop
+            self.interface.poke()
 
     def set_path(self, wallet_path):
 
@@ -329,17 +326,19 @@ class Wallet:
 
     def import_key(self, keypair, password):
         address, key = keypair.split(':')
-        if not self.is_valid(address): return False
-        if address in self.all_addresses(): return False
+        if not self.is_valid(address):
+            raise BaseException('Invalid Bitcoin address')
+        if address in self.all_addresses():
+            raise BaseException('Address already in wallet')
         b = ASecretToSecret( key )
         if not b: return False
         secexp = int( b.encode('hex'), 16)
         private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve=SECP256k1 )
         # sanity check
         public_key = private_key.get_verifying_key()
-        if not address == public_key_to_bc_address( '04'.decode('hex') + public_key.to_string() ): return False
+        if not address == public_key_to_bc_address( '04'.decode('hex') + public_key.to_string() ):
+            raise BaseException('Address does not match private key')
         self.imported_keys[address] = self.pw_encode( key, password )
-        return True
 
     def new_seed(self, password):
         seed = "%032x"%ecdsa.util.randrange( pow(2,128) )
@@ -382,12 +381,18 @@ class Wallet:
     def get_sequence(self,n,for_change):
         return string_to_number( Hash( "%d:%d:"%(n,for_change) + self.master_public_key ) )
 
+    def get_private_key_base58(self, address, password):
+        pk = self.get_private_key(address, password)
+        if pk is None: return None
+        return SecretToASecret( pk )
+
     def get_private_key(self, address, password):
         """  Privatekey(type,n) = Master_private_key + H(n|S|type)  """
         order = generator_secp256k1.order()
         
         if address in self.imported_keys.keys():
             b = self.pw_decode( self.imported_keys[address], password )
+            if not b: return None
             b = ASecretToSecret( b )
             secexp = int( b.encode('hex'), 16)
         else:
@@ -403,6 +408,7 @@ class Wallet:
                 seed = self.pw_decode( self.seed, password)
             except:
                 raise BaseException("Invalid password")
+            if not seed: return None
             secexp = self.stretch_key(seed)
             secexp = ( secexp + self.get_sequence(n,for_change) ) % order
 
@@ -770,11 +776,21 @@ class Wallet:
             else:
                 for o_addr in tx['outputs']:
                     if self.is_mine(o_addr) and not self.is_change(o_addr):
-                        dest_label = self.labels.get(o_addr)
-                        if dest_label:
-                            default_label = 'at: ' + dest_label
-                        else:
-                            default_label = 'at: ' + o_addr
+                        break
+                else:
+                    for o_addr in tx['outputs']:
+                        if self.is_mine(o_addr):
+                            break
+                    else:
+                        o_addr = None
+
+                if o_addr:
+                    dest_label = self.labels.get(o_addr)
+                    if dest_label:
+                        default_label = 'at: ' + dest_label
+                    else:
+                        default_label = 'at: ' + o_addr
+
             tx['default_label'] = default_label
 
     def mktx(self, to_address, amount, label, password, fee=None, change_addr=None, from_addr= None):
@@ -852,13 +868,13 @@ class Wallet:
 
         return target, signing_addr, auth_name
 
-    def update_password(self, seed, new_password):
+    def update_password(self, seed, old_password, new_password):
         if new_password == '': new_password = None
         self.use_encryption = (new_password != None)
         self.seed = self.pw_encode( seed, new_password)
         for k in self.imported_keys.keys():
             a = self.imported_keys[k]
-            b = self.pw_decode(a, password)
+            b = self.pw_decode(a, old_password)
             c = self.pw_encode(b, new_password)
             self.imported_keys[k] = c
         self.save()
@@ -869,7 +885,7 @@ class Wallet:
         except BaseException, e:
             # raise exception if verify fails (verify the chain)
             if interactive:
-                show_message("Alias error: " + e.message)
+                show_message("Alias error: " + str(e))
             return
 
         print target, signing_address, auth_name
@@ -950,7 +966,7 @@ class Wallet:
 
     def update(self):
         self.interface.poke()
-        self.up_to_date_event.wait()
+        self.up_to_date_event.wait(10000000000)
 
 
     def start_session(self, interface):