Explorar o código

have the block chain keep track of unspent coins (for more efficient accesses)

Malte Kraus %!s(int64=8) %!d(string=hai) anos
pai
achega
4323dfad7e
Modificáronse 1 ficheiros con 20 adicións e 2 borrados
  1. 20 2
      src/blockchain.py

+ 20 - 2
src/blockchain.py

@@ -13,12 +13,30 @@ class Blockchain:
     :ivar block_indices: A dictionary allowing efficient lookup of the index of a block in this
     :ivar block_indices: A dictionary allowing efficient lookup of the index of a block in this
                          block chain by its hash value.
                          block chain by its hash value.
     :vartype block_indices: Dict[bytes, int]
     :vartype block_indices: Dict[bytes, int]
+    :ivar unspent_coins: A dictionary mapping from (allowed/available) transaction inputs
+                         to the transaction output that created this coin.
+    :vartype unspent_coins: Dict[TransactionInput, TransactionTarget]
     """
     """
 
 
     def __init__(self, blocks: 'List[Block]'):
     def __init__(self, blocks: 'List[Block]'):
         self.blocks = blocks
         self.blocks = blocks
         assert self.blocks[0].height == 0
         assert self.blocks[0].height == 0
         self.block_indices = {block.hash: i for (i, block) in enumerate(blocks)}
         self.block_indices = {block.hash: i for (i, block) in enumerate(blocks)}
+        self.unspent_coins = self._compute_unspent_coins()
+
+    def _compute_unspent_coins(self):
+        val = {}
+
+        for b in self.blocks:
+            for t in b.transactions:
+                for inp in t.inputs:
+                    if inp not in val:
+                        logging.warning("Aborting computation of unspent transactions because a transaction spent an unavailable coin.")
+                        return {}
+                    del val[inp]
+                for i, target in enumerate(t.targets):
+                    val[TransactionInput(t.get_hash(), i)] = target
+        return val
 
 
     def get_transaction_by_hash(self, hash_val: bytes) -> 'Optional[Transaction]':
     def get_transaction_by_hash(self, hash_val: bytes) -> 'Optional[Transaction]':
         """ Returns a transaction from its hash, or None. """
         """ Returns a transaction from its hash, or None. """
@@ -40,8 +58,8 @@ class Blockchain:
         :param prev_block: The youngest block in this block chain that should be considered for
         :param prev_block: The youngest block in this block chain that should be considered for
                            the validation.
                            the validation.
         """
         """
-        if prev_block is None:
-            prev_block = self.head
+        if prev_block is None or prev_block is self.head:
+            return transaction_input in self.unspent_coins
 
 
         idx = self.block_indices[prev_block.hash]
         idx = self.block_indices[prev_block.hash]
         assert self.blocks[idx] is prev_block
         assert self.blocks[idx] is prev_block