test_verifications.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. from .utils import *
  2. def block_test(proof_of_work_res=True):
  3. """ Immediately runs a test that requires a blockchain. """
  4. def decorator(fn):
  5. def wrapper():
  6. orig_proof = src.proof_of_work.verify_proof_of_work
  7. src.proof_of_work.verify_proof_of_work = lambda b: proof_of_work_res
  8. src.block.verify_proof_of_work = src.proof_of_work.verify_proof_of_work
  9. chain = Blockchain()
  10. assert chain.verify_all()
  11. try:
  12. fn(chain)
  13. finally:
  14. src.block.verify_proof_of_work = orig_proof
  15. src.proof_of_work.verify_proof_of_work = orig_proof
  16. return wrapper
  17. return decorator
  18. def trans_test(fn):
  19. """ Immediately runs a test that requires a blockchain, and a transaction with private key in that blockchain. """
  20. @block_test()
  21. def wrapper(gen_chain):
  22. key = Signing.generate_private_key()
  23. reward_trans = Transaction([], [TransactionTarget(key, gen_chain.compute_blockreward(gen_chain.head))])
  24. chain = extend_blockchain(gen_chain, [reward_trans])
  25. fn(chain, reward_trans)
  26. return wrapper
  27. @trans_test
  28. def test_double_spend1(chain, reward_trans):
  29. trans1 = new_trans(reward_trans)
  30. chain = extend_blockchain(chain, [trans1])
  31. # spending the coin in reward_trans again must fail:
  32. extend_blockchain(chain, [trans1], verify_res=False)
  33. # spending the output of trans1 must work:
  34. assert chain.is_coin_still_valid(trans_as_input(trans1))
  35. @trans_test
  36. def test_double_spend2(chain, reward_trans):
  37. trans1 = new_trans(reward_trans)
  38. trans2 = new_trans(reward_trans)
  39. extend_blockchain(chain, [trans1, trans2], verify_res=False)
  40. @trans_test
  41. def test_double_spend3(chain, reward_trans):
  42. trans1 = Transaction([trans_as_input(reward_trans), trans_as_input(reward_trans)], [])
  43. key = reward_trans.targets[0].recipient_pk
  44. trans1.sign([key, key])
  45. extend_blockchain(chain, [trans1], verify_res=False)
  46. @trans_test
  47. def test_create_money1(chain, reward_trans):
  48. key = reward_trans.targets[0].recipient_pk
  49. # create a transaction where the receiver gets 1 more coin than the sender puts in
  50. target = TransactionTarget(key, reward_trans.targets[0].amount + 1)
  51. trans1 = Transaction([trans_as_input(reward_trans)], [target])
  52. trans1.sign([key])
  53. extend_blockchain(chain, [trans1], verify_res=False)
  54. @trans_test
  55. def test_create_money2(chain, reward_trans):
  56. # create a transaction where we create money by sending a negative amount N to someone
  57. # and the inputs + N to us
  58. key = reward_trans.targets[0].recipient_pk
  59. target1 = TransactionTarget(key, -10)
  60. target2 = TransactionTarget(key, reward_trans.targets[0].amount + 10)
  61. trans1 = Transaction([trans_as_input(reward_trans)], [target1, target2])
  62. trans1.sign([key])
  63. extend_blockchain(chain, [trans1], verify_res=False)
  64. @trans_test
  65. def test_dupl_block_reward(chain, reward_trans):
  66. key = reward_trans.targets[0].recipient_pk
  67. target1 = TransactionTarget(key, 1)
  68. trans1 = Transaction([], [target1], iv=b"1")
  69. trans2 = Transaction([], [target1], iv=b"2")
  70. extend_blockchain(chain, [trans1, trans2], verify_res=False)
  71. @trans_test
  72. def test_negative_block_reward(chain, reward_trans):
  73. key = reward_trans.targets[0].recipient_pk
  74. target1 = TransactionTarget(key, -1)
  75. trans1 = Transaction([], [target1], iv=b"1")
  76. extend_blockchain(chain, [trans1], verify_res=False)
  77. @trans_test
  78. def test_zero_block_reward(chain, reward_trans):
  79. extend_blockchain(chain, [], verify_res=True)
  80. @trans_test
  81. def test_too_large_block_reward(chain, reward_trans):
  82. key = reward_trans.targets[0].recipient_pk
  83. target1 = TransactionTarget(key, chain.compute_blockreward() + 1)
  84. trans1 = Transaction([], [target1], iv=b"1")
  85. extend_blockchain(chain, [trans1], verify_res=False)
  86. trans2 = new_trans(reward_trans, fee=1)
  87. target2 = TransactionTarget(key, chain.compute_blockreward() + 2)
  88. trans3 = Transaction([], [target2], iv=b"2")
  89. extend_blockchain(chain, [trans2, trans3], verify_res=False)
  90. @trans_test
  91. def test_max_block_reward(chain, reward_trans):
  92. key = reward_trans.targets[0].recipient_pk
  93. target1 = TransactionTarget(key, chain.compute_blockreward())
  94. trans1 = Transaction([], [target1], iv=b"1")
  95. extend_blockchain(chain, [trans1], verify_res=True)
  96. trans2 = new_trans(reward_trans, fee=1)
  97. target2 = TransactionTarget(key, chain.compute_blockreward() + 1)
  98. trans3 = Transaction([], [target2], iv=b"2")
  99. extend_blockchain(chain, [trans2, trans3], verify_res=True)
  100. @trans_test
  101. def test_spend_too_much(chain, reward_trans):
  102. trans = new_trans(reward_trans, fee=-1)
  103. assert trans.targets[0].amount == reward_trans.targets[0].amount + 1
  104. extend_blockchain(chain, [trans], verify_res=False)
  105. @trans_test
  106. def test_spend_unknown_coin(chain, reward_trans):
  107. key = reward_trans.targets[0].recipient_pk
  108. inp1 = TransactionInput(reward_trans.get_hash(), len(reward_trans.targets))
  109. trans1 = Transaction([inp1], [])
  110. trans1.sign([key])
  111. extend_blockchain(chain, [trans1], verify_res=False)
  112. inp2 = TransactionInput(b"invalid", 0)
  113. trans2 = Transaction([inp2], [])
  114. trans2.sign([key])
  115. extend_blockchain(chain, [trans2], verify_res=False)
  116. @trans_test
  117. def test_send_zero(chain, reward_trans):
  118. trans = new_trans(reward_trans, fee=reward_trans.targets[0].amount)
  119. assert trans.targets[0].amount == 0
  120. extend_blockchain(chain, [trans], verify_res=False)
  121. @trans_test
  122. def test_invalid_signature(chain, reward_trans):
  123. trans1 = new_trans(reward_trans, fee=0)
  124. trans2 = new_trans(reward_trans, fee=1)
  125. trans1.signatures, trans2.signatures = trans2.signatures, trans1.signatures
  126. extend_blockchain(chain, [trans1], verify_res=False)
  127. extend_blockchain(chain, [trans2], verify_res=False)
  128. trans3 = Transaction(trans1.inputs, trans1.targets, signatures=trans1.signatures+trans2.signatures)
  129. extend_blockchain(chain, [trans3], verify_res=False)
  130. trans4 = Transaction(trans1.inputs, trans1.targets, signatures=[])
  131. extend_blockchain(chain, [trans4], verify_res=False)
  132. # too few signatures:
  133. key = reward_trans.targets[0].recipient_pk
  134. target1 = TransactionTarget(key, 1)
  135. target2 = TransactionTarget(key, 1)
  136. trans5 = Transaction(trans1.inputs, [target1, target2])
  137. trans5.sign([key])
  138. extend_blockchain(chain, [trans5], verify_res=True)
  139. input1 = TransactionInput(trans5.get_hash(), 0)
  140. input2 = TransactionInput(trans5.get_hash(), 1)
  141. trans6 = Transaction([input1, input2], [])
  142. trans6.sign([key, key])
  143. trans6.signatures.pop()
  144. extend_blockchain(chain, [trans6], verify_res=False)
  145. @block_test(proof_of_work_res=False)
  146. def test_invalid_proof_of_work(chain):
  147. block = Block.create(chain, [])
  148. assert chain.try_append(block) is None
  149. @block_test()
  150. def test_invalid_hash(chain):
  151. block = Block.create(chain, [])
  152. block.hash = b"invalid"
  153. assert chain.try_append(block) is None
  154. @block_test()
  155. def test_invalid_prev_hash(chain):
  156. block = create_block(chain, prev_block_hash="0001020304")
  157. assert chain.try_append(block) is None
  158. @block_test()
  159. def test_invalid_merkle_root_hash(chain):
  160. block = create_block(chain, merkle_root_hash="0001020304")
  161. assert chain.try_append(block) is None
  162. @block_test()
  163. def test_monotonic_time(chain):
  164. block = create_block(chain, time="1900-01-01T00:00:00.000000 UTC")
  165. assert chain.try_append(block) is None
  166. @block_test()
  167. def test_future_time(chain):
  168. block = create_block(chain, time="2900-01-01T00:00:00.000000 UTC")
  169. assert chain.try_append(block) is None
  170. @block_test()
  171. def test_invalid_height(chain):
  172. block = create_block(chain, height=-1)
  173. assert chain.try_append(block) is None
  174. block = create_block(chain, height=chain.head.height)
  175. assert chain.try_append(block) is None
  176. block = create_block(chain, height=chain.head.height ** 42)
  177. assert chain.try_append(block) is None
  178. block = create_block(chain, height=chain.head.height ** 42)
  179. assert chain.try_append(block) is None
  180. @block_test()
  181. def test_invalid_difficulty(chain):
  182. block = create_block(chain, difficulty=-1)
  183. assert chain.try_append(block) is None
  184. block = create_block(chain, difficulty=chain.head.difficulty + 1)
  185. assert chain.try_append(block) is None
  186. block = create_block(chain, difficulty=chain.head.difficulty - 1)
  187. assert chain.try_append(block) is None
  188. block = create_block(chain, difficulty=chain.head.difficulty ** 42)
  189. assert chain.try_append(block) is None
  190. @block_test()
  191. def test_invalid_height_difficulty(chain):
  192. block = create_block(chain, height=chain.head.height - 1, difficulty=-1)
  193. assert chain.try_append(block) is None
  194. block = create_block(chain, height=chain.head.height, difficulty=0)
  195. assert chain.try_append(block) is None
  196. block = create_block(chain, height=chain.head.height + 1, difficulty=1)
  197. assert chain.try_append(block) is None
  198. block = create_block(chain, height=chain.head.height * 42, difficulty=chain.head.height * 41)
  199. assert chain.try_append(block) is None
  200. block = create_block(chain, height=chain.head.height + chain.head.difficulty + 1,
  201. difficulty=chain.head.difficulty + 1)
  202. assert chain.try_append(block) is None
  203. block = create_block(chain, height=chain.head.height + chain.head.difficulty - 1,
  204. difficulty=chain.head.difficulty - 1)
  205. assert chain.try_append(block) is None