mirror of
https://github.com/Chia-Network/chia-blockchain.git
synced 2026-08-24 10:05:29 -05:00
* First pass add 3.14 * Update bitarray * Update markupsafe * Update zstd * Update tach to version with 3.14 support * Changes for 3.14 related things * Refactor shutdown handling in sync method * Ignore unclosed database ResourceWarning Added a new warning to ignore for unclosed database resources. * Update pytest.ini to ignore additional warnings * ignore resourcewarnings about tempdir cleanup * Minor cleanup for tests running under python 3.14 * Reduce consensus tests for test_ban_for_mismatched_tx_cost_fee * make sure to close RPC client at end of test * different idea for TempFile * oh, no cleanup function * small fixes for tests detected by 3.14 * update pytest.ini * ignore sqlite errors during closing in __del__ * add code to ignore deprecatewarnings for loop policy * Pass in ClientSession to wschiaconnection for proper cleanup * Some more resource cleanup * Trying to find unclosed sessions * One more time needing a close * wait for harvesters to connect to the farmer * properly teardown vdf_server using context manager * Testing cleanup for simulator tests * Add in a sleep to allow sockets time to cleanup * Revert "Testing cleanup for simulator tests" This reverts commitc5a4ef0cc3. * Revert "properly teardown vdf_server using context manager" This reverts commit18b456a7b6. * Revert "Revert "Testing cleanup for simulator tests"" This reverts commit8c8efc2e03. * vdf_server cleanup * attempt 47 of timelord cleanup * Some other cleanup fixes in tests * yet another attempt at timelord shutdown * Some more adjustments for 3.14 * ignore unclosed socket resource warnings * some more adjustments and cleanup * remove commented code * correct poetry.lock file * Address some review comments * fix merge indentation * fix install script print * update requests * fix problems with timelord tests on 3.14 * Make sure to close dummy session on any exception * Use different cleanup pattern to help with flakes on Windows * better shutdown handling * hopefully better awaiting for cleanup * yet more better timelord cleanup * some test adjustments * more time for cleanup
297 lines
12 KiB
Python
297 lines
12 KiB
Python
from __future__ import annotations
|
|
|
|
import re
|
|
from collections.abc import AsyncGenerator
|
|
from typing import Any
|
|
|
|
import pytest
|
|
from chia_rs import SpendBundle
|
|
from chia_rs.sized_bytes import bytes32
|
|
from chia_rs.sized_ints import uint64
|
|
|
|
from chia.full_node.full_node_rpc_api import FullNodeRpcApi
|
|
from chia.full_node.full_node_rpc_client import FullNodeRpcClient
|
|
from chia.rpc.rpc_errors import RpcError
|
|
from chia.simulator.block_tools import BlockTools
|
|
from chia.simulator.full_node_simulator import FullNodeSimulator
|
|
from chia.simulator.simulator_protocol import FarmNewBlockProtocol
|
|
from chia.simulator.start_simulator import SimulatorFullNodeService
|
|
from chia.simulator.wallet_tools import WalletTool
|
|
from chia.types.blockchain_format.coin import Coin
|
|
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
|
|
from chia.wallet.wallet_service import WalletService
|
|
|
|
|
|
@pytest.fixture(scope="function")
|
|
async def setup_node_and_rpc(
|
|
two_wallet_nodes_services: tuple[list[SimulatorFullNodeService], list[WalletService], BlockTools],
|
|
) -> AsyncGenerator[tuple[FullNodeRpcClient, FullNodeRpcApi], None]:
|
|
full_nodes, wallets, bt = two_wallet_nodes_services
|
|
wallet = wallets[0]._node.wallet_state_manager.main_wallet
|
|
full_node_apis = [full_node_service._api for full_node_service in full_nodes]
|
|
full_node_api: FullNodeSimulator = full_node_apis[0]
|
|
full_node_service_1 = full_nodes[0]
|
|
assert full_node_service_1.rpc_server is not None
|
|
|
|
async with FullNodeRpcClient.create_as_context(
|
|
bt.config["self_hostname"],
|
|
full_node_service_1.rpc_server.listen_port,
|
|
full_node_service_1.root_path,
|
|
full_node_service_1.config,
|
|
) as client:
|
|
full_node_rpc_api = FullNodeRpcApi(full_node_api.full_node)
|
|
|
|
async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
|
|
ph = await action_scope.get_puzzle_hash(wallet.wallet_state_manager)
|
|
|
|
for i in range(4):
|
|
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
|
|
|
|
yield client, full_node_rpc_api
|
|
|
|
|
|
@pytest.fixture(scope="function")
|
|
async def one_node_no_blocks(
|
|
one_node: tuple[list[SimulatorFullNodeService], list[WalletService], BlockTools],
|
|
) -> tuple[FullNodeRpcClient, FullNodeRpcApi]:
|
|
full_nodes, _wallets, bt = one_node
|
|
full_node_apis = [full_node_service._api for full_node_service in full_nodes]
|
|
full_node_api: FullNodeSimulator = full_node_apis[0]
|
|
full_node_service_1 = full_nodes[0]
|
|
assert full_node_service_1.rpc_server is not None
|
|
client = await FullNodeRpcClient.create(
|
|
bt.config["self_hostname"],
|
|
full_node_service_1.rpc_server.listen_port,
|
|
full_node_service_1.root_path,
|
|
full_node_service_1.config,
|
|
)
|
|
full_node_rpc_api = FullNodeRpcApi(full_node_api.full_node)
|
|
|
|
return client, full_node_rpc_api
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_get_blockchain_state(setup_node_and_rpc: tuple[FullNodeRpcClient, FullNodeRpcApi]) -> None:
|
|
# Confirm full node setup correctly
|
|
client, _ = setup_node_and_rpc
|
|
response = await client.get_blockchain_state()
|
|
assert response["genesis_challenge_initialized"] is True
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_empty_request(setup_node_and_rpc: tuple[FullNodeRpcClient, FullNodeRpcApi]) -> None:
|
|
_client, full_node_rpc_api = setup_node_and_rpc
|
|
|
|
with pytest.raises(RpcError):
|
|
await full_node_rpc_api.get_fee_estimate({})
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_empty_peak(one_node_no_blocks: tuple[FullNodeRpcClient, FullNodeRpcApi]) -> None:
|
|
client, full_node_rpc_api = one_node_no_blocks
|
|
response = await full_node_rpc_api.get_fee_estimate({"target_times": [], "cost": 1})
|
|
del response["node_time_utc"]
|
|
assert response == {
|
|
"estimates": [],
|
|
"target_times": [],
|
|
"current_fee_rate": 0,
|
|
"mempool_size": 0,
|
|
"mempool_max_size": 0,
|
|
"full_node_synced": False,
|
|
"peak_height": 0,
|
|
"last_peak_timestamp": 0,
|
|
"fee_rate_last_block": 0.0,
|
|
"fees_last_block": 0,
|
|
"last_block_cost": 0,
|
|
"last_tx_block_height": 0,
|
|
"mempool_fees": 0,
|
|
"num_spends": 0,
|
|
}
|
|
|
|
# one_node_no_blocks is not an async generator, so we have to close the client ourselves
|
|
client.close()
|
|
await client.await_closed()
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_no_target_times(setup_node_and_rpc: tuple[FullNodeRpcClient, FullNodeRpcApi]) -> None:
|
|
_client, full_node_rpc_api = setup_node_and_rpc
|
|
with pytest.raises(RpcError):
|
|
await full_node_rpc_api.get_fee_estimate({"cost": 1})
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_negative_time(setup_node_and_rpc: tuple[FullNodeRpcClient, FullNodeRpcApi]) -> None:
|
|
_client, full_node_rpc_api = setup_node_and_rpc
|
|
with pytest.raises(RpcError):
|
|
await full_node_rpc_api.get_fee_estimate({"cost": 1, "target_times": [-1]})
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_negative_cost(setup_node_and_rpc: tuple[FullNodeRpcClient, FullNodeRpcApi]) -> None:
|
|
_client, full_node_rpc_api = setup_node_and_rpc
|
|
with pytest.raises(RpcError):
|
|
await full_node_rpc_api.get_fee_estimate({"cost": -1, "target_times": [1]})
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_no_cost_or_tx(setup_node_and_rpc: tuple[FullNodeRpcClient, FullNodeRpcApi]) -> None:
|
|
_client, full_node_rpc_api = setup_node_and_rpc
|
|
with pytest.raises(RpcError):
|
|
await full_node_rpc_api.get_fee_estimate({"target_times": []})
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_both_cost_and_tx(setup_node_and_rpc: tuple[FullNodeRpcClient, FullNodeRpcApi]) -> None:
|
|
_client, full_node_rpc_api = setup_node_and_rpc
|
|
with pytest.raises(RpcError):
|
|
await full_node_rpc_api.get_fee_estimate({"target_times": [], "cost": 1, "spend_bundle": "80"})
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_target_times_invalid_type(setup_node_and_rpc: tuple[FullNodeRpcClient, FullNodeRpcApi]) -> None:
|
|
_client, full_node_rpc_api = setup_node_and_rpc
|
|
with pytest.raises(TypeError):
|
|
await full_node_rpc_api.get_fee_estimate({"target_times": 1, "cost": 1})
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_cost_invalid_type(setup_node_and_rpc: tuple[FullNodeRpcClient, FullNodeRpcApi]) -> None:
|
|
_client, full_node_rpc_api = setup_node_and_rpc
|
|
with pytest.raises(RpcError):
|
|
await full_node_rpc_api.get_fee_estimate({"target_times": [], "cost": "a lot"})
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_tx_invalid_type(setup_node_and_rpc: tuple[FullNodeRpcClient, FullNodeRpcApi]) -> None:
|
|
_client, full_node_rpc_api = setup_node_and_rpc
|
|
with pytest.raises(TypeError):
|
|
await full_node_rpc_api.get_fee_estimate({"target_times": [], "spend_bundle": {"coin_spends": 1}})
|
|
|
|
|
|
#####################
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_empty_target_times(setup_node_and_rpc: tuple[FullNodeRpcClient, FullNodeRpcApi]) -> None:
|
|
_client, full_node_rpc_api = setup_node_and_rpc
|
|
response = await full_node_rpc_api.get_fee_estimate({"target_times": [], "cost": 1})
|
|
assert response["estimates"] == []
|
|
assert response["target_times"] == []
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_cost(setup_node_and_rpc: tuple[FullNodeRpcClient, FullNodeRpcApi]) -> None:
|
|
_client, full_node_rpc_api = setup_node_and_rpc
|
|
response = await full_node_rpc_api.get_fee_estimate({"target_times": [1], "cost": 1})
|
|
assert response["estimates"] == [0]
|
|
assert response["target_times"] == [1]
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_tx(setup_node_and_rpc: tuple[FullNodeRpcClient, FullNodeRpcApi], bt: BlockTools) -> None:
|
|
_client, full_node_rpc_api = setup_node_and_rpc
|
|
wallet_a: WalletTool = bt.get_pool_wallet_tool()
|
|
my_puzzle_hash = wallet_a.get_new_puzzlehash()
|
|
recevier_puzzle_hash = bytes32(b"0" * 32)
|
|
coin_to_spend = Coin(bytes32(b"0" * 32), my_puzzle_hash, uint64(1750000000000))
|
|
spend_bundle = wallet_a.generate_signed_transaction(
|
|
uint64(coin_to_spend.amount), recevier_puzzle_hash, coin_to_spend
|
|
)
|
|
response = await full_node_rpc_api.get_fee_estimate(
|
|
{"target_times": [1], "spend_bundle": spend_bundle.to_json_dict()}
|
|
)
|
|
assert response["estimates"] == [0]
|
|
assert response["target_times"] == [1]
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_multiple(setup_node_and_rpc: tuple[FullNodeRpcClient, FullNodeRpcApi]) -> None:
|
|
_client, full_node_rpc_api = setup_node_and_rpc
|
|
response = await full_node_rpc_api.get_fee_estimate({"target_times": [1, 5, 10, 15, 60, 120, 180, 240], "cost": 1})
|
|
assert response["estimates"] == [0, 0, 0, 0, 0, 0, 0, 0]
|
|
assert response["target_times"] == [1, 5, 10, 15, 60, 120, 180, 240]
|
|
|
|
|
|
def get_test_spendbundle(bt: BlockTools) -> SpendBundle:
|
|
wallet_a: WalletTool = bt.get_pool_wallet_tool()
|
|
my_puzzle_hash = wallet_a.get_new_puzzlehash()
|
|
recevier_puzzle_hash = bytes32(b"0" * 32)
|
|
coin_to_spend = Coin(bytes32(b"0" * 32), my_puzzle_hash, uint64(1750000000000))
|
|
return wallet_a.generate_signed_transaction(uint64(coin_to_spend.amount), recevier_puzzle_hash, coin_to_spend)
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_validate_fee_estimate_cost_err(
|
|
setup_node_and_rpc: tuple[FullNodeRpcClient, FullNodeRpcApi], bt: BlockTools
|
|
) -> None:
|
|
spend_bundle = get_test_spendbundle(bt)
|
|
_client, full_node_rpc_api = setup_node_and_rpc
|
|
bad_arglist: list[list[Any]] = [
|
|
[["foo", "bar"]],
|
|
[["spend_bundle", spend_bundle.to_json_dict()], ["cost", 1]],
|
|
[["spend_bundle", spend_bundle.to_json_dict()], ["spend_type", "send_xch_transaction"]],
|
|
[["cost", 1], ["spend_type", "send_xch_transaction"]],
|
|
[["spend_bundle", spend_bundle.to_json_dict()], ["cost", 1], ["spend_type", "send_xch_transaction"]],
|
|
]
|
|
for args in bad_arglist:
|
|
print(args)
|
|
request = {"target_times": [1]}
|
|
for var, val in args:
|
|
print(var)
|
|
request[var] = val
|
|
with pytest.raises(
|
|
RpcError, match=re.escape("Request must contain exactly one of ['spend_bundle', 'cost', 'spend_type']")
|
|
):
|
|
_ = await full_node_rpc_api.get_fee_estimate(request)
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_validate_fee_estimate_cost_ok(
|
|
setup_node_and_rpc: tuple[FullNodeRpcClient, FullNodeRpcApi], bt: BlockTools
|
|
) -> None:
|
|
spend_bundle = get_test_spendbundle(bt)
|
|
_client, full_node_rpc_api = setup_node_and_rpc
|
|
|
|
good_arglist: list[list[Any]] = [
|
|
["spend_bundle", spend_bundle.to_json_dict()],
|
|
["cost", 1],
|
|
["spend_type", "send_xch_transaction"],
|
|
]
|
|
for var, val in good_arglist:
|
|
request = {"target_times": [1]}
|
|
request[var] = val
|
|
_ = await full_node_rpc_api.get_fee_estimate(request)
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_get_spendbundle_type_cost_missing(
|
|
setup_node_and_rpc: tuple[FullNodeRpcClient, FullNodeRpcApi], bt: BlockTools
|
|
) -> None:
|
|
_client, full_node_rpc_api = setup_node_and_rpc
|
|
with pytest.raises(KeyError, match=re.escape("INVALID")):
|
|
request = {"target_times": [1], "spend_type": "INVALID"}
|
|
_ = await full_node_rpc_api.get_fee_estimate(request)
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_get_spendbundle_type_cost_spend_count_ok(
|
|
setup_node_and_rpc: tuple[FullNodeRpcClient, FullNodeRpcApi], bt: BlockTools
|
|
) -> None:
|
|
_client, full_node_rpc_api = setup_node_and_rpc
|
|
spend_counts = [0, 1, 2]
|
|
for spend_count in spend_counts:
|
|
request = {"target_times": [1], "spend_type": "send_xch_transaction", "spend_count": spend_count}
|
|
ret = await full_node_rpc_api.get_fee_estimate(request)
|
|
print(spend_count, ret)
|
|
|
|
|
|
@pytest.mark.anyio
|
|
async def test_get_spendbundle_type_cost_spend_count_bad(
|
|
setup_node_and_rpc: tuple[FullNodeRpcClient, FullNodeRpcApi], bt: BlockTools
|
|
) -> None:
|
|
_client, full_node_rpc_api = setup_node_and_rpc
|
|
with pytest.raises(RpcError):
|
|
request = {"target_times": [1], "spend_type": "send_xch_transaction", "spend_count": -1}
|
|
_ = await full_node_rpc_api.get_fee_estimate(request)
|