Bläddra i källkod

add tests checking double spends are not allowed

Malte Kraus 8 år sedan
förälder
incheckning
a498bbcd8e
3 ändrade filer med 86 tillägg och 0 borttagningar
  1. 4 0
      src/blockchain.py
  2. 30 0
      tests/utils.py
  3. 52 0
      tests/verifications.py

+ 4 - 0
src/blockchain.py

@@ -53,6 +53,10 @@ class Blockchain:
                 return False
         return True
 
+    def verify_all(self):
+        """ Verify all blocks in this block chain. """
+        return all(block.verify(self) for block in self.blocks)
+
     @property
     def head(self):
         """ The head of this block chain. """

+ 30 - 0
tests/utils.py

@@ -0,0 +1,30 @@
+import src.proof_of_work
+src.proof_of_work.verify_proof_of_work = lambda b: True
+
+from src.block import *
+from src.blockchain import *
+from src.crypto import *
+from src.transaction import *
+
+from datetime import datetime
+
+
+def extend_blockchain(chain, trans:list=None, verify_res=True):
+    ts = datetime.utcfromtimestamp(len(chain.blocks))
+    new_block = Block.create(chain, trans, ts)
+    new_block.hash = new_block.get_hash()
+    new_chain = Blockchain(chain.blocks + [new_block])
+    assert new_chain.verify_all() == verify_res
+    return new_chain
+
+def trans_as_input(trans, out_idx=0):
+    assert len(trans.targets) > out_idx
+    return TransactionInput(trans.get_hash(), out_idx)
+
+def new_trans(old_trans, out_idx=0):
+    amount = old_trans.targets[out_idx].amount
+    key = Signing.generatePrivateKey()
+    trans = Transaction([trans_as_input(old_trans, out_idx)],
+                        [TransactionTarget(key, amount)])
+    trans.sign([old_trans.targets[out_idx].recipient_pk])
+    return trans

+ 52 - 0
tests/verifications.py

@@ -0,0 +1,52 @@
+from .utils import *
+import traceback
+
+errors = 0
+
+def trans_test(fn):
+    """ Immediately runs a test that requires a blockchain, and a transaction with private key in that blockchain. """
+
+    gen_chain = Blockchain([GENESIS_BLOCK])
+    assert gen_chain.verify_all()
+    key = Signing.generatePrivateKey()
+    reward_trans = Transaction([], [TransactionTarget(key, gen_chain.compute_blockreward(gen_chain.head))])
+    chain = extend_blockchain(gen_chain, [reward_trans])
+    try:
+        fn(chain, reward_trans)
+    except:
+        global errors
+        errors += 1
+        traceback.print_exc()
+
+@trans_test
+def test_double_spend1(chain, reward_trans):
+    trans1 = new_trans(reward_trans)
+    chain = extend_blockchain(chain, [trans1])
+
+    # spending the coin in reward_trans again must fail:
+    extend_blockchain(chain, [trans1], verify_res=False)
+
+    # spending the output of trans1 must work:
+    assert chain.is_coin_still_valid(trans_as_input(trans1))
+
+@trans_test
+def test_double_spend2(chain, reward_trans):
+    trans1 = new_trans(reward_trans)
+    trans2 = new_trans(reward_trans)
+    extend_blockchain(chain, [trans1, trans2], verify_res=False)
+
+@trans_test
+def test_double_spend3(chain, reward_trans):
+    trans1 = Transaction([trans_as_input(reward_trans), trans_as_input(reward_trans)], [])
+    key = reward_trans.targets[0].recipient_pk
+    trans1.sign([key, key])
+    extend_blockchain(chain, [trans1], verify_res=False)
+
+
+OKGREEN = '\033[92m'
+FAIL = '\033[91m'
+ENDC = '\033[0m'
+if errors == 0:
+    print(OKGREEN + "All tests passed." + ENDC)
+else:
+    print(FAIL + str(errors) + " tests failed." + ENDC)