Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/check_wheel_availability.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
matrix: arm
- name: Intel
matrix: intel
python-version: ["3.10", "3.11", "3.12", "3.13"]
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
exclude:
- os:
matrix: windows
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ jobs:
- major_dot_minor: "3.11"
- major_dot_minor: "3.12"
- major_dot_minor: "3.13"
- major_dot_minor: "3.14"
exclude:
- os:
matrix: windows
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/test-single.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,16 @@ jobs:
exclude_from:
limited: True
main: True
- name: "3.14"
file_name: "3.14"
action: "3.14"
apt: "3.14"
install_sh: "3.14"
matrix: "3.14"
exclude_from:
limited: True
main: True

exclude:
- arch:
matrix: arm
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/upload-pypi-source.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ jobs:
- major_dot_minor: "3.11"
- major_dot_minor: "3.12"
- major_dot_minor: "3.13"
- major_dot_minor: "3.14"
check:
- name: mypy
command: |
Expand Down
2 changes: 1 addition & 1 deletion Install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ if ($null -eq (Get-Command py -ErrorAction SilentlyContinue))
Exit 1
}

$supportedPythonVersions = "3.13", "3.12", "3.11", "3.10"
$supportedPythonVersions = "3.14", "3.13", "3.12", "3.11", "3.10"
if ("$env:INSTALL_PYTHON_VERSION" -ne "")
{
$pythonVersion = $env:INSTALL_PYTHON_VERSION
Expand Down
1 change: 1 addition & 0 deletions chia/_tests/core/full_node/test_full_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -3363,6 +3363,7 @@ async def test_pending_tx_cache_retry_on_new_peak(


@pytest.mark.anyio
@pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.HARD_FORK_2_0], reason="irrelevant")
@pytest.mark.parametrize("mismatch_cost", [True, False])
@pytest.mark.parametrize("mismatch_fee", [True, False])
@pytest.mark.parametrize("tx_already_seen", [True, False])
Expand Down
1 change: 1 addition & 0 deletions chia/_tests/core/server/test_dos.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ async def test_banned_host_can_not_connect(
await session.ws_connect(
url, autoclose=True, autoping=True, ssl=ssl_context, max_msg_size=100 * 1024 * 1024
)
await session.close()

@pytest.mark.anyio
async def test_large_message_disconnect_and_ban(
Expand Down
15 changes: 9 additions & 6 deletions chia/_tests/core/server/test_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import subprocess
import sys
import threading
import warnings
from collections.abc import AsyncIterator
from dataclasses import dataclass, field

Expand Down Expand Up @@ -115,12 +116,14 @@ def port(self) -> int:

def _run(self) -> None:
# TODO: yuck yuck, messes with a single global
original_event_loop_policy = asyncio.get_event_loop_policy()
asyncio.set_event_loop_policy(chia_policy.ChiaPolicy())
try:
asyncio.run(self.main())
finally:
asyncio.set_event_loop_policy(original_event_loop_policy)
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
original_event_loop_policy = asyncio.get_event_loop_policy()
asyncio.set_event_loop_policy(chia_policy.ChiaPolicy())
try:
asyncio.run(self.main())
finally:
asyncio.set_event_loop_policy(original_event_loop_policy)

async def main(self) -> None:
self.server_task = create_referenced_task(
Expand Down
2 changes: 1 addition & 1 deletion chia/_tests/core/test_daemon_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ async def test_get_version_rpc(get_daemon, bt):

assert response["data"]["success"]
assert response["data"]["version"] == __version__
ws_server.stop()
await ws_server.stop()
2 changes: 1 addition & 1 deletion chia/_tests/simulation/test_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ async def test_process_transaction_records(
)

await full_node_api.process_transaction_records(records=action_scope.side_effects.transactions)
assert full_node_api.full_node.coin_store.get_coin_record(coin.name()) is not None
assert await full_node_api.full_node.coin_store.get_coin_record(coin.name()) is not None


@pytest.mark.anyio
Expand Down
4 changes: 3 additions & 1 deletion chia/_tests/util/temp_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@

@contextlib.contextmanager
def TempFile() -> Iterator[Path]:
path = Path(tempfile.NamedTemporaryFile().name)
t = tempfile.NamedTemporaryFile(delete=False)
path = Path(t.name)
t.close()
yield path
if path.exists():
path.unlink()
8 changes: 7 additions & 1 deletion chia/_tests/util/test_replace_str_to_bytes.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from __future__ import annotations

import sys

import pytest
from chia_rs import ConsensusConstants
from chia_rs.sized_bytes import bytes32
Expand Down Expand Up @@ -138,7 +140,11 @@ def test_replace_str_to_bytes_deprecated_field(caplog: pytest.LogCaptureFixture)

def test_replace_str_to_bytes_invalid_value() -> None:
# invalid value
with pytest.raises(ValueError, match="non-hexadecimal number found in"):
if sys.version_info >= (3, 14):
matchstr = "arg must contain an even number of hexadecimal digits"
else:
matchstr = "non-hexadecimal number found in"
with pytest.raises(ValueError, match=matchstr):
replace_str_to_bytes(
test_constants,
GENESIS_PRE_FARM_FARMER_PUZZLE_HASH="fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
Expand Down
17 changes: 8 additions & 9 deletions chia/_tests/wallet/rpc/test_dl_wallet_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,18 +382,17 @@ async def test_wallet_dl_verify_proof(
wallet_node.config["trusted_peers"] = {}

assert wallet_service.rpc_server is not None
client = await WalletRpcClient.create(
async with WalletRpcClient.create_as_context(
self_hostname,
wallet_service.rpc_server.listen_port,
wallet_service.root_path,
wallet_service.config,
)

with pytest.raises(ValueError, match="No peer connected"):
await wallet_service.rpc_server.rpc_api.dl_verify_proof(fake_gpr.to_json_dict())
) as client:
with pytest.raises(ValueError, match="No peer connected"):
await wallet_service.rpc_server.rpc_api.dl_verify_proof(fake_gpr.to_json_dict())

await wallet_node.server.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
await validate_get_routes(client, wallet_service.rpc_server.rpc_api)
await wallet_node.server.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
await validate_get_routes(client, wallet_service.rpc_server.rpc_api)

with pytest.raises(ValueError, match=f"Invalid Proof: No DL singleton found at coin id: {fake_coin_id}"):
await client.dl_verify_proof(fake_gpr)
with pytest.raises(ValueError, match=f"Invalid Proof: No DL singleton found at coin id: {fake_coin_id}"):
await client.dl_verify_proof(fake_gpr)
3 changes: 3 additions & 0 deletions chia/_tests/wallet/vc_wallet/test_vc_wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -873,3 +873,6 @@ async def check_length(length: int, func: Callable[..., Awaitable[Any]], *args:
await time_out_assert_not_none(
15, check_length, 0, wallet_node_0.wallet_state_manager.get_all_wallet_info_entries, WalletType.CAT
)

client_0.close()
await client_0.await_closed()
5 changes: 2 additions & 3 deletions chia/full_node/full_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -1069,9 +1069,8 @@ async def _sync(self) -> None:
tb = traceback.format_exc()
self.log.error(f"Error with syncing: {type(e)}{tb}")
finally:
if self._shut_down:
return None
await self._finish_sync(fork_point)
if not self._shut_down:
await self._finish_sync(fork_point)

async def request_validate_wp(
self, peak_header_hash: bytes32, peak_height: uint32, peak_weight: uint128
Expand Down
10 changes: 9 additions & 1 deletion chia/full_node/mempool.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,15 @@ def __init__(self, mempool_info: MempoolInfo, fee_estimator: FeeEstimatorInterfa
self.fee_estimator: FeeEstimatorInterface = fee_estimator

def __del__(self) -> None:
self._db_conn.close()
try:
self._db_conn.close()
except sqlite3.ProgrammingError:
#
# ignore case where this cleanup happens in another thread
# TODO: this should probably be refactored to use context managers
# instead of relying on __del__
#
pass

def _row_to_item(self, row: sqlite3.Row) -> MempoolItem:
name = bytes32(row[0])
Expand Down
4 changes: 2 additions & 2 deletions chia/seeder/dns_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -462,9 +462,9 @@ async def refresh_reliable_peers(self) -> None:
try:
validated_peer = ip_address(peer)
if validated_peer.version == 4:
self.reliable_peers_v4.append(validated_peer)
self.reliable_peers_v4.append(IPv4Address(validated_peer))
elif validated_peer.version == 6:
self.reliable_peers_v6.append(validated_peer)
self.reliable_peers_v6.append(IPv6Address(validated_peer))
except ValueError:
log.error(f"Invalid peer: {peer}")
continue
Expand Down
30 changes: 22 additions & 8 deletions chia/server/chia_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,15 +348,29 @@ def disable_connections(self) -> None:
self._proactor.disable_connections()


class ChiaPolicy(asyncio.DefaultEventLoopPolicy):
def new_event_loop(self) -> asyncio.AbstractEventLoop:
# overriding https://github.com/python/cpython/blob/v3.11.0/Lib/asyncio/events.py#L689-L695
if sys.platform == "win32":
loop_factory = ChiaProactorEventLoop
else:
loop_factory = ChiaSelectorEventLoop
if sys.version_info >= (3, 14):
# DefaultEventLoopPolicy is deprecated in 3.14 and will be removed in 3.16
# Need to inherit from _BaseDefaultEventLoopPolicy instead
class ChiaPolicy(asyncio.events._BaseDefaultEventLoopPolicy):
def new_event_loop(self) -> asyncio.AbstractEventLoop:
# overriding https://github.com/python/cpython/blob/v3.14.0/Lib/asyncio/events.py#L726-L732
if sys.platform == "win32":
loop_factory = ChiaProactorEventLoop
else:
loop_factory = ChiaSelectorEventLoop

return loop_factory()
else:

class ChiaPolicy(asyncio.DefaultEventLoopPolicy):
def new_event_loop(self) -> asyncio.AbstractEventLoop:
# overriding https://github.com/python/cpython/blob/v3.11.0/Lib/asyncio/events.py#L689-L695
if sys.platform == "win32":
loop_factory = ChiaProactorEventLoop
else:
loop_factory = ChiaSelectorEventLoop

return loop_factory()
return loop_factory()


def set_chia_policy(connection_limit: int) -> None:
Expand Down
2 changes: 1 addition & 1 deletion chia/wallet/cat_wallet/r_cat_wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ async def convert_to_revocable(
cat_wallet: CATWallet,
hidden_puzzle_hash: bytes32,
) -> bool:
if not cat_wallet.lineage_store.is_empty():
if not await cat_wallet.lineage_store.is_empty():
cat_wallet.log.error("Received a revocable CAT to a CAT wallet that already has CATs")
return False
replace_self = cls()
Expand Down
4 changes: 2 additions & 2 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ OPENSSL_VERSION_INT=
find_python() {
set +e
unset BEST_VERSION
for V in 313 3.13 312 3.12 311 3.11 310 3.10 3; do
for V in 314 3.14 313 3.13 312 3.12 311 3.11 310 3.10 3; do
if command -v python$V >/dev/null; then
if [ "$BEST_VERSION" = "" ]; then
BEST_VERSION=$V
Expand Down Expand Up @@ -134,7 +134,7 @@ if ! command -v "$INSTALL_PYTHON_PATH" >/dev/null; then
exit 1
fi

if [ "$PYTHON_MAJOR_VER" -ne "3" ] || [ "$PYTHON_MINOR_VER" -lt "10" ] || [ "$PYTHON_MINOR_VER" -ge "14" ]; then
if [ "$PYTHON_MAJOR_VER" -ne "3" ] || [ "$PYTHON_MINOR_VER" -lt "10" ] || [ "$PYTHON_MINOR_VER" -ge "15" ]; then
echo "Chia requires Python version >= 3.10 and < 3.14.0" >&2
echo "Current Python version = $INSTALL_PYTHON_VERSION" >&2
# If Arch, direct to Arch Wiki
Expand Down
Loading
Loading