diff --git a/tests/coins/btc/test_without_wallet.py b/tests/coins/btc/test_without_wallet.py index 22ddd0b..3314700 100644 --- a/tests/coins/btc/test_without_wallet.py +++ b/tests/coins/btc/test_without_wallet.py @@ -9,8 +9,6 @@ from bitcart import BTC -from ...utils import assert_contains, data_check - pytestmark = pytest.mark.asyncio @@ -48,48 +46,6 @@ async def test_validate_key(btc, key, expected): assert await btc.validate_key(key) == expected -async def get_tx(btc, tx_hash): - # TODO: remove when protocol 1.5 is released - # This is temporarily using SPV verification to reliably get confirmations - # This helps avoiding CI failures, see https://github.com/spesmilo/electrum/issues/7342 - return await btc.server.get_transaction(tx_hash, use_spv=True) - - -async def get_address(btc, address): - out = await btc.server.getaddresshistory(address) - for i in out: - i["tx"] = await get_tx(btc, i["tx_hash"]) - return out - - -async def test_get_tx(btc): - info = await get_tx(btc, "15967d9ed9b63f068c7578d54b7adff859f4aadc1253ba316b429d251da6b48c") - assert_contains({"version": 2, "locktime": 1895035}, info) - data_check(info, "confirmations", int) - assert info["confirmations"] > 0 - data_check(info, "inputs", list, 1) - assert_contains( - { - "prevout_hash": "3fb55b64df34ded97e97cbd5cfc17b6f114a086950fbb0bffe3c985bfa9f5af8", - "prevout_n": 1, - "coinbase": False, - "nsequence": 4294967294, - "scriptSig": "", - "witness": [ - "30440220331290fdbb259fde31d6e0c4eea883e7b7442b1fb1dab0b763cd82c1c5b27a6a02205f37387895fbedb5514a6eb3f374c3943ffefd5df589ac5c59f34f99558386a501", - "0314ef5ee304b86a5c2bbc9d9e1987cd0cb156ca6942ea41dfb487f8d5494bc5bf", - ], - }, - info["inputs"][0], - ) - data_check(info, "outputs", list, 2) - assert info["outputs"][0] == { - "scriptpubkey": "a9144eee7441c8104f1470e6dde89f1439cab91fdc9987", - "address": "2MzSaML6Y3kGn7mPx1T9xXZW1r2N9vKhGo2", - "value_sats": 1515748829, - } - - async def test_config_methods(btc): k, v = "auto_connect", False await btc.set_config(k, v) @@ -97,20 +53,6 @@ async def test_config_methods(btc): await btc.set_config(k, True) -async def test_get_address(btc): - txes = await get_address(btc, "2MzSaML6Y3kGn7mPx1T9xXZW1r2N9vKhGo2") - assert isinstance(txes, list) - tx = txes[0] - assert tx["tx_hash"] == "15967d9ed9b63f068c7578d54b7adff859f4aadc1253ba316b429d251da6b48c" - assert tx["height"] == 1895036 - tx2 = await get_tx(btc, tx["tx_hash"]) - # To avoid comparing exact confirmations - # TODO: remove when SPV verification is the default - tx["tx"].pop("confirmations") - tx2.pop("confirmations") - assert tx["tx"] == tx2 - - async def test_create_wallet(btc, tmp_path): wallet_path = os.path.join(str(tmp_path), "my_wallet") wallet = await btc.server.create(wallet_path=wallet_path) diff --git a/tests/regtest.py b/tests/regtest.py index 423b593..c2852ef 100644 --- a/tests/regtest.py +++ b/tests/regtest.py @@ -70,6 +70,49 @@ def check_tx(tx, broadcast): # if it is not broadcast, it returns raw transaction +async def fetch_regtest_tx(wallet, tx_hash): + return await wallet.server.get_transaction(tx_hash, use_spv=True) + + +async def fetch_regtest_address_history(wallet, address): + out = await wallet.server.getaddresshistory(address) + for tx_info in out: + tx_info["tx"] = await fetch_regtest_tx(wallet, tx_info["tx_hash"]) + return out + + +def without_confirmations(tx): + comparable_tx = tx.copy() + comparable_tx.pop("confirmations") + return comparable_tx + + +async def test_get_tx(regtest_wallet): + txes = await fetch_regtest_address_history(regtest_wallet, BTC_ADDRESS) + tx_hash = txes[0]["tx_hash"] + + info = await fetch_regtest_tx(regtest_wallet, tx_hash) + + data_check(info, "confirmations", int) + assert info["confirmations"] > 0 + data_check(info, "inputs", list) + data_check(info, "outputs", list) + assert any(output.get("address") == BTC_ADDRESS for output in info["outputs"]) + + +async def test_get_address(regtest_wallet): + txes = await fetch_regtest_address_history(regtest_wallet, BTC_ADDRESS) + + assert isinstance(txes, list) + assert len(txes) > 0 + tx = txes[0] + data_check(tx, "tx_hash", str, 64) + data_check(tx, "height", int) + assert tx["height"] > 0 + tx2 = await fetch_regtest_tx(regtest_wallet, tx["tx_hash"]) + assert without_confirmations(tx["tx"]) == without_confirmations(tx2) + + @pytest.mark.parametrize("fee,feerate,broadcast", TEST_PARAMS) async def test_payment_to_single(regtest_wallet, fee, feerate, broadcast, wait_for_balance): check_tx( diff --git a/tests/test_test_suite_boundaries.py b/tests/test_test_suite_boundaries.py new file mode 100644 index 0000000..f3abe4f --- /dev/null +++ b/tests/test_test_suite_boundaries.py @@ -0,0 +1,21 @@ +import ast +from pathlib import Path + +SYNC_DEPENDENT_TESTS = {"test_get_tx", "test_get_address"} + + +def get_test_names(test_file: Path) -> set[str]: + tree = ast.parse(test_file.read_text()) + return {node.name for node in tree.body if isinstance(node, ast.AsyncFunctionDef | ast.FunctionDef)} + + +def test_default_btc_without_wallet_tests_do_not_include_sync_dependent_cases(): + test_names = get_test_names(Path("tests/coins/btc/test_without_wallet.py")) + + assert test_names.isdisjoint(SYNC_DEPENDENT_TESTS) + + +def test_regtest_suite_includes_sync_dependent_cases(): + test_names = get_test_names(Path("tests/regtest.py")) + + assert SYNC_DEPENDENT_TESTS.issubset(test_names)