more robust synchronization method
authorthomasv <thomasv@gitorious>
Tue, 29 Jan 2013 13:53:13 +0000 (14:53 +0100)
committerthomasv <thomasv@gitorious>
Tue, 29 Jan 2013 13:53:13 +0000 (14:53 +0100)
lib/wallet.py

index e6dd102..97f0d3b 100644 (file)
@@ -52,6 +52,7 @@ class Wallet:
 
         self.config = config
         self.electrum_version = ELECTRUM_VERSION
+        self.gap_limit_for_change = 3 # constant
 
         # saved fields
         self.seed_version          = config.get('seed_version', SEED_VERSION)
@@ -348,36 +349,45 @@ class Wallet:
         return nmax + 1
 
 
-    def synchronize(self):
-        if not self.master_public_key:
-            return []
+    def address_is_old(self, address):
+        age = -1
+        h = self.history.get(address, [])
+        if h == ['*']:
+            return True
+        for tx_hash, tx_height in h:
+            if tx_height == 0:
+                tx_age = 0
+            else: 
+                tx_age = self.verifier.height - tx_height + 1
+            if tx_age > age:
+                age = tx_age
+        return age > 2
 
-        new_addresses = []
-        while True:
-            if self.change_addresses == []:
-                new_addresses.append( self.create_new_address(True) )
-                continue
-            a = self.change_addresses[-1]
-            if self.history.get(a):
-                new_addresses.append( self.create_new_address(True) )
-            else:
-                break
 
-        n = self.gap_limit
+    def synchronize_sequence(self, addresses, n, for_change):
+        new_addresses = []
         while True:
             if len(self.addresses) < n:
-                new_addresses.append( self.create_new_address(False) )
+                new_addresses.append( self.create_new_address(for_change) )
                 continue
-            if map( lambda a: self.history.get(a, []), self.addresses[-n:] ) == n*[[]]:
+            if map( lambda a: self.address_is_old(a), addresses[-n:] ) == n*[False]:
                 break
             else:
-                new_addresses.append( self.create_new_address(False) )
+                new_addresses.append( self.create_new_address(for_change) )
+        return new_addresses
+        
 
+    def synchronize(self):
+        if not self.master_public_key:
+            return []
+        new_addresses = []
+        new_addresses += self.synchronize_sequence(self.addresses, self.gap_limit, False)
+        new_addresses += self.synchronize_sequence(self.change_addresses, self.gap_limit_for_change, True)
         return new_addresses
 
 
     def is_found(self):
-        return (len(self.change_addresses) > 1 ) or ( len(self.addresses) > self.gap_limit )
+        return (len(self.change_addresses) > self.gap_limit_for_change ) or ( len(self.addresses) > self.gap_limit )
 
     def fill_addressbook(self):
         for tx_hash, tx in self.transactions.items():
@@ -609,7 +619,7 @@ class Wallet:
         if change_amount != 0:
             # normally, the update thread should ensure that the last change address is unused
             if not change_addr:
-                change_addr = self.change_addresses[-1]
+                change_addr = self.change_addresses[-self.gap_limit_for_change]
             # Insert the change output at a random position in the outputs
             posn = random.randint(0, len(outputs))
             outputs[posn:posn] = [( change_addr,  change_amount)]