add memory pool results to getaddressbalance
[electrum-server.git] / backends / bitcoind / storage.py
index 7233e26..cca9645 100644 (file)
@@ -25,8 +25,8 @@ class Storage(object):
 
         self.test_reorgs = test_reorgs
         try:
-            self.db_tree = plyvel.DB(os.path.join(self.dbpath,'addr'), create_if_missing=True, compression=None)
-            self.db      = plyvel.DB(os.path.join(self.dbpath,'utxo'), create_if_missing=True, compression=None)
+            self.db_utxo = plyvel.DB(os.path.join(self.dbpath,'utxo'), create_if_missing=True, compression=None)
+            self.db_addr = plyvel.DB(os.path.join(self.dbpath,'addr'), create_if_missing=True, compression=None)
             self.db_hist = plyvel.DB(os.path.join(self.dbpath,'hist'), create_if_missing=True, compression=None)
             self.db_undo = plyvel.DB(os.path.join(self.dbpath,'undo'), create_if_missing=True, compression=None)
         except:
@@ -54,6 +54,11 @@ class Storage(object):
             return
 
 
+        # compute root hash
+        d = self.get_node('')
+        self.root_hash, v = self.get_node_hash('',d,None)
+        print_log("UTXO tree root hash:", self.root_hash.encode('hex'))
+        print_log("Coins in database:", v)
 
     # convert between bitcoin addresses and 20 bytes keys used for storage. 
     def address_to_key(self, addr):
@@ -63,14 +68,17 @@ class Storage(object):
         return hash_160_to_bc_address(addr)
 
 
-    def get_address_path(self, addr):
+    def get_proof(self, addr):
         key = self.address_to_key(addr)
-        p = self.get_path(key) 
-        p.append(key)
+        i = self.db_utxo.iterator(start=key)
+        k, _ = i.next()
+
+        p = self.get_path(k) 
+        p.append(k)
 
         out = []
         for item in p:
-            v = self.db_tree.get(item)
+            v = self.db_utxo.get(item)
             out.append((item.encode('hex'), v.encode('hex')))
 
         return out
@@ -78,7 +86,7 @@ class Storage(object):
 
     def get_balance(self, addr):
         key = self.address_to_key(addr)
-        i = self.db_tree.iterator(start=key)
+        i = self.db_utxo.iterator(start=key)
         k, _ = i.next()
         if not k.startswith(key): 
             return 0
@@ -92,7 +100,7 @@ class Storage(object):
         key = self.address_to_key(addr)
 
         out = []
-        for k, v in self.db_tree.iterator(start=key):
+        for k, v in self.db_utxo.iterator(start=key):
             if not k.startswith(key):
                 break
             if len(k) == KEYLENGTH:
@@ -136,7 +144,7 @@ class Storage(object):
 
 
     def get_address(self, txi):
-        addr = self.db.get(txi)
+        addr = self.db_addr.get(txi)
         return self.key_to_address(addr) if addr else None
 
 
@@ -182,12 +190,12 @@ class Storage(object):
         if batch:
             batch.put(key, out)
         else:
-            self.db_tree.put(key, out) 
+            self.db_utxo.put(key, out) 
 
 
     def get_node(self, key):
 
-        s = self.db_tree.get(key)
+        s = self.db_utxo.get(key)
         if s is None: 
             return 
 
@@ -214,7 +222,7 @@ class Storage(object):
         word = target
         key = ''
         path = [ '' ]
-        i = self.db_tree.iterator()
+        i = self.db_utxo.iterator()
 
         while key != target:
 
@@ -262,7 +270,7 @@ class Storage(object):
 
         # write 
         s = (int_to_hex(value, 8) + int_to_hex(height,4)).decode('hex')
-        self.db_tree.put(target, s)
+        self.db_utxo.put(target, s)
         # the hash of a node is the txid
         _hash = target[20:52]
         self.update_node_hash(target, path, _hash, value)
@@ -321,7 +329,7 @@ class Storage(object):
 
         
         # batch write modified nodes 
