Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CHIA-1348] Port chia wallet coin commands to @chia_command framework #18641

Open
wants to merge 29 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0d5e6ab
Extract TransactionsIn/Out
Quexington Sep 20, 2024
c692f93
Create a helper for coin selection arguments
Quexington Sep 23, 2024
e708fad
Port `chia wallet coins list`
Quexington Sep 23, 2024
e462c10
Unused item
Quexington Sep 24, 2024
0df4ff5
Add TransactionEndpoint
Quexington Sep 24, 2024
1409b07
Port `chia wallet coins combine`
Quexington Sep 25, 2024
8f56cd2
Port `chia wallet coins split`
Quexington Sep 25, 2024
32f07e2
Delete test_coins.py
Quexington Sep 25, 2024
2b91e01
Add test for TXConfig helpers
Quexington Sep 25, 2024
fb1731b
Add test for TransactionEndpoint mixin
Quexington Sep 26, 2024
025fac6
Forgot to delete old split command
Quexington Sep 26, 2024
b043e2d
test coverage
Quexington Sep 26, 2024
d0f47f0
coverage ignores
Quexington Sep 26, 2024
d6c80c9
Link old framework with new
Quexington Sep 26, 2024
db75520
fix command tests
Quexington Sep 26, 2024
b5ad8ac
fix signer test
Quexington Sep 27, 2024
51fee38
coverage ignores
Quexington Sep 27, 2024
272b636
Merge remote-tracking branch 'origin/main' into quex.port_coin_cmds_t…
Quexington Oct 28, 2024
def23d4
Merge remote-tracking branch 'origin/main' into quex.port_coin_cmds_t…
Quexington Nov 15, 2024
d9e9c10
pre-commit
Quexington Nov 15, 2024
cae866c
Move tests back to rpc file
Quexington Dec 4, 2024
914997d
Move coin functions back to their own file
Quexington Dec 4, 2024
115dc71
Merge remote-tracking branch 'origin/main' into quex.port_coin_cmds_t…
Quexington Dec 4, 2024
6135a27
Move split above combine in rpc tests
Quexington Dec 4, 2024
f77fc4e
Stop duplicate name definitions
Quexington Dec 5, 2024
8d92fee
new puzzle hashes allowed
Quexington Dec 9, 2024
5bbc3df
Merge remote-tracking branch 'origin/main' into quex.port_coin_cmds_t…
Quexington Dec 10, 2024
2634e56
Address comments by @altendky
Quexington Dec 11, 2024
5b81208
more comments by @altendky
Quexington Dec 12, 2024
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
220 changes: 216 additions & 4 deletions chia/_tests/cmds/test_cmd_framework.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,35 @@
import textwrap
from collections.abc import Sequence
from dataclasses import asdict
from decimal import Decimal
from typing import Any, Optional

import click
import pytest
from click.testing import CliRunner

from chia._tests.conftest import ConsensusMode
from chia._tests.environments.wallet import WalletTestFramework
from chia._tests.environments.wallet import STANDARD_TX_ENDPOINT_ARGS, WalletTestFramework
from chia._tests.wallet.conftest import * # noqa
from chia.cmds.cmd_classes import ChiaCommand, Context, NeedsWalletRPC, chia_command, option
from chia.cmds.cmd_classes import (
_DECORATOR_APPLIED,
ChiaCommand,
Context,
NeedsCoinSelectionConfig,
NeedsTXConfig,
NeedsWalletRPC,
TransactionEndpoint,
TransactionEndpointWithTimelocks,
chia_command,
option,
transaction_endpoint_runner,
)
from chia.cmds.cmds_util import coin_selection_args, tx_config_args, tx_out_cmd
from chia.cmds.param_types import CliAmount
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.util.ints import uint64
from chia.wallet.conditions import ConditionValidTimes
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.util.tx_config import CoinSelectionConfig, TXConfig


def check_click_parsing(cmd: ChiaCommand, *args: str, obj: Optional[Any] = None) -> None:
Expand All @@ -36,6 +54,9 @@ def new_run(self: Any) -> None:
# cmd is appropriately not recognized as a dataclass but I'm not sure how to hint that something is a dataclass
dict_compare_with_ignore_context(asdict(cmd), asdict(self)) # type: ignore[call-overload]

# We hack this in because more robust solutions are harder and probably not worth it
setattr(new_run, _DECORATOR_APPLIED, True)

setattr(mock_type, "run", new_run)
chia_command(_cmd, "_", "", "")(mock_type)

Expand Down Expand Up @@ -330,7 +351,7 @@ def run(self) -> None: ...
assert "not a valid 32-byte hex string" in result.output


@pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="doesn't matter")
@pytest.mark.limit_consensus_modes(reason="doesn't matter")
@pytest.mark.parametrize(
"wallet_environments",
[
Expand Down Expand Up @@ -400,3 +421,194 @@ def run(self) -> None:
test_present_client_info = TempCMD(rpc_info=NeedsWalletRPC(client_info="hello world")) # type: ignore[arg-type]
async with test_present_client_info.rpc_info.wallet_rpc(consume_errors=False) as client_info:
assert client_info == "hello world" # type: ignore[comparison-overlap]


def test_tx_config_helper() -> None:
@click.group()
def cmd() -> None:
pass # pragma: no cover

@chia_command(cmd, "cs_cmd", "blah", "blah")
class CsCMD:
coin_selection_loader: NeedsCoinSelectionConfig

def run(self) -> None:
assert self.coin_selection_loader.load_coin_selection_config(100) == CoinSelectionConfig(
min_coin_amount=uint64(1),
max_coin_amount=uint64(1),
excluded_coin_amounts=[uint64(1)],
excluded_coin_ids=[bytes32([0] * 32)],
)
altendky marked this conversation as resolved.
Show resolved Hide resolved

example_cs_cmd = CsCMD(
coin_selection_loader=NeedsCoinSelectionConfig(
min_coin_amount=CliAmount(amount=Decimal("0.01"), mojos=False),
max_coin_amount=CliAmount(amount=Decimal("0.01"), mojos=False),
amounts_to_exclude=(CliAmount(amount=Decimal("0.01"), mojos=False),),
coins_to_exclude=(bytes32([0] * 32),),
)
)

check_click_parsing(
example_cs_cmd,
"--min-coin-amount",
"0.01",
"--max-coin-amount",
"0.01",
"--exclude-amount",
"0.01",
"--exclude-coin",
bytes32([0] * 32).hex(),
)

example_cs_cmd.run() # trigger inner assert

@chia_command(cmd, "tx_confg_cmd", "blah", "blah")
altendky marked this conversation as resolved.
Show resolved Hide resolved
class TXConfigCMD:
tx_config_loader: NeedsTXConfig

def run(self) -> None:
assert self.tx_config_loader.load_tx_config(100, {}, 0) == TXConfig(
min_coin_amount=uint64(1),
max_coin_amount=uint64(1),
excluded_coin_amounts=[uint64(1)],
excluded_coin_ids=[bytes32([0] * 32)],
reuse_puzhash=False,
)

example_tx_config_cmd = TXConfigCMD(
tx_config_loader=NeedsTXConfig(
min_coin_amount=CliAmount(amount=Decimal("0.01"), mojos=False),
max_coin_amount=CliAmount(amount=Decimal("0.01"), mojos=False),
amounts_to_exclude=(CliAmount(amount=Decimal("0.01"), mojos=False),),
coins_to_exclude=(bytes32([0] * 32),),
reuse=False,
)
)

check_click_parsing(
example_tx_config_cmd,
"--min-coin-amount",
"0.01",
"--max-coin-amount",
"0.01",
"--exclude-amount",
"0.01",
"--exclude-coin",
bytes32([0] * 32).hex(),
"--new-address",
)

example_tx_config_cmd.run() # trigger inner assert


@pytest.mark.anyio
async def test_transaction_endpoint_mixin() -> None:
@click.group()
def cmd() -> None:
pass # pragma: no cover

with pytest.raises(TypeError, match="transaction_endpoint_runner"):

@chia_command(cmd, "bad_cmd", "blah", "blah")
class BadCMD(TransactionEndpoint):
def run(self) -> None:
pass # pragma: no cover

BadCMD(**STANDARD_TX_ENDPOINT_ARGS)
altendky marked this conversation as resolved.
Show resolved Hide resolved

@chia_command(cmd, "cs_cmd", "blah", "blah")
class TxCMD(TransactionEndpoint):
@transaction_endpoint_runner
async def run(self) -> list[TransactionRecord]:
assert self.load_condition_valid_times() == ConditionValidTimes(
min_time=uint64(10),
max_time=uint64(20),
)
return []

# Check that our default object lines up with the default options
check_click_parsing(TxCMD(**STANDARD_TX_ENDPOINT_ARGS))

example_tx_cmd = TxCMD(
**{
**STANDARD_TX_ENDPOINT_ARGS,
**dict(
fee=uint64(1_000_000_000_000 / 100),
push=False,
valid_at=10,
expires_at=20,
),
}
)
check_click_parsing(
example_tx_cmd,
"--fee",
"0.01",
"--no-push",
"--valid-at",
"10",
"--expires-at",
"20",
)

await example_tx_cmd.run() # trigger inner assert


# While we sit in between two paradigms, this test is in place to ensure they remain in sync.
# Delete this if the old decorators are deleted.
def test_old_decorator_support() -> None:
@click.group()
def cmd() -> None:
pass # pragma: no cover

@chia_command(cmd, "cs_cmd", "blah", "blah")
class CsCMD:
coin_selection_loader: NeedsCoinSelectionConfig

def run(self) -> None:
pass # pragma: no cover

@chia_command(cmd, "tx_config_cmd", "blah", "blah")
class TXConfigCMD:
tx_config_loader: NeedsTXConfig

def run(self) -> None:
pass # pragma: no cover

@chia_command(cmd, "tx_cmd", "blah", "blah")
class TxCMD(TransactionEndpoint):
def run(self) -> None:
pass # pragma: no cover

@chia_command(cmd, "tx_w_tl_cmd", "blah", "blah")
class TxWTlCMD(TransactionEndpointWithTimelocks):
def run(self) -> None:
pass # pragma: no cover

@cmd.command("cs_cmd_dec")
@coin_selection_args
def cs_cmd(**kwargs: Any) -> None:
pass # pragma: no cover

@cmd.command("tx_config_cmd_dec")
@tx_config_args
def tx_config_cmd(**kwargs: Any) -> None:
pass # pragma: no cover

@cmd.command("tx_cmd_dec") # type: ignore[arg-type]
@tx_out_cmd(enable_timelock_args=False)
def tx_cmd(**kwargs: Any) -> None:
pass # pragma: no cover

@cmd.command("tx_w_tl_cmd_dec") # type: ignore[arg-type]
@tx_out_cmd(enable_timelock_args=True)
def tx_w_tl_cmd(**kwargs: Any) -> None:
pass # pragma: no cover

for command_name, command in cmd.commands.items():
if "_dec" in command_name:
continue
params = [param.to_info_dict() for param in cmd.commands[command_name].params]
for param in cmd.commands[f"{command_name}_dec"].params:
assert param.to_info_dict() in params
Loading
Loading