Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Quexington committed Aug 19, 2024
1 parent 8f89ed6 commit d29c99e
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 9 deletions.
177 changes: 176 additions & 1 deletion chia/_tests/wallet/rpc/test_wallet_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import pytest
from chia_rs import G2Element

from chia._tests.conftest import ConsensusMode
from chia._tests.environments.wallet import WalletStateTransition, WalletTestFramework
from chia._tests.util.time_out_assert import time_out_assert, time_out_assert_not_none
from chia._tests.wallet.test_wallet_coin_store import (
get_coin_records_amount_filter_tests,
Expand Down Expand Up @@ -42,8 +44,9 @@
from chia.consensus.block_rewards import calculate_base_farmer_reward, calculate_pool_reward
from chia.consensus.coinbase import create_puzzlehash_for_pk
from chia.rpc.full_node_rpc_client import FullNodeRpcClient
from chia.rpc.rpc_client import ResponseFailureError
from chia.rpc.rpc_server import RpcServer
from chia.rpc.wallet_request_types import GetNotifications
from chia.rpc.wallet_request_types import GetNotifications, SplitCoins, SplitCoinsResponse
from chia.rpc.wallet_rpc_api import WalletRpcApi
from chia.rpc.wallet_rpc_client import WalletRpcClient
from chia.server.server import ChiaServer
Expand Down Expand Up @@ -2598,3 +2601,175 @@ async def test_get_balances(wallet_rpc_environment: WalletRpcTestEnvironment):
assert len(bal_ids) == 2
assert bal["2"]["confirmed_wallet_balance"] == 100
assert bal["3"]["confirmed_wallet_balance"] == 20


@pytest.mark.parametrize(
"wallet_environments",
[
{
"num_environments": 1,
"blocks_needed": [1],
}
],
indirect=True,
)
@pytest.mark.limit_consensus_modes([ConsensusMode.PLAIN], reason="irrelevant")
@pytest.mark.anyio
async def test_split_coins(wallet_environments: WalletTestFramework) -> None:
env = wallet_environments.environments[0]
env.wallet_aliases = {
"xch": 1,
"cat": 2,
}

# Test XCH first
async with env.wallet_state_manager.new_action_scope(wallet_environments.tx_config) as action_scope:
target_coin = list(await env.xch_wallet.select_coins(uint64(250_000_000_000), action_scope))[0]
assert target_coin.amount == 250_000_000_000

xch_request = SplitCoins(
wallet_id=uint32(1),
number_of_coins=uint16(100),
amount_per_coin=uint64(100),
target_coin_id=target_coin.name(),
fee=uint64(1_000_000_000_000), # 1 XCH
push=True,
)

with pytest.raises(ResponseFailureError, match="501 coins is greater then the maximum limit of 500 coins"):
await env.rpc_client.split_coins(
dataclasses.replace(xch_request, number_of_coins=uint16(501)),
wallet_environments.tx_config,
)

with pytest.raises(ResponseFailureError, match="Could not find coin with ID 00000000000000000"):
await env.rpc_client.split_coins(
dataclasses.replace(xch_request, target_coin_id=bytes32([0] * 32)),
wallet_environments.tx_config,
)

with pytest.raises(ResponseFailureError, match="is less than the total amount of the split"):
await env.rpc_client.split_coins(
dataclasses.replace(xch_request, amount_per_coin=uint64(1_000_000_000_000)),
wallet_environments.tx_config,
)

with pytest.raises(ResponseFailureError, match="Wallet with ID 42 does not exist"):
await env.rpc_client.split_coins(
dataclasses.replace(xch_request, wallet_id=uint32(42)),
wallet_environments.tx_config,
)

env.wallet_state_manager.wallets[uint32(42)] = object() # type: ignore[assignment]
with pytest.raises(ResponseFailureError, match="Cannot split coins from non-fungible wallet types"):
await env.rpc_client.split_coins(
dataclasses.replace(xch_request, wallet_id=uint32(42)),
wallet_environments.tx_config,
)
del env.wallet_state_manager.wallets[uint32(42)]

response = await env.rpc_client.split_coins(
dataclasses.replace(xch_request, number_of_coins=uint16(0)),
wallet_environments.tx_config,
)
assert response == SplitCoinsResponse([], [])

await env.rpc_client.split_coins(
xch_request,
wallet_environments.tx_config,
)

await wallet_environments.process_pending_states(
[
WalletStateTransition(
pre_block_balance_updates={
"xch": {
"unconfirmed_wallet_balance": -1_000_000_000_000, # just the fee
"spendable_balance": -2_000_000_000_000,
"pending_change": 1_000_000_000_000,
"max_send_amount": -2_000_000_000_000,
"pending_coin_removal_count": 2,
}
},
post_block_balance_updates={
"xch": {
"confirmed_wallet_balance": -1_000_000_000_000, # just the fee
"spendable_balance": 1_000_000_000_000,
"pending_change": -1_000_000_000_000,
"max_send_amount": 1_000_000_000_000,
"pending_coin_removal_count": -2,
"unspent_coin_count": 99, # split 1 into 100 i.e. +99
}
},
)
]
)

# Now do CATs
async with env.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
cat_wallet = await CATWallet.create_new_cat_wallet(
env.wallet_state_manager,
env.xch_wallet,
{"identifier": "genesis_by_id"},
uint64(50),
action_scope,
)

await wallet_environments.process_pending_states(
[
WalletStateTransition(
# no need to test this, it is tested elsewhere
pre_block_balance_updates={
"xch": {"set_remainder": True},
"cat": {"init": True, "set_remainder": True},
},
post_block_balance_updates={
"xch": {"set_remainder": True},
"cat": {"set_remainder": True},
},
)
]
)

async with env.wallet_state_manager.new_action_scope(wallet_environments.tx_config) as action_scope:
target_coin = list(await cat_wallet.select_coins(uint64(50), action_scope))[0]
assert target_coin.amount == 50

cat_request = SplitCoins(
wallet_id=uint32(2),
number_of_coins=uint16(50),
amount_per_coin=uint64(1),
target_coin_id=target_coin.name(),
push=True,
)

await env.rpc_client.split_coins(
cat_request,
wallet_environments.tx_config,
)

await wallet_environments.process_pending_states(
[
WalletStateTransition(
pre_block_balance_updates={
"cat": {
"unconfirmed_wallet_balance": 0,
"spendable_balance": -50,
"pending_change": 50,
"max_send_amount": -50,
"pending_coin_removal_count": 1,
}
},
post_block_balance_updates={
"cat": {
"confirmed_wallet_balance": 0,
"spendable_balance": 50,
"pending_change": -50,
"max_send_amount": 50,
"pending_coin_removal_count": -1,
"unspent_coin_count": 49, # split 1 into 50 i.e. +49
}
},
)
]
)
13 changes: 6 additions & 7 deletions chia/rpc/wallet_rpc_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1107,6 +1107,8 @@ async def split_coins(
f"Coin amount: {coin.amount} is less than the total amount of the split: {total_amount}, exiting."
)

if request.wallet_id not in self.service.wallet_state_manager.wallets:
raise ValueError(f"Wallet with ID {request.wallet_id} does not exist")
wallet = self.service.wallet_state_manager.wallets[request.wallet_id]
if not isinstance(wallet, (Wallet, CATWallet)):
raise ValueError("Cannot split coins from non-fungible wallet types")
Expand All @@ -1122,16 +1124,13 @@ async def split_coins(
if wallet.type() == WalletType.STANDARD_WALLET:
assert isinstance(wallet, Wallet)
if coin.amount < total_amount + request.fee:
async with action_scope.use() as interface:
interface.side_effects.selected_coins.append(coin)
coins = await wallet.select_coins(
uint64(total_amount + request.fee - coin.amount),
dataclasses.replace(
action_scope.config.tx_config.coin_selection_config,
excluded_coin_ids=[
coin.name(),
*action_scope.config.tx_config.coin_selection_config.excluded_coin_ids,
],
),
action_scope,
)
coins.add(coin)
else:
coins = {coin}
await wallet.generate_signed_transaction(
Expand Down
2 changes: 1 addition & 1 deletion chia/rpc/wallet_rpc_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1709,5 +1709,5 @@ async def split_coins(
tx_config: TXConfig,
) -> SplitCoinsResponse:
return SplitCoinsResponse.from_json_dict(
await self.fetch("split_coins", {*args.to_json_dict(), *tx_config.to_json_dict()})
await self.fetch("split_coins", {**args.to_json_dict(), **tx_config.to_json_dict()})
)

0 comments on commit d29c99e

Please sign in to comment.