-        batch = self.db_tree.write_batch()
+        batch = self.db_utxo.write_batch()
         for k, v in nodes.items():
             self.put_node(k, v, batch)
         batch.write()
@@ -351,7 +359,7 @@ class Storage(object):
         word = target
         key = ''
         path = [ '' ]
-        i = self.db_tree.iterator(start='')
+        i = self.db_utxo.iterator(start='')
 
         while key != target:
 
@@ -374,7 +382,7 @@ class Storage(object):
                         assert key not in path
                         path.append(key)
                 else:
-                    print_log('not in tree', self.db_tree.get(key+word[0]), new_key.encode('hex'))
+                    print_log('not in tree', self.db_utxo.get(key+word[0]), new_key.encode('hex'))
                     return False
             else:
                 assert key in path
@@ -386,12 +394,12 @@ class Storage(object):
     def delete_address(self, leaf):
         path = self.get_path(leaf)
         if path is False:
-            print_log("addr not in tree", leaf.encode('hex'), self.key_to_address(leaf[0:20]), self.db_tree.get(leaf))
+            print_log("addr not in tree", leaf.encode('hex'), self.key_to_address(leaf[0:20]), self.db_utxo.get(leaf))
             raise
 
-        s = self.db_tree.get(leaf)
+        s = self.db_utxo.get(leaf)
         
-        self.db_tree.delete(leaf)
+        self.db_utxo.delete(leaf)
         if leaf in self.hash_list:
             self.hash_list.pop(leaf)
 
@@ -404,12 +412,12 @@ class Storage(object):
         if len(items) == 1:
             letter, v = items.items()[0]
 
-            self.db_tree.delete(parent)
+            self.db_utxo.delete(parent)
             if parent in self.hash_list: 
                 self.hash_list.pop(parent)
 
             # we need the exact length for the iteration
-            i = self.db_tree.iterator()
+            i = self.db_utxo.iterator()
             i.seek(parent+letter)
             k, v = i.next()
 
@@ -430,7 +438,7 @@ class Storage(object):
 
 
     def get_children(self, x):
-        i = self.db_tree.iterator()
+        i = self.db_utxo.iterator()
         l = 0
         while l <256:
             i.seek(x+chr(l))
@@ -449,7 +457,7 @@ class Storage(object):
 
     def get_parent(self, x):
         """ return parent and skip string"""
-        i = self.db_tree.iterator()
+        i = self.db_utxo.iterator()
         for j in range(len(x)):
             p = x[0:-j-1]
             i.seek(p)
@@ -470,8 +478,8 @@ class Storage(object):
 
 
     def close(self):
-        self.db_tree.close()
-        self.db.close()
+        self.db_utxo.close()
+        self.db_addr.close()
         self.db_hist.close()
         self.db_undo.close()
 
@@ -484,7 +492,7 @@ class Storage(object):
         self.add_address(key + txo, value, tx_height)
 
         # backlink
-        self.db.put(txo, key)
+        self.db_addr.put(txo, key)
 
 
 
@@ -496,8 +504,15 @@ class Storage(object):
         self.delete_address(key + txo)
 
         # backlink
-        self.db.delete(txo)
+        self.db_addr.delete(txo)
+
 
+    def get_utxo_value(self, addr, txi):
+        key = self.address_to_key(addr)
+        leaf = key + txi
+        s = self.db_utxo.get(leaf)
+        value = hex_to_int(s[0:8])
+        return value
 
 
     def set_spent(self, addr, txi, txid, index, height, undo):
@@ -510,7 +525,7 @@ class Storage(object):
         undo[leaf] = value, in_height
 
         # delete backlink txi-> addr
-        self.db.delete(txi)
+        self.db_addr.delete(txi)
 
         # add to history
         s = self.db_hist.get(addr)
@@ -527,7 +542,7 @@ class Storage(object):
         leaf = key + txi
 
         # restore backlink
-        self.db.put(txi, key)
+        self.db_addr.put(txi, key)
 
         v, height = undo.pop(leaf)
         self.add_address(leaf, v, height)