Skip to content

Commit c41a5f6

Browse files
committed
Port select_coins to @marshal
1 parent c8a2fa1 commit c41a5f6

File tree

6 files changed

+169
-93
lines changed

6 files changed

+169
-93
lines changed

chia/_tests/wallet/nft_wallet/test_nft_bulk_mint.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from chia.wallet.nft_wallet.uncurry_nft import UncurriedNFT
1616
from chia.wallet.transaction_record import TransactionRecord
1717
from chia.wallet.util.address_type import AddressType
18-
from chia.wallet.wallet_request_types import NFTGetNFTs, NFTMintBulk, NFTMintMetadata, PushTransactions
18+
from chia.wallet.wallet_request_types import NFTGetNFTs, NFTMintBulk, NFTMintMetadata, PushTransactions, SelectCoins
1919

2020

2121
async def nft_count(wallet: NFTWallet) -> int:
@@ -291,22 +291,25 @@ async def test_nft_mint_rpc(wallet_environments: WalletTestFramework, zero_royal
291291
fee = 100
292292
num_chunks = int(n / chunk) + (1 if n % chunk > 0 else 0)
293293
required_amount = n + (fee * num_chunks)
294-
xch_coins = await env_0.rpc_client.select_coins(
295-
amount=required_amount,
296-
coin_selection_config=wallet_environments.tx_config.coin_selection_config,
297-
wallet_id=wallet_0.id(),
294+
select_coins_response = await env_0.rpc_client.select_coins(
295+
SelectCoins.from_coin_selection_config(
296+
amount=uint64(required_amount),
297+
coin_selection_config=wallet_environments.tx_config.coin_selection_config,
298+
wallet_id=wallet_0.id(),
299+
)
298300
)
299-
funding_coin = xch_coins[0]
301+
funding_coin = select_coins_response.coins[0]
300302
assert funding_coin.amount >= required_amount
301-
funding_coin_dict = xch_coins[0].to_json_dict()
302303
next_coin = funding_coin
303304
did_coin = (
304305
await env_0.rpc_client.select_coins(
305-
amount=1,
306-
coin_selection_config=wallet_environments.tx_config.coin_selection_config,
307-
wallet_id=env_0.wallet_aliases["did"],
306+
SelectCoins.from_coin_selection_config(
307+
amount=uint64(1),
308+
coin_selection_config=wallet_environments.tx_config.coin_selection_config,
309+
wallet_id=uint32(env_0.wallet_aliases["did"]),
310+
)
308311
)
309-
)[0]
312+
).coins[0]
310313
did_lineage_parent: Optional[bytes32] = None
311314
txs: list[TransactionRecord] = []
312315
nft_ids = set()
@@ -321,7 +324,7 @@ async def test_nft_mint_rpc(wallet_environments: WalletTestFramework, zero_royal
321324
mint_number_start=uint16(i + 1),
322325
mint_total=uint16(n),
323326
xch_coins=[next_coin],
324-
xch_change_target=funding_coin_dict["puzzle_hash"],
327+
xch_change_target=funding_coin.puzzle_hash.hex(),
325328
did_coin=did_coin if with_did else None,
326329
did_lineage_parent=did_lineage_parent if with_did else None,
327330
mint_from_did=with_did,

chia/_tests/wallet/rpc/test_wallet_rpc.py

Lines changed: 83 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@
141141
PushTransactions,
142142
PushTX,
143143
RoyaltyAsset,
144+
SelectCoins,
144145
SendTransaction,
145146
SetWalletResyncOnStartup,
146147
SpendClawbackCoins,
@@ -645,10 +646,12 @@ async def test_create_signed_transaction(
645646

646647
selected_coin = None
647648
if select_coin:
648-
selected_coin = await wallet_1_rpc.select_coins(
649-
amount=amount_total, wallet_id=wallet_id, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
649+
select_coins_response = await wallet_1_rpc.select_coins(
650+
SelectCoins.from_coin_selection_config(
651+
amount=amount_total, wallet_id=uint32(wallet_id), coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
652+
)
650653
)
651-
assert len(selected_coin) == 1
654+
assert len(select_coins_response.coins) == 1
652655

653656
txs = (
654657
await wallet_1_rpc.create_signed_transactions(
@@ -784,38 +787,42 @@ async def test_create_signed_transaction_with_excluded_coins(wallet_rpc_environm
784787
await generate_funds(full_node_api, env.wallet_1)
785788

786789
async def it_does_not_include_the_excluded_coins() -> None:
787-
selected_coins = await wallet_1_rpc.select_coins(
788-
amount=250000000000, wallet_id=1, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
790+
select_coins_response = await wallet_1_rpc.select_coins(
791+
SelectCoins.from_coin_selection_config(
792+
amount=uint64(250000000000), wallet_id=uint32(1), coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
793+
)
789794
)
790-
assert len(selected_coins) == 1
795+
assert len(select_coins_response.coins) == 1
791796
outputs = await create_tx_outputs(wallet_1, [(uint64(250000000000), None)])
792797

793798
tx = (
794799
await wallet_1_rpc.create_signed_transactions(
795800
outputs,
796801
DEFAULT_TX_CONFIG.override(
797-
excluded_coin_ids=[c.name() for c in selected_coins],
802+
excluded_coin_ids=[c.name() for c in select_coins_response.coins],
798803
),
799804
)
800805
).signed_tx
801806

802807
assert len(tx.removals) == 1
803-
assert tx.removals[0] != selected_coins[0]
808+
assert tx.removals[0] != select_coins_response.coins[0]
804809
assert tx.removals[0].amount == uint64(1750000000000)
805810
await assert_push_tx_error(full_node_rpc, tx)
806811

807812
async def it_throws_an_error_when_all_spendable_coins_are_excluded() -> None:
808-
selected_coins = await wallet_1_rpc.select_coins(
809-
amount=1750000000000, wallet_id=1, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
813+
select_coins_response = await wallet_1_rpc.select_coins(
814+
SelectCoins.from_coin_selection_config(
815+
amount=uint64(1750000000000), wallet_id=uint32(1), coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
816+
)
810817
)
811-
assert len(selected_coins) == 1
818+
assert len(select_coins_response.coins) == 1
812819
outputs = await create_tx_outputs(wallet_1, [(uint64(1750000000000), None)])
813820

814821
with pytest.raises(ValueError):
815822
await wallet_1_rpc.create_signed_transactions(
816823
outputs,
817824
DEFAULT_TX_CONFIG.override(
818-
excluded_coin_ids=[c.name() for c in selected_coins],
825+
excluded_coin_ids=[c.name() for c in select_coins_response.coins],
819826
),
820827
)
821828

@@ -960,8 +967,10 @@ async def test_send_transaction_multi(wallet_rpc_environment: WalletRpcTestEnvir
960967

961968
generated_funds = await generate_funds(full_node_api, env.wallet_1)
962969

963-
removals = await client.select_coins(
964-
1750000000000, wallet_id=1, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
970+
select_coins_response = await client.select_coins(
971+
SelectCoins.from_coin_selection_config(
972+
amount=uint64(1750000000000), wallet_id=uint32(1), coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
973+
)
965974
) # we want a coin that won't be selected by default
966975
outputs = await create_tx_outputs(wallet_2, [(uint64(1), ["memo_1"]), (uint64(2), ["memo_2"])])
967976
amount_outputs = sum(output["amount"] for output in outputs)
@@ -972,7 +981,7 @@ async def test_send_transaction_multi(wallet_rpc_environment: WalletRpcTestEnvir
972981
1,
973982
outputs,
974983
DEFAULT_TX_CONFIG,
975-
coins=removals,
984+
coins=select_coins_response.coins,
976985
fee=amount_fee,
977986
)
978987
).transaction
@@ -981,7 +990,7 @@ async def test_send_transaction_multi(wallet_rpc_environment: WalletRpcTestEnvir
981990
assert send_tx_res is not None
982991

983992
assert_tx_amounts(send_tx_res, outputs, amount_fee=amount_fee, change_expected=True)
984-
assert send_tx_res.removals == removals
993+
assert send_tx_res.removals == select_coins_response.coins
985994

986995
await farm_transaction(full_node_api, wallet_node, spend_bundle)
987996

@@ -1355,8 +1364,12 @@ async def test_cat_endpoints(wallet_environments: WalletTestFramework, wallet_ty
13551364
await wallet_environments.process_pending_states(cat_spend_changes)
13561365

13571366
# Test CAT spend with a fee and pre-specified removals / coins
1358-
removals = await env_0.rpc_client.select_coins(
1359-
amount=uint64(2), wallet_id=cat_0_id, coin_selection_config=wallet_environments.tx_config.coin_selection_config
1367+
select_coins_response = await env_0.rpc_client.select_coins(
1368+
SelectCoins.from_coin_selection_config(
1369+
amount=uint64(2),
1370+
wallet_id=cat_0_id,
1371+
coin_selection_config=wallet_environments.tx_config.coin_selection_config,
1372+
)
13601373
)
13611374
tx_res = await env_0.rpc_client.cat_spend(
13621375
cat_0_id,
@@ -1365,12 +1378,12 @@ async def test_cat_endpoints(wallet_environments: WalletTestFramework, wallet_ty
13651378
addr_1,
13661379
uint64(5_000_000),
13671380
["the cat memo"],
1368-
removals=removals,
1381+
removals=select_coins_response.coins,
13691382
)
13701383

13711384
spend_bundle = tx_res.transaction.spend_bundle
13721385
assert spend_bundle is not None
1373-
assert removals[0] in {removal for tx in tx_res.transactions for removal in tx.removals}
1386+
assert select_coins_response.coins[0] in {removal for tx in tx_res.transactions for removal in tx.removals}
13741387

13751388
await wallet_environments.process_pending_states(cat_spend_changes)
13761389

@@ -1382,10 +1395,14 @@ async def test_cat_endpoints(wallet_environments: WalletTestFramework, wallet_ty
13821395
assert len(cats) == 1
13831396

13841397
# Test CAT coin selection
1385-
selected_coins = await env_0.rpc_client.select_coins(
1386-
amount=1, wallet_id=cat_0_id, coin_selection_config=wallet_environments.tx_config.coin_selection_config
1398+
select_coins_response = await env_0.rpc_client.select_coins(
1399+
SelectCoins.from_coin_selection_config(
1400+
amount=uint64(1),
1401+
wallet_id=cat_0_id,
1402+
coin_selection_config=wallet_environments.tx_config.coin_selection_config,
1403+
)
13871404
)
1388-
assert len(selected_coins) > 0
1405+
assert len(select_coins_response.coins) > 0
13891406

13901407
# Test get_cat_list
13911408
cat_list = (await env_0.rpc_client.get_cat_list()).cat_list
@@ -2299,51 +2316,63 @@ async def test_select_coins_rpc(wallet_rpc_environment: WalletRpcTestEnvironment
22992316
await time_out_assert(20, get_confirmed_balance, funds, client, 1)
23002317

23012318
# test min coin amount
2302-
min_coins: list[Coin] = await client_2.select_coins(
2303-
amount=1000,
2304-
wallet_id=1,
2305-
coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(min_coin_amount=uint64(1001)),
2319+
min_coins_response = await client_2.select_coins(
2320+
SelectCoins.from_coin_selection_config(
2321+
amount=uint64(1000),
2322+
wallet_id=uint32(1),
2323+
coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(min_coin_amount=uint64(1001)),
2324+
)
23062325
)
2307-
assert len(min_coins) == 1
2308-
assert min_coins[0].amount == uint64(10_000)
2326+
assert len(min_coins_response.coins) == 1
2327+
assert min_coins_response.coins[0].amount == uint64(10_000)
23092328

23102329
# test max coin amount
2311-
max_coins: list[Coin] = await client_2.select_coins(
2312-
amount=2000,
2313-
wallet_id=1,
2314-
coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(
2315-
min_coin_amount=uint64(999), max_coin_amount=uint64(9999)
2316-
),
2330+
max_coins_reponse = await client_2.select_coins(
2331+
SelectCoins.from_coin_selection_config(
2332+
amount=uint64(2000),
2333+
wallet_id=uint32(1),
2334+
coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(
2335+
min_coin_amount=uint64(999), max_coin_amount=uint64(9999)
2336+
),
2337+
)
23172338
)
2318-
assert len(max_coins) == 2
2319-
assert max_coins[0].amount == uint64(1000)
2339+
assert len(max_coins_reponse.coins) == 2
2340+
assert max_coins_reponse.coins[0].amount == uint64(1000)
23202341

23212342
# test excluded coin amounts
23222343
non_1000_amt: int = sum(a for a in tx_amounts if a != 1000)
2323-
excluded_amt_coins: list[Coin] = await client_2.select_coins(
2324-
amount=non_1000_amt,
2325-
wallet_id=1,
2326-
coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(excluded_coin_amounts=[uint64(1000)]),
2344+
excluded_amt_coins_response = await client_2.select_coins(
2345+
SelectCoins.from_coin_selection_config(
2346+
amount=uint64(non_1000_amt),
2347+
wallet_id=uint32(1),
2348+
coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(excluded_coin_amounts=[uint64(1000)]),
2349+
)
23272350
)
2328-
assert len(excluded_amt_coins) == len([a for a in tx_amounts if a != 1000])
2329-
assert sum(c.amount for c in excluded_amt_coins) == non_1000_amt
2351+
assert len(excluded_amt_coins_response.coins) == len([a for a in tx_amounts if a != 1000])
2352+
assert sum(c.amount for c in excluded_amt_coins_response.coins) == non_1000_amt
23302353

23312354
# test excluded coins
23322355
with pytest.raises(ValueError):
23332356
await client_2.select_coins(
2334-
amount=5000,
2335-
wallet_id=1,
2357+
SelectCoins.from_coin_selection_config(
2358+
amount=uint64(5000),
2359+
wallet_id=uint32(1),
2360+
coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(
2361+
excluded_coin_ids=[c.name() for c in min_coins_response.coins]
2362+
),
2363+
)
2364+
)
2365+
excluded_test_response = await client_2.select_coins(
2366+
SelectCoins.from_coin_selection_config(
2367+
amount=uint64(1300),
2368+
wallet_id=uint32(1),
23362369
coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(
2337-
excluded_coin_ids=[c.name() for c in min_coins]
2370+
excluded_coin_ids=[c.name() for c in coin_300]
23382371
),
23392372
)
2340-
excluded_test = await client_2.select_coins(
2341-
amount=1300,
2342-
wallet_id=1,
2343-
coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(excluded_coin_ids=[c.name() for c in coin_300]),
23442373
)
2345-
assert len(excluded_test) == 2
2346-
for coin in excluded_test:
2374+
assert len(excluded_test_response.coins) == 2
2375+
for coin in excluded_test_response.coins:
23472376
assert coin != coin_300[0]
23482377

23492378
# test backwards compatibility in the RPC
@@ -2365,10 +2394,10 @@ async def test_select_coins_rpc(wallet_rpc_environment: WalletRpcTestEnvironment
23652394
all_coins, _, _ = await client_2.get_spendable_coins(
23662395
wallet_id=1,
23672396
coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(
2368-
excluded_coin_ids=[c.name() for c in excluded_amt_coins]
2397+
excluded_coin_ids=[c.name() for c in excluded_amt_coins_response.coins]
23692398
),
23702399
)
2371-
assert set(excluded_amt_coins).intersection({rec.coin for rec in all_coins}) == set()
2400+
assert set(excluded_amt_coins_response.coins).intersection({rec.coin for rec in all_coins}) == set()
23722401
all_coins, _, _ = await client_2.get_spendable_coins(
23732402
wallet_id=1,
23742403
coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(excluded_coin_amounts=[uint64(1000)]),

chia/wallet/util/tx_config.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from chia_rs import ConsensusConstants
77
from chia_rs.sized_bytes import bytes32
88
from chia_rs.sized_ints import uint64
9-
from typing_extensions import NotRequired, Self, TypedDict, Unpack
9+
from typing_extensions import NotRequired, Self, TypedDict, TypeVar, Unpack
1010

1111
from chia.consensus.default_constants import DEFAULT_CONSTANTS
1212
from chia.types.blockchain_format.coin import Coin
@@ -98,10 +98,14 @@ def from_json_dict(cls, json_dict: dict[str, Any]) -> Self:
9898
return super().from_json_dict(json_dict)
9999

100100
# This function is purely for ergonomics
101-
def override(self, **kwargs: Any) -> CoinSelectionConfigLoader:
101+
# But creates a small linting complication
102+
def override(self: _T_CoinSelectionConfigLoader, **kwargs: Any) -> _T_CoinSelectionConfigLoader: # noqa: PYI019
102103
return dataclasses.replace(self, **kwargs)
103104

104105

106+
_T_CoinSelectionConfigLoader = TypeVar("_T_CoinSelectionConfigLoader", bound=CoinSelectionConfigLoader)
107+
108+
105109
@streamable
106110
@dataclasses.dataclass(frozen=True)
107111
class TXConfigLoader(CoinSelectionConfigLoader):
@@ -138,10 +142,6 @@ def autofill(
138142
reuse_puzhash,
139143
)
140144

141-
# This function is purely for ergonomics
142-
def override(self, **kwargs: Any) -> TXConfigLoader:
143-
return dataclasses.replace(self, **kwargs)
144-
145145

146146
DEFAULT_COIN_SELECTION_CONFIG = CoinSelectionConfig(uint64(0), uint64(DEFAULT_CONSTANTS.MAX_COIN_AMOUNT), [], [])
147147
DEFAULT_TX_CONFIG = TXConfig(

0 commit comments

Comments
 (0)