check that histories and transactions are consistent
authorThomasV <thomasv@gitorious>
Wed, 7 Nov 2012 19:25:23 +0000 (20:25 +0100)
committerThomasV <thomasv@gitorious>
Wed, 7 Nov 2012 19:25:23 +0000 (20:25 +0100)
lib/wallet.py

index cfc8a5f..c60cfb9 100644 (file)
@@ -538,17 +538,26 @@ class Wallet:
 
 
 
-    def receive_tx_callback(self, tx_hash, d):
-        #print "updating history for", addr
-        #with self.lock:
-        self.transactions[tx_hash] = d
+    def receive_tx_callback(self, tx_hash, tx):
+
+        if not self.check_new_tx(tx_hash, tx):
+            print "error: transaction not consistent with history", tx_hash
+            return
+
+        with self.lock:
+            self.transactions[tx_hash] = tx
+
         self.update_tx_outputs(tx_hash)
 
         self.save()
 
 
     def receive_history_callback(self, addr, hist):
-        #print "updating history for", addr
+
+        if not self.check_new_history(addr, hist):
+            print "error: history check failed", tx_hash
+            return
+            
         with self.lock:
             self.history[addr] = hist
             self.save()
@@ -557,6 +566,7 @@ class Wallet:
                     self.verifier.add(tx_hash)
 
 
+
     def get_tx_history(self):
         with self.lock:
             lines = self.transactions.values()
@@ -896,6 +906,53 @@ class Wallet:
 
 
 
+    def is_addr_in_tx(self, addr, tx):
+        found = False
+        for txin in tx.get('inputs'):
+            if addr == txin.get('address'): 
+                found = True
+                break
+        for txout in tx.get('outputs'):
+            if addr == txout.get('address'): 
+                found = True
+                break
+        return found
+
+
+    def check_new_history(self, addr, hist):
+        # - check that all tx in hist are relevant
+        for tx_hash, height in hist:
+            tx = self.transactions.get(tx_hash)
+            if not tx: continue
+            if not self.is_addr_in_tx(addr,tx):
+                return False
+
+        # todo: check that we are not "orphaning" a transaction
+        # if we are, reject tx if unconfirmed, else reject the server
+
+        return True
+
+
+
+    def check_new_tx(self, tx_hash, tx):
+        # 1 check that tx is referenced in addr_history. 
+        addresses = []
+        for addr, hist in self.history.items():
+            for txh, height in hist:
+                if txh == tx_hash: 
+                    addresses.append(addr)
+
+        if not addresses:
+            return False
+
+        # 2 check that referencing addresses are in the tx
+        for addr in addresses:
+            if not self.is_addr_in_tx(addr, tx):
+                return False
+
+        return True
+
+
 
 
 class WalletSynchronizer(threading.Thread):
@@ -915,19 +972,20 @@ class WalletSynchronizer(threading.Thread):
         new_addresses = self.wallet.synchronize()
         if new_addresses:
             self.subscribe_to_addresses(new_addresses)
+            self.wallet.up_to_date = False
+            return
             
-        if self.interface.is_up_to_date('synchronizer'):
-            if not self.wallet.up_to_date:
-                self.wallet.up_to_date = True
-                self.was_updated = True
-                self.wallet.up_to_date_event.set()
-        else:
+        if not self.interface.is_up_to_date('synchronizer'):
             if self.wallet.up_to_date:
                 self.wallet.up_to_date = False
                 self.was_updated = True
+            return
 
+        self.wallet.up_to_date = True
+        self.was_updated = True
+        self.wallet.up_to_date_event.set()
 
-
+    
     def subscribe_to_addresses(self, addresses):
         messages = []
         for addr in addresses: