import re import pytest from time import sleep from threading import Thread from test.simulator.transaction import TX from test.pisa.unit import get_random_value_hex from test.simulator.bitcoind_sim import run_simulator from pisa.utils.auth_proxy import AuthServiceProxy, JSONRPCException from pisa.conf import BTC_RPC_USER, BTC_RPC_PASSWD, BTC_RPC_HOST, BTC_RPC_PORT MIXED_VALUES = values = [-1, 500, "", "111", [], 1.1, None, "", "a" * 31, "b" * 33, get_random_value_hex(32)] bitcoin_cli = AuthServiceProxy("http://%s:%s@%s:%d" % (BTC_RPC_USER, BTC_RPC_PASSWD, BTC_RPC_HOST, BTC_RPC_PORT)) @pytest.fixture(scope="module") def run_bitcoind(): bitcoind_thread = Thread(target=run_simulator, kwargs={"mode": "event"}) bitcoind_thread.daemon = True bitcoind_thread.start() # It takes a little bit of time to start the API (otherwise the requests are sent too early and they fail) sleep(0.1) @pytest.fixture(scope="module") def genesis_block_hash(run_bitcoind): return bitcoin_cli.getblockhash(0) def check_hash_format(txid): # TODO: #12-check-txid-regexp return isinstance(txid, str) and re.search(r"^[0-9A-Fa-f]{64}$", txid) is not None def test_help(run_bitcoind): # Help should always return 0 assert bitcoin_cli.help() == 0 # FIXME: Better assert for the exceptions would be nice (check the returned errno is the expected one) def test_getblockhash(genesis_block_hash): # First block assert check_hash_format(genesis_block_hash) # Check that the values are within range and of the proper format (all should fail) for v in MIXED_VALUES: try: bitcoin_cli.getblockhash(v) assert False except JSONRPCException as e: assert True def test_get_block(genesis_block_hash): # getblock should return a list of transactions and the height block = bitcoin_cli.getblock(genesis_block_hash) assert isinstance(block.get("tx"), list) assert len(block.get("tx")) != 0 assert isinstance(block.get("height"), int) # It should fail for wrong data formats and random ids for v in MIXED_VALUES: try: bitcoin_cli.getblock(v) assert False except JSONRPCException as e: assert True def test_decoderawtransaction(genesis_block_hash): # decoderawtransaction should only return if the given transaction matches a txid format block = bitcoin_cli.getblock(genesis_block_hash) coinbase_txid = block.get("tx")[0] coinbase_tx = bitcoin_cli.getrawtransaction(coinbase_txid).get("hex") tx = bitcoin_cli.decoderawtransaction(coinbase_tx) assert isinstance(tx, dict) assert isinstance(tx.get("txid"), str) assert check_hash_format(tx.get("txid")) # Therefore should also work for a random transaction hex in our simulation random_tx = TX.create_dummy_transaction() tx = bitcoin_cli.decoderawtransaction(random_tx) assert isinstance(tx, dict) assert isinstance(tx.get("txid"), str) assert check_hash_format(tx.get("txid")) # But it should fail for not proper formatted one for v in MIXED_VALUES: try: bitcoin_cli.decoderawtransaction(v) assert False except JSONRPCException as e: assert True def test_sendrawtransaction(genesis_block_hash): # sendrawtransaction should only allow txids that the simulator has not mined yet bitcoin_cli.sendrawtransaction(TX.create_dummy_transaction()) # Any data not matching the txid format or that matches with an already mined transaction should fail try: genesis_tx = bitcoin_cli.getblock(genesis_block_hash).get("tx")[0] bitcoin_cli.sendrawtransaction(genesis_tx) assert False except JSONRPCException as e: assert True for v in MIXED_VALUES: try: bitcoin_cli.sendrawtransaction(v) assert False except JSONRPCException as e: assert True def test_getrawtransaction(genesis_block_hash): # getrawtransaction should work for existing transactions, and fail for non-existing ones genesis_tx = bitcoin_cli.getblock(genesis_block_hash).get("tx")[0] tx = bitcoin_cli.getrawtransaction(genesis_tx) assert isinstance(tx, dict) assert isinstance(tx.get("confirmations"), int) for v in MIXED_VALUES: try: bitcoin_cli.getrawtransaction(v) assert False except JSONRPCException as e: assert True def test_getblockcount(): # getblockcount should always return a positive integer bc = bitcoin_cli.getblockcount() assert isinstance(bc, int) assert bc >= 0