diff --git a/pisa/block_processor.py b/pisa/block_processor.py index d426bda..eb09e45 100644 --- a/pisa/block_processor.py +++ b/pisa/block_processor.py @@ -8,40 +8,43 @@ from pisa.utils.auth_proxy import JSONRPCException class BlockProcessor: @staticmethod def get_block(block_hash): - block = None try: block = bitcoin_cli.getblock(block_hash) except JSONRPCException as e: + block = None logging.error("[BlockProcessor] couldn't get block from bitcoind. Error code {}".format(e)) return block @staticmethod def get_best_block_hash(): - block_hash = None try: block_hash = bitcoin_cli.getbestblockhash() except JSONRPCException as e: + block_hash = None logging.error("[BlockProcessor] couldn't get block hash. Error code {}".format(e)) return block_hash @staticmethod def get_block_count(): - block_count = None try: block_count = bitcoin_cli.getblockcount() except JSONRPCException as e: + block_count = None logging.error("[BlockProcessor] couldn't get block block count. Error code {}".format(e)) return block_count + # FIXME: The following two functions does not seem to belong here. They come from the Watcher, and need to be + # separated since they will be reused by the TimeTraveller. + # DISCUSS: 36-who-should-check-appointment-trigger @staticmethod def get_potential_matches(txids, locator_uuid_map): potential_locators = {sha256(binascii.unhexlify(txid)).hexdigest(): txid for txid in txids} @@ -80,6 +83,7 @@ class BlockProcessor: return matches + # DISCUSS: This method comes from the Responder and seems like it could go back there. @staticmethod def check_confirmations(txs, unconfirmed_txs, tx_job_map, missed_confirmations): diff --git a/test/unit/test_block_processor.py b/test/unit/test_block_processor.py new file mode 100644 index 0000000..062e917 --- /dev/null +++ b/test/unit/test_block_processor.py @@ -0,0 +1,75 @@ +import pytest +from time import sleep +from os import urandom +from uuid import uuid4 +from hashlib import sha256 +from threading import Thread +from binascii import unhexlify + +from pisa.block_processor import BlockProcessor +from test.simulator.bitcoind_sim import run_simulator + +APPOINTMENT_COUNT = 100 +TEST_SET_SIZE = 200 + + +@pytest.fixture(autouse=True, scope='session') +def run_bitcoind(): + bitcoind_thread = Thread(target=run_simulator) + bitcoind_thread.daemon = True + bitcoind_thread.start() + + sleep(0.1) + + +@pytest.fixture(scope='session') +def txids(): + return [urandom(32).hex() for _ in range(APPOINTMENT_COUNT)] + + +@pytest.fixture(scope='session') +def locator_uuid_map(txids): + return {sha256(unhexlify(txid)).hexdigest(): uuid4().hex for txid in txids} + + +@pytest.fixture +def best_block_hash(): + return BlockProcessor.get_best_block_hash() + + +def test_get_best_block_hash(best_block_hash): + # As long as bitcoind is running (or mocked in this case) we should always a block hash + assert best_block_hash is not None and isinstance(best_block_hash, str) + + +def test_get_block(best_block_hash): + # Getting a block from a block hash we are aware of should return data + block = BlockProcessor.get_block(best_block_hash) + + # Checking that the received block has at least the fields we need + # FIXME: We could be more strict here, but we'll need to add those restrictions to bitcoind_sim too + assert isinstance(block, dict) + assert block.get('hash') == best_block_hash and 'height' in block and 'previousblockhash' in block and 'tx' in block + + +def test_get_block_count(): + block_count = BlockProcessor.get_block_count() + assert isinstance(block_count, int) and block_count >= 0 + + +def test_potential_matches(txids, locator_uuid_map): + potential_matches = BlockProcessor.get_potential_matches(txids, locator_uuid_map) + + # All the txids must match + assert locator_uuid_map.keys() == potential_matches.keys() + + +def test_potential_matches_random_data(locator_uuid_map): + # The likelihood of finding a potential match with random data should be negligible + txids = [urandom(32).hex() for _ in range(TEST_SET_SIZE)] + + potential_matches = BlockProcessor.get_potential_matches(txids, locator_uuid_map) + + # None of the txids should match + assert len(potential_matches) == 0 +