Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .github/workflows/test-install-scripts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ concurrency:
group: ${{ github.event_name == 'pull_request' && format('{0}-{1}', github.workflow_ref, github.event.pull_request.number) || github.run_id }}
cancel-in-progress: true

defaults:
run:
shell: bash

jobs:
test_scripts:
name: Native ${{ matrix.os.emoji }} ${{ matrix.arch.emoji }} ${{ matrix.development.name }} - ${{ matrix.editable.name }}
Expand Down Expand Up @@ -109,6 +113,7 @@ jobs:

- name: Run install-gui script (Windows)
if: matrix.os.matrix == 'windows'
shell: pwsh
run: |
./Install-gui.ps1

Expand Down
36 changes: 19 additions & 17 deletions chia/_tests/cmds/wallet/test_notifications.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
from __future__ import annotations

from pathlib import Path
from typing import cast

from chia_rs.sized_bytes import bytes32
from chia_rs.sized_ints import uint32, uint64

from chia._tests.cmds.cmd_test_utils import TestRpcClients, TestWalletRpcClient, logType, run_cli_command_and_assert
from chia._tests.cmds.wallet.test_consts import FINGERPRINT, FINGERPRINT_ARG, get_bytes32
from chia._tests.cmds.wallet.test_consts import FINGERPRINT, FINGERPRINT_ARG, STD_TX, STD_UTX, get_bytes32
from chia.util.bech32m import encode_puzzle_hash
from chia.wallet.conditions import ConditionValidTimes
from chia.wallet.conditions import Condition, ConditionValidTimes
from chia.wallet.notification_store import Notification
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.wallet_request_types import DeleteNotifications, GetNotifications, GetNotificationsResponse
from chia.wallet.util.tx_config import TXConfig
from chia.wallet.wallet_request_types import (
DeleteNotifications,
GetNotifications,
GetNotificationsResponse,
SendNotification,
SendNotificationResponse,
)

test_condition_valid_times: ConditionValidTimes = ConditionValidTimes(min_time=uint64(100), max_time=uint64(150))

