aucoin/tests/test_validator_block.py

93 lines
4.2 KiB
Python
Raw Permalink Normal View History

2018-07-15 23:30:55 +02:00
import logging
import unittest
from datetime import datetime
from unittest.mock import patch, MagicMock
from freezegun import freeze_time
from aucoin import consensus, dsa, util
from aucoin.block import Block
from aucoin.blockchain import Blockchain
from aucoin.database import session_scope
from aucoin.exceptions import InvalidBlockException, OrphanException
from aucoin.mempool import Mempool
from aucoin.network import Network
from aucoin.transactions import CoinbaseTransaction
from aucoin.validation import Validator
from aucoin.wallet import public_bytes
from tests import helpers
logging.basicConfig(level=logging.DEBUG)
easy_target = bytes.fromhex("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
@patch("aucoin.consensus.required_target", MagicMock(return_value=easy_target))
class TestAddBlock(unittest.TestCase):
def setUp(self):
# setup a fresh blockchain and mempool
self.blockchain = Blockchain(reset=True)
self.mempool = Mempool()
self.network = Network(self.blockchain, self.mempool, max_peers=0)
# A valid block used for testing.
with session_scope() as session:
self.private_key, self.public_key = dsa.generate_keypair()
self.block = Block(
target=easy_target,
hash_prev_block=self.blockchain.genesis_block(session).hash,
public_key=public_bytes(self.public_key),
transactions=[
CoinbaseTransaction(
address=util.address(public_bytes(self.public_key)),
block_height=1
)
]
)
self.validator = Validator(helpers.Core(), self.blockchain, self.mempool, self.network)
def test_valid(self):
self.validator.add_block(helpers.mine(self.block, self.private_key))
def test_reject_invalid_syntax(self):
self.block.transactions = []
self.assertRaisesRegex(InvalidBlockException, "Transaction list must be non-empty",
self.validator.add_block, helpers.mine(self.block, self.private_key))
def test_reject_duplicate(self):
self.block = helpers.mine(self.block, self.private_key)
self.validator.add_block(self.block)
self.assertRaisesRegex(InvalidBlockException, "Already exists in blockchain",
self.validator.add_block, self.block)
def test_reject_orphan(self):
self.block.hash_prev_block = b"non existent"
with self.assertRaises(OrphanException) as cm:
self.validator.add_block(helpers.mine(self.block, self.private_key))
self.assertEqual(cm.exception.missing, b'non existent')
def test_reject_target_difficulty_rules_mismatch(self):
self.block.target = bytes.fromhex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
self.assertRaisesRegex(InvalidBlockException, "Target does not match the difficulty rules",
self.validator.add_block, helpers.mine(self.block, self.private_key))
@freeze_time("2010-01-01")
def test_reject_future_timestamp(self):
self.block.timestamp = int((datetime(2010, 1, 1, 0, 0, 1) + consensus.block_max_future_time).timestamp())
self.assertRaisesRegex(InvalidBlockException, "Block timestamp must not be more than block_max_future_time in the future",
self.validator.add_block, helpers.mine(self.block, self.private_key))
def test_reject_old_timestamp(self):
with session_scope() as session:
self.block.timestamp = self.blockchain.genesis_block(session).timestamp
self.assertRaisesRegex(InvalidBlockException, "Timestamp is before or equal to median time of the last n blocks",
self.validator.add_block, helpers.mine(self.block, self.private_key))
def test_reject_incorrect_block_height(self):
self.block.transactions[0].inputs[0].block_height = 3
self.block.calculate_merkle()
self.assertRaisesRegex(InvalidBlockException, "Block height is not equal to previous block's height \+ 1",
self.validator.add_block, helpers.mine(self.block, self.private_key))