mirror of
https://github.com/aljazceru/python-teos.git
synced 2025-12-18 06:34:19 +01:00
Multiple simulator improvements
The simulator has been updated to work with real transaction structures instead of transaction hashes. It now supports: - Non-SegWit transaction format - Generation of blocks event-wise and time-wise Some small issues have also been fixed. With the new approach, the simulator can be used in a broader range of tests. Moreover tests can run faster since they do not have to wait for blocks. Instead, the generation of new blocks can be triggered by the test.
This commit is contained in:
@@ -1,107 +1,146 @@
|
||||
import re
|
||||
import os
|
||||
import pytest
|
||||
from time import sleep
|
||||
from threading import Thread
|
||||
|
||||
from test.simulator.transaction import TX
|
||||
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
|
||||
from pisa.tools import check_txid_format
|
||||
|
||||
MIXED_VALUES = values = [-1, 500, '', '111', [], 1.1, None, '', "a" * 31, "b" * 33, os.urandom(32).hex()]
|
||||
|
||||
|
||||
@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
|
||||
|
||||
|
||||
bitcoin_cli = AuthServiceProxy("http://%s:%s@%s:%d" % (BTC_RPC_USER, BTC_RPC_PASSWD, BTC_RPC_HOST, BTC_RPC_PORT))
|
||||
|
||||
# Help should always return 0
|
||||
assert(bitcoin_cli.help() == 0)
|
||||
|
||||
# getblockhash should return a blockid (which matches the txid format)
|
||||
block_hash = bitcoin_cli.getblockhash(0)
|
||||
assert(check_txid_format(block_hash))
|
||||
def test_help(run_bitcoind):
|
||||
# Help should always return 0
|
||||
assert(bitcoin_cli.help() == 0)
|
||||
|
||||
# Check that the values are within range and of the proper format (all should fail)
|
||||
values = [-1, 500, None, '', '111', [], 1.1]
|
||||
print("getblockhash fails ({}):".format(len(values)))
|
||||
|
||||
for v in values:
|
||||
# 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:
|
||||
block_hash = bitcoin_cli.getblockhash(v)
|
||||
genesis_tx = bitcoin_cli.getblock(genesis_block_hash).get("tx")[0]
|
||||
bitcoin_cli.sendrawtransaction(genesis_tx)
|
||||
assert False
|
||||
|
||||
except JSONRPCException as e:
|
||||
print('\t{}'.format(e))
|
||||
assert True
|
||||
|
||||
# getblock should return a list of transactions and the height
|
||||
block = bitcoin_cli.getblock(block_hash)
|
||||
assert(isinstance(block.get('tx'), list))
|
||||
assert(len(block.get('tx')) != 0)
|
||||
assert(isinstance(block.get('height'), int))
|
||||
for v in MIXED_VALUES:
|
||||
try:
|
||||
bitcoin_cli.sendrawtransaction(v)
|
||||
assert False
|
||||
except JSONRPCException as e:
|
||||
assert True
|
||||
|
||||
# Some fails
|
||||
values += ["a"*64, os.urandom(32).hex()]
|
||||
print("\ngetblock fails ({}):".format(len(values)))
|
||||
|
||||
for v in values:
|
||||
try:
|
||||
block = bitcoin_cli.getblock(v)
|
||||
assert False
|
||||
except JSONRPCException as e:
|
||||
print('\t{}'.format(e))
|
||||
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)
|
||||
|
||||
# decoderawtransaction should only return if the given transaction matches a txid format
|
||||
coinbase_tx = block.get('tx')[0]
|
||||
tx = bitcoin_cli.decoderawtransaction(coinbase_tx)
|
||||
assert(isinstance(tx, dict))
|
||||
assert(isinstance(tx.get('txid'), str))
|
||||
assert(check_txid_format(tx.get('txid')))
|
||||
assert(isinstance(tx, dict))
|
||||
assert(isinstance(tx.get('confirmations'), int))
|
||||
|
||||
# Therefore should also work for a random formatted 32-byte hex in our simulation
|
||||
random_tx = os.urandom(32).hex()
|
||||
tx = bitcoin_cli.decoderawtransaction(random_tx)
|
||||
assert(isinstance(tx, dict))
|
||||
assert(isinstance(tx.get('txid'), str))
|
||||
assert(check_txid_format(tx.get('txid')))
|
||||
for v in MIXED_VALUES:
|
||||
try:
|
||||
bitcoin_cli.getrawtransaction(v)
|
||||
assert False
|
||||
except JSONRPCException as e:
|
||||
assert True
|
||||
|
||||
# But it should fail for not proper formatted one
|
||||
values = [1, None, '', "a"*63, "b"*65, [], os.urandom(31).hex()]
|
||||
print("\ndecoderawtransaction fails ({}):".format(len(values)))
|
||||
|
||||
for v in values:
|
||||
try:
|
||||
block = bitcoin_cli.decoderawtransaction(v)
|
||||
assert False
|
||||
except JSONRPCException as e:
|
||||
print('\t{}'.format(e))
|
||||
|
||||
# sendrawtransaction should only allow txids that the simulator has not mined yet
|
||||
bitcoin_cli.sendrawtransaction(os.urandom(32).hex())
|
||||
|
||||
# Any data not matching the txid format or that matches with an already mined transaction should fail
|
||||
values += [coinbase_tx]
|
||||
|
||||
print("\nsendrawtransaction fails ({}):".format(len(values)))
|
||||
|
||||
for v in values:
|
||||
try:
|
||||
block = bitcoin_cli.sendrawtransaction(v)
|
||||
assert False
|
||||
except JSONRPCException as e:
|
||||
print('\t{}'.format(e))
|
||||
|
||||
# getrawtransaction should work for existing transactions, and fail for non-existing ones
|
||||
tx = bitcoin_cli.getrawtransaction(coinbase_tx)
|
||||
|
||||
assert(isinstance(tx, dict))
|
||||
assert(isinstance(tx.get('confirmations'), int))
|
||||
|
||||
print("\nsendrawtransaction fails ({}):".format(len(values)))
|
||||
|
||||
for v in values:
|
||||
try:
|
||||
block = bitcoin_cli.sendrawtransaction(v)
|
||||
assert False
|
||||
except JSONRPCException as e:
|
||||
print('\t{}'.format(e))
|
||||
|
||||
# getblockcount should always return a positive integer
|
||||
bc = bitcoin_cli.getblockcount()
|
||||
assert (isinstance(bc, int))
|
||||
assert (bc >= 0)
|
||||
|
||||
print("\nAll tests passed!")
|
||||
def test_getblockcount():
|
||||
# getblockcount should always return a positive integer
|
||||
bc = bitcoin_cli.getblockcount()
|
||||
assert (isinstance(bc, int))
|
||||
assert (bc >= 0)
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user