Expand All @@ -26,20 +31,17 @@ def test_notifications_send(capsys: object, get_test_cli_clients: tuple[TestRpcC
class NotificationsSendRpcClient(TestWalletRpcClient):
async def send_notification(
self,
target: bytes32,
msg: bytes,
amount: uint64,
fee: uint64 = uint64(0),
push: bool = True,
request: SendNotification,
tx_config: TXConfig,
extra_conditions: tuple[Condition, ...] = tuple(),
timelock_info: ConditionValidTimes = ConditionValidTimes(),
) -> TransactionRecord:
self.add_to_log("send_notification", (target, msg, amount, fee, push, timelock_info))

class FakeTransactionRecord:
def __init__(self, name: str) -> None:
self.name = name
) -> SendNotificationResponse:
self.add_to_log(
"send_notification",
(request.target, request.message, request.amount, request.fee, request.push, timelock_info),
)

return cast(TransactionRecord, FakeTransactionRecord(get_bytes32(2).hex()))
return SendNotificationResponse([STD_UTX], [STD_TX], tx=STD_TX)

inst_rpc_client = NotificationsSendRpcClient()
test_rpc_clients.wallet_rpc_client = inst_rpc_client
Expand Down
30 changes: 16 additions & 14 deletions chia/_tests/core/mempool/test_mempool_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,6 @@ def make_bundle_spends_map_and_fee(
bundle_coin_spends[coin_id] = BundleCoinSpend(
coin_spend=coin_spend,
eligible_for_dedup=bool(spend_conds.flags & ELIGIBLE_FOR_DEDUP),
eligible_for_fast_forward=bool(spend_conds.flags & ELIGIBLE_FOR_FF),
additions=additions,
cost=uint64(spend_conds.condition_cost + spend_conds.execution_cost),
latest_singleton_lineage=UnspentLineageInfo(coin_id, coin_spend.coin.parent_coin_info, bytes32([0] * 32))
Expand Down Expand Up @@ -890,9 +889,13 @@ def mk_bcs(coin_spend: CoinSpend, flags: int = 0) -> BundleCoinSpend:
return BundleCoinSpend(
coin_spend=coin_spend,
eligible_for_dedup=bool(flags & ELIGIBLE_FOR_DEDUP),
eligible_for_fast_forward=bool(flags & ELIGIBLE_FOR_FF),
additions=[],
cost=uint64(0),
latest_singleton_lineage=UnspentLineageInfo(
coin_spend.coin.name(), coin_spend.coin.parent_coin_info, bytes32([0] * 32)
)
if flags & ELIGIBLE_FOR_FF
else None,
)


Expand Down Expand Up @@ -1119,8 +1122,7 @@ def make_test_coins() -> list[Coin]:
],
)
def test_can_replace(existing_items: list[MempoolItem], new_item: MempoolItem, expected: bool) -> None:
removals = {c.name() for c in new_item.spend_bundle.removals()}
assert can_replace(existing_items, removals, new_item) == expected
assert can_replace(existing_items, new_item) == expected


@pytest.mark.anyio
Expand Down Expand Up @@ -1802,16 +1804,16 @@ async def test_bundle_coin_spends() -> None:
assert mi123e.bundle_coin_spends[coins[i].name()] == BundleCoinSpend(
coin_spend=sb123.coin_spends[i],
eligible_for_dedup=False,
eligible_for_fast_forward=False,
additions=[Coin(coins[i].name(), IDENTITY_PUZZLE_HASH, coins[i].amount)],
cost=uint64(ConditionCost.CREATE_COIN.value + ConditionCost.AGG_SIG.value + execution_cost),
latest_singleton_lineage=None,
)
assert mi123e.bundle_coin_spends[coins[3].name()] == BundleCoinSpend(
coin_spend=eligible_sb.coin_spends[0],
eligible_for_dedup=True,
eligible_for_fast_forward=False,
additions=[Coin(coins[3].name(), IDENTITY_PUZZLE_HASH, coins[3].amount)],
cost=uint64(ConditionCost.CREATE_COIN.value + execution_cost),
latest_singleton_lineage=None,
)


Expand Down Expand Up @@ -2463,7 +2465,7 @@ async def test_new_peak_ff_eviction(
item = mempool_manager.get_mempool_item(bundle.name())
assert item is not None
singleton_name = singleton_spend.coin.name()
assert item.bundle_coin_spends[singleton_name].eligible_for_fast_forward
assert item.bundle_coin_spends[singleton_name].supports_fast_forward
latest_singleton_lineage = item.bundle_coin_spends[singleton_name].latest_singleton_lineage
assert latest_singleton_lineage is not None
assert latest_singleton_lineage.coin_id == singleton_name
Expand Down Expand Up @@ -2495,7 +2497,7 @@ async def test_new_peak_ff_eviction(
else:
item = mempool_manager.get_mempool_item(bundle.name())
assert item is not None
assert item.bundle_coin_spends[singleton_spend.coin.name()].eligible_for_fast_forward
assert item.bundle_coin_spends[singleton_spend.coin.name()].supports_fast_forward
latest_singleton_lineage = item.bundle_coin_spends[singleton_spend.coin.name()].latest_singleton_lineage
assert latest_singleton_lineage is not None
assert latest_singleton_lineage.coin_id == singleton_spend.coin.name()
Expand Down Expand Up @@ -2552,9 +2554,9 @@ async def test_multiple_ff(use_optimization: bool) -> None:

item = mempool_manager.get_mempool_item(bundle.name())
assert item is not None
assert item.bundle_coin_spends[singleton_spend1.coin.name()].eligible_for_fast_forward
assert item.bundle_coin_spends[singleton_spend2.coin.name()].eligible_for_fast_forward
assert not item.bundle_coin_spends[coin_spend.coin.name()].eligible_for_fast_forward
assert item.bundle_coin_spends[singleton_spend1.coin.name()].supports_fast_forward
assert item.bundle_coin_spends[singleton_spend2.coin.name()].supports_fast_forward
assert not item.bundle_coin_spends[coin_spend.coin.name()].supports_fast_forward

# spend the singleton coin2 and make coin3 the latest version
coins.update_lineage(singleton_ph, singleton_spend3.coin)
Expand Down Expand Up @@ -2616,7 +2618,7 @@ async def test_advancing_ff(use_optimization: bool) -> None:
item = mempool_manager.get_mempool_item(bundle.name())
assert item is not None
spend = item.bundle_coin_spends[spend_a.coin.name()]
assert spend.eligible_for_fast_forward
assert spend.supports_fast_forward
assert spend.latest_singleton_lineage is not None
assert spend.latest_singleton_lineage.coin_id == spend_a.coin.name()

Expand All @@ -2628,7 +2630,7 @@ async def test_advancing_ff(use_optimization: bool) -> None:
item = mempool_manager.get_mempool_item(bundle.name())
assert item is not None
spend = item.bundle_coin_spends[spend_a.coin.name()]
assert spend.eligible_for_fast_forward
assert spend.supports_fast_forward
assert spend.latest_singleton_lineage is not None
assert spend.latest_singleton_lineage.coin_id == spend_b.coin.name()

Expand All @@ -2640,7 +2642,7 @@ async def test_advancing_ff(use_optimization: bool) -> None:
item = mempool_manager.get_mempool_item(bundle.name())
assert item is not None
spend = item.bundle_coin_spends[spend_a.coin.name()]
assert spend.eligible_for_fast_forward
assert spend.supports_fast_forward
assert spend.latest_singleton_lineage is not None
assert spend.latest_singleton_lineage.coin_id == spend_c.coin.name()

Expand Down
28 changes: 3 additions & 25 deletions chia/_tests/core/mempool/test_singleton_fast_forward.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def test_process_fast_forward_spends_nothing_to_do() -> None:
sb = spend_bundle_from_conditions(conditions, TEST_COIN, sig)
item = mempool_item_from_spendbundle(sb)
# This coin is not eligible for fast forward
assert item.bundle_coin_spends[TEST_COIN_ID].eligible_for_fast_forward is False
assert not item.bundle_coin_spends[TEST_COIN_ID].supports_fast_forward
internal_mempool_item = InternalMempoolItem(sb, item.conds, item.height_added_to_mempool, item.bundle_coin_spends)
original_version = dataclasses.replace(internal_mempool_item)
singleton_ff = SingletonFastForward()
Expand All @@ -63,28 +63,6 @@ def test_process_fast_forward_spends_nothing_to_do() -> None:
assert bundle_coin_spends == original_version.bundle_coin_spends


def test_process_fast_forward_spends_unknown_ff() -> None:
"""
This tests the case when we process for the first time but we are unable
to lookup the latest version from the item's latest singleton lineage
"""
test_coin = Coin(TEST_COIN_ID, IDENTITY_PUZZLE_HASH, uint64(1))
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, 1]]
sb = spend_bundle_from_conditions(conditions, test_coin)
item = mempool_item_from_spendbundle(sb)
# The coin is eligible for fast forward
assert item.bundle_coin_spends[test_coin.name()].eligible_for_fast_forward is True
item.bundle_coin_spends[test_coin.name()].latest_singleton_lineage = None
internal_mempool_item = InternalMempoolItem(sb, item.conds, item.height_added_to_mempool, item.bundle_coin_spends)
singleton_ff = SingletonFastForward()
# We have no fast forward records yet, so we'll process this coin for the
# first time here, but the item's latest singleton lineage returns None
with pytest.raises(ValueError, match="Cannot proceed with singleton spend fast forward"):
singleton_ff.process_fast_forward_spends(
mempool_item=internal_mempool_item, height=TEST_HEIGHT, constants=DEFAULT_CONSTANTS
)


def test_process_fast_forward_spends_latest_unspent() -> None:
"""
This tests the case when we are the latest singleton version already, so
Expand All @@ -103,7 +81,7 @@ def test_process_fast_forward_spends_latest_unspent() -> None:
conditions = [[ConditionOpcode.CREATE_COIN, IDENTITY_PUZZLE_HASH, test_amount]]
sb = spend_bundle_from_conditions(conditions, test_coin)
item = mempool_item_from_spendbundle(sb)
assert item.bundle_coin_spends[test_coin.name()].eligible_for_fast_forward is True
assert item.bundle_coin_spends[test_coin.name()].supports_fast_forward
item.bundle_coin_spends[test_coin.name()].latest_singleton_lineage = test_unspent_lineage_info
internal_mempool_item = InternalMempoolItem(sb, item.conds, item.height_added_to_mempool, item.bundle_coin_spends)
original_version = dataclasses.replace(internal_mempool_item)
Expand Down Expand Up @@ -168,12 +146,12 @@ def test_perform_the_fast_forward() -> None:
"517b0dadb0c310ded24dd86dff8205398080ff808080"
)
test_coin_spend = CoinSpend(test_coin, test_puzzle_reveal, test_solution)
test_spend_data = BundleCoinSpend(test_coin_spend, False, True, [test_child_coin], uint64(0))
test_unspent_lineage_info = UnspentLineageInfo(
coin_id=latest_unspent_coin.name(),
parent_id=latest_unspent_coin.parent_coin_info,
parent_parent_id=test_child_coin.parent_coin_info,
)
test_spend_data = BundleCoinSpend(test_coin_spend, False, [test_child_coin], uint64(0), test_unspent_lineage_info)
# Start from a fresh state of fast forward spends
fast_forward_spends: dict[bytes32, UnspentLineageInfo] = {}
# Perform the fast forward on the test coin (the grandparent)
Expand Down
16 changes: 16 additions & 0 deletions chia/_tests/core/util/test_lru_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import unittest

import pytest

from chia.util.lru_cache import LRUCache


Expand Down Expand Up @@ -54,3 +56,17 @@ def test_lru_cache(self):
assert len(cache.cache) == 5
assert cache.get(b"0") is None
assert cache.get(b"1") == 1


@pytest.mark.parametrize(argnames="capacity", argvalues=[-10, -1, 0])
def test_with_zero_capacity(capacity: int) -> None:
cache: LRUCache[bytes, int] = LRUCache(capacity=capacity)
cache.put(b"0", 1)
assert cache.get(b"0") is None
assert len(cache.cache) == 0


@pytest.mark.parametrize(argnames="capacity", argvalues=[-10, -1, 0, 1, 5, 10])
def test_get_capacity(capacity: int) -> None:
cache: LRUCache[object, object] = LRUCache(capacity=capacity)
assert cache.get_capacity() == capacity
45 changes: 27 additions & 18 deletions chia/_tests/wallet/rpc/test_wallet_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@
PushTX,
RoyaltyAsset,
SelectCoins,
SendNotification,
SendTransaction,
SetWalletResyncOnStartup,
SpendClawbackCoins,
Expand Down Expand Up @@ -2621,21 +2622,25 @@ async def test_notification_rpcs(wallet_rpc_environment: WalletRpcTestEnvironmen
env.wallet_2.node.config["enable_notifications"] = True
env.wallet_2.node.config["required_notification_amount"] = 100000000000
async with wallet_2.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
tx = await client.send_notification(
await action_scope.get_puzzle_hash(wallet_2.wallet_state_manager),
b"hello",
uint64(100000000000),
fee=uint64(100000000000),
response = await client.send_notification(
SendNotification(
target=(await action_scope.get_puzzle_hash(wallet_2.wallet_state_manager)),
message=b"hello",
amount=uint64(100000000000),
fee=uint64(100000000000),
push=True,
),
tx_config=DEFAULT_TX_CONFIG,
)

assert tx.spend_bundle is not None
assert response.tx.spend_bundle is not None
await time_out_assert(
5,
full_node_api.full_node.mempool_manager.get_spendbundle,
tx.spend_bundle,
tx.spend_bundle.name(),
response.tx.spend_bundle,
response.tx.spend_bundle.name(),
)
await farm_transaction(full_node_api, wallet_node, tx.spend_bundle)
await farm_transaction(full_node_api, wallet_node, response.tx.spend_bundle)
await time_out_assert(20, env.wallet_2.wallet.get_confirmed_balance, uint64(100000000000))

notification = (await client_2.get_notifications(GetNotifications())).notifications[0]
Expand All @@ -2648,21 +2653,25 @@ async def test_notification_rpcs(wallet_rpc_environment: WalletRpcTestEnvironmen
assert [] == (await client_2.get_notifications(GetNotifications([notification.id]))).notifications

async with wallet_2.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
tx = await client.send_notification(
await action_scope.get_puzzle_hash(wallet_2.wallet_state_manager),
b"hello",
uint64(100000000000),
fee=uint64(100000000000),
response = await client.send_notification(
SendNotification(
target=(await action_scope.get_puzzle_hash(wallet_2.wallet_state_manager)),
message=b"hello",
amount=uint64(100000000000),
fee=uint64(100000000000),
push=True,
),
tx_config=DEFAULT_TX_CONFIG,
)

assert tx.spend_bundle is not None
assert response.tx.spend_bundle is not None
await time_out_assert(
5,
full_node_api.full_node.mempool_manager.get_spendbundle,
tx.spend_bundle,
tx.spend_bundle.name(),
response.tx.spend_bundle,
response.tx.spend_bundle.name(),
)
await farm_transaction(full_node_api, wallet_node, tx.spend_bundle)
await farm_transaction(full_node_api, wallet_node, response.tx.spend_bundle)
await time_out_assert(20, env.wallet_2.wallet.get_confirmed_balance, uint64(200000000000))

notification = (await client_2.get_notifications(GetNotifications())).notifications[0]
Expand Down
23 changes: 15 additions & 8 deletions chia/cmds/wallet_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
NFTSetNFTDID,
NFTTransferNFT,
RoyaltyAsset,
SendNotification,
SendTransaction,
SendTransactionResponse,
SignMessageByAddress,
Expand Down Expand Up @@ -1576,19 +1577,25 @@ async def send_notification(
async with get_wallet_client(root_path, wallet_rpc_port, fp) as (wallet_client, fingerprint, _):
amount: uint64 = cli_amount.convert_amount(units["chia"])

tx = await wallet_client.send_notification(
address.puzzle_hash,
message,
amount,
fee,
push=push,
response = await wallet_client.send_notification(
SendNotification(
address.puzzle_hash,
message,
amount,
fee=fee,
push=push,
),
tx_config=DEFAULT_TX_CONFIG,
timelock_info=condition_valid_times,
)

if push:
print("Notification sent successfully.")
print(f"To get status, use command: chia wallet get_transaction -f {fingerprint} -tx 0x{tx.name}")
return [tx]
print(
"To get status, use command: chia wallet get_transaction"
f" -f {fingerprint} -tx 0x{response.transactions[0].name}"
)
return response.transactions


async def get_notifications(
Expand Down
Loading
Loading