Skip to content

Commit f3a84b1

Browse files
committed
Port spend_clawback_coins to @marshal
1 parent 5872b9c commit f3a84b1

File tree

6 files changed

+95
-83
lines changed

6 files changed

+95
-83
lines changed

chia/_tests/cmds/wallet/test_wallet.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161
RoyaltyAsset,
6262
SendTransaction,
6363
SendTransactionResponse,
64+
SpendClawbackCoins,
65+
SpendClawbackCoinsResponse,
6466
TakeOfferResponse,
6567
TransactionRecordWithMetadata,
6668
WalletInfoResponse,
@@ -533,18 +535,20 @@ def test_clawback(capsys: object, get_test_cli_clients: tuple[TestRpcClients, Pa
533535
class ClawbackWalletRpcClient(TestWalletRpcClient):
534536
async def spend_clawback_coins(
535537
self,
536-
coin_ids: list[bytes32],
537-
fee: int = 0,
538-
force: bool = False,
539-
push: bool = True,
538+
request: SpendClawbackCoins,
539+
tx_config: TXConfig,
540+
extra_conditions: tuple[Condition, ...] = tuple(),
540541
timelock_info: ConditionValidTimes = ConditionValidTimes(),
541-
) -> dict[str, Any]:
542-
self.add_to_log("spend_clawback_coins", (coin_ids, fee, force, push, timelock_info))
543-
tx_hex_list = [get_bytes32(6).hex(), get_bytes32(7).hex(), get_bytes32(8).hex()]
544-
return {
545-
"transaction_ids": tx_hex_list,
546-
"transactions": [STD_TX.to_json_dict()],
547-
}
542+
) -> SpendClawbackCoinsResponse:
543+
self.add_to_log(
544+
"spend_clawback_coins", (request.coin_ids, request.fee, request.force, request.push, timelock_info)
545+
)
546+
tx_list = [get_bytes32(6), get_bytes32(7), get_bytes32(8)]
547+
return SpendClawbackCoinsResponse(
548+
transaction_ids=tx_list,
549+
transactions=[STD_TX],
550+
unsigned_transactions=[STD_UTX],
551+
)
548552

549553
inst_rpc_client = ClawbackWalletRpcClient()
550554
test_rpc_clients.wallet_rpc_client = inst_rpc_client

chia/_tests/wallet/rpc/test_wallet_rpc.py

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@
139139
RoyaltyAsset,
140140
SendTransaction,
141141
SetWalletResyncOnStartup,
142+
SpendClawbackCoins,
142143
SplitCoins,
143144
VerifySignature,
144145
VerifySignatureResponse,
@@ -829,7 +830,6 @@ async def test_spend_clawback_coins(wallet_rpc_environment: WalletRpcTestEnviron
829830
wallet_1 = wallet_1_node.wallet_state_manager.main_wallet
830831
wallet_2 = wallet_2_node.wallet_state_manager.main_wallet
831832
full_node_api: FullNodeSimulator = env.full_node.api
832-
wallet_2_api = WalletRpcApi(wallet_2_node)
833833

834834
generated_funds = await generate_funds(full_node_api, env.wallet_1, 1)
835835
await generate_funds(full_node_api, env.wallet_2, 1)
@@ -872,41 +872,39 @@ async def test_spend_clawback_coins(wallet_rpc_environment: WalletRpcTestEnviron
872872
await time_out_assert(20, get_confirmed_balance, generated_funds - 500, wallet_1_rpc, 1)
873873
await time_out_assert(20, get_confirmed_balance, generated_funds - 500, wallet_2_rpc, 1)
874874
await asyncio.sleep(10)
875-
# Test missing coin_ids
876-
has_exception = False
877-
try:
878-
await wallet_2_api.spend_clawback_coins({})
879-
except ValueError:
880-
has_exception = True
881-
assert has_exception
882875
# Test coin ID is not a Clawback coin
883876
invalid_coin_id = tx.removals[0].name()
884-
resp = await wallet_2_rpc.spend_clawback_coins([invalid_coin_id], 500)
885-
assert resp["success"]
886-
assert resp["transaction_ids"] == []
877+
resp = await wallet_2_rpc.spend_clawback_coins(
878+
SpendClawbackCoins(coin_ids=[invalid_coin_id], fee=uint64(500), push=True), tx_config=DEFAULT_TX_CONFIG
879+
)
880+
assert resp.transaction_ids == []
887881
# Test unsupported wallet
888882
coin_record = await wallet_1_node.wallet_state_manager.coin_store.get_coin_record(clawback_coin_id_1)
889883
assert coin_record is not None
890884
await wallet_1_node.wallet_state_manager.coin_store.add_coin_record(
891885
dataclasses.replace(coin_record, wallet_type=WalletType.CAT)
892886
)
893-
resp = await wallet_1_rpc.spend_clawback_coins([clawback_coin_id_1], 100)
894-
assert resp["success"]
895-
assert len(resp["transaction_ids"]) == 0
887+
resp = await wallet_1_rpc.spend_clawback_coins(
888+
SpendClawbackCoins(coin_ids=[clawback_coin_id_1], fee=uint64(100), push=True), tx_config=DEFAULT_TX_CONFIG
889+
)
890+
assert len(resp.transaction_ids) == 0
896891
# Test missing metadata
897892
await wallet_1_node.wallet_state_manager.coin_store.add_coin_record(dataclasses.replace(coin_record, metadata=None))
898-
resp = await wallet_1_rpc.spend_clawback_coins([clawback_coin_id_1], 100)
899-
assert resp["success"]
900-
assert len(resp["transaction_ids"]) == 0
893+
resp = await wallet_1_rpc.spend_clawback_coins(
894+
SpendClawbackCoins(coin_ids=[clawback_coin_id_1], fee=uint64(100), push=True), tx_config=DEFAULT_TX_CONFIG
895+
)
896+
assert len(resp.transaction_ids) == 0
901897
# Test missing incoming tx
902898
coin_record = await wallet_1_node.wallet_state_manager.coin_store.get_coin_record(clawback_coin_id_2)
903899
assert coin_record is not None
904900
fake_coin = Coin(coin_record.coin.parent_coin_info, wallet_2_puzhash, coin_record.coin.amount)
905901
await wallet_1_node.wallet_state_manager.coin_store.add_coin_record(
906902
dataclasses.replace(coin_record, coin=fake_coin)
907903
)
908-
resp = await wallet_1_rpc.spend_clawback_coins([fake_coin.name()], 100)
909-
assert resp["transaction_ids"] == []
904+
resp = await wallet_1_rpc.spend_clawback_coins(
905+
SpendClawbackCoins(coin_ids=[fake_coin.name()], fee=uint64(100), push=True), tx_config=DEFAULT_TX_CONFIG
906+
)
907+
assert resp.transaction_ids == []
910908
# Test coin puzzle hash doesn't match the puzzle
911909
farmed_tx = (await wallet_1.wallet_state_manager.tx_store.get_farming_rewards())[0]
912910
await wallet_1.wallet_state_manager.tx_store.add_transaction_record(
@@ -915,8 +913,10 @@ async def test_spend_clawback_coins(wallet_rpc_environment: WalletRpcTestEnviron
915913
await wallet_1_node.wallet_state_manager.coin_store.add_coin_record(
916914
dataclasses.replace(coin_record, coin=fake_coin)
917915
)
918-
resp = await wallet_1_rpc.spend_clawback_coins([fake_coin.name()], 100)
919-
assert resp["transaction_ids"] == []
916+
resp = await wallet_1_rpc.spend_clawback_coins(
917+
SpendClawbackCoins(coin_ids=[fake_coin.name()], fee=uint64(100), push=True), tx_config=DEFAULT_TX_CONFIG
918+
)
919+
assert resp.transaction_ids == []
920920
# Test claim spend
921921
await wallet_2_rpc.set_auto_claim(
922922
AutoClaimSettings(
@@ -926,21 +926,23 @@ async def test_spend_clawback_coins(wallet_rpc_environment: WalletRpcTestEnviron
926926
batch_size=uint16(1),
927927
)
928928
)
929-
resp = await wallet_2_rpc.spend_clawback_coins([clawback_coin_id_1, clawback_coin_id_2], 100)
930-
assert resp["success"]
931-
assert len(resp["transaction_ids"]) == 2
932-
for _tx in resp["transactions"]:
933-
clawback_tx = TransactionRecord.from_json_dict(_tx)
929+
resp = await wallet_2_rpc.spend_clawback_coins(
930+
SpendClawbackCoins(coin_ids=[clawback_coin_id_1, clawback_coin_id_2], fee=uint64(100), push=True),
931+
tx_config=DEFAULT_TX_CONFIG,
932+
)
933+
assert len(resp.transaction_ids) == 2
934+
for clawback_tx in resp.transactions:
934935
if clawback_tx.spend_bundle is not None:
935936
await time_out_assert_not_none(
936937
10, full_node_api.full_node.mempool_manager.get_spendbundle, clawback_tx.spend_bundle.name()
937938
)
938939
await farm_transaction_block(full_node_api, wallet_2_node)
939940
await time_out_assert(20, get_confirmed_balance, generated_funds + 300, wallet_2_rpc, 1)
940941
# Test spent coin
941-
resp = await wallet_2_rpc.spend_clawback_coins([clawback_coin_id_1], 500)
942-
assert resp["success"]
943-
assert resp["transaction_ids"] == []
942+
resp = await wallet_2_rpc.spend_clawback_coins(
943+
SpendClawbackCoins(coin_ids=[clawback_coin_id_1], fee=uint64(500), push=True), tx_config=DEFAULT_TX_CONFIG
944+
)
945+
assert resp.transaction_ids == []
944946

945947

946948
@pytest.mark.anyio
@@ -2855,12 +2857,11 @@ async def test_set_wallet_resync_on_startup(wallet_rpc_environment: WalletRpcTes
28552857
await farm_transaction(full_node_api, wallet_node, tx.spend_bundle)
28562858
await time_out_assert(20, check_client_synced, True, wc)
28572859
await asyncio.sleep(10)
2858-
resp = await wc.spend_clawback_coins([clawback_coin_id], 0)
2859-
assert resp["success"]
2860-
assert len(resp["transaction_ids"]) == 1
2861-
await time_out_assert_not_none(
2862-
10, full_node_api.full_node.mempool_manager.get_spendbundle, bytes32.from_hexstr(resp["transaction_ids"][0])
2860+
resp = await wc.spend_clawback_coins(
2861+
SpendClawbackCoins(coin_ids=[clawback_coin_id], fee=uint64(0), push=True), tx_config=DEFAULT_TX_CONFIG
28632862
)
2863+
assert len(resp.transaction_ids) == 1
2864+
await time_out_assert_not_none(10, full_node_api.full_node.mempool_manager.get_spendbundle, resp.transaction_ids[0])
28642865
await farm_transaction_block(full_node_api, wallet_node)
28652866
await time_out_assert(20, check_client_synced, True, wc)
28662867
wallet_node_2._close()

chia/cmds/wallet_funcs.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
from chia.wallet.util.puzzle_decorator_type import PuzzleDecoratorType
4141
from chia.wallet.util.query_filter import HashFilter, TransactionTypeFilter
4242
from chia.wallet.util.transaction_type import CLAWBACK_INCOMING_TRANSACTION_TYPES, TransactionType
43+
from chia.wallet.util.tx_config import DEFAULT_TX_CONFIG
4344
from chia.wallet.util.wallet_types import WalletType
4445
from chia.wallet.vc_wallet.vc_store import VCProofs
4546
from chia.wallet.wallet_coin_store import GetCoinRecords
@@ -71,6 +72,7 @@
7172
RoyaltyAsset,
7273
SendTransaction,
7374
SendTransactionResponse,
75+
SpendClawbackCoins,
7476
VCAddProofs,
7577
VCGet,
7678
VCGetList,
@@ -1673,14 +1675,12 @@ async def spend_clawback(
16731675
print("Batch fee cannot be negative.")
16741676
return []
16751677
response = await wallet_client.spend_clawback_coins(
1676-
tx_ids,
1677-
fee,
1678-
force,
1679-
push=push,
1678+
SpendClawbackCoins(coin_ids=tx_ids, fee=fee, force=force, push=push),
1679+
tx_config=DEFAULT_TX_CONFIG,
16801680
timelock_info=condition_valid_times,
16811681
)
16821682
print(str(response))
1683-
return [TransactionRecord.from_json_dict(tx) for tx in response["transactions"]]
1683+
return response.transactions
16841684

16851685

16861686
async def mint_vc(

chia/wallet/wallet_request_types.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,6 +1051,20 @@ class SendTransactionResponse(TransactionEndpointResponse):
10511051
transaction_id: bytes32
10521052

10531053

1054+
@streamable
1055+
@dataclass(frozen=True)
1056+
class SpendClawbackCoins(TransactionEndpointRequest):
1057+
coin_ids: list[bytes32] = field(default_factory=default_raise)
1058+
batch_size: Optional[uint16] = None
1059+
force: bool = False
1060+
1061+
1062+
@streamable
1063+
@dataclass(frozen=True)
1064+
class SpendClawbackCoinsResponse(TransactionEndpointResponse):
1065+
transaction_ids: list[bytes32]
1066+
1067+
10541068
@streamable
10551069
@dataclass(frozen=True)
10561070
class PushTransactions(TransactionEndpointRequest):

chia/wallet/wallet_rpc_api.py

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@
236236
SendTransaction,
237237
SendTransactionResponse,
238238
SetWalletResyncOnStartup,
239+
SpendClawbackCoins,
240+
SpendClawbackCoinsResponse,
239241
SplitCoins,
240242
SplitCoinsResponse,
241243
SubmitTransactions,
@@ -1647,34 +1649,33 @@ async def send_transaction_multi(self, request: dict[str, Any]) -> EndpointResul
16471649
}
16481650

16491651
@tx_endpoint(push=True, merge_spends=False)
1652+
@marshal
16501653
async def spend_clawback_coins(
16511654
self,
1652-
request: dict[str, Any],
1655+
request: SpendClawbackCoins,
16531656
action_scope: WalletActionScope,
16541657
extra_conditions: tuple[Condition, ...] = tuple(),
1655-
) -> EndpointResult:
1658+
) -> SpendClawbackCoinsResponse:
16561659
"""Spend clawback coins that were sent (to claw them back) or received (to claim them).
16571660
16581661
:param coin_ids: list of coin ids to be spent
16591662
:param batch_size: number of coins to spend per bundle
16601663
:param fee: transaction fee in mojos
16611664
:return:
16621665
"""
1663-
if "coin_ids" not in request:
1664-
raise ValueError("Coin IDs are required.")
1665-
coin_ids: list[bytes32] = [bytes32.from_hexstr(coin) for coin in request["coin_ids"]]
1666-
tx_fee: uint64 = uint64(request.get("fee", 0))
16671666
# Get inner puzzle
16681667
coin_records = await self.service.wallet_state_manager.coin_store.get_coin_records(
1669-
coin_id_filter=HashFilter.include(coin_ids),
1668+
coin_id_filter=HashFilter.include(request.coin_ids),
16701669
coin_type=CoinType.CLAWBACK,
16711670
wallet_type=WalletType.STANDARD_WALLET,
16721671
spent_range=UInt32Range(stop=uint32(0)),
16731672
)
16741673

16751674
coins: dict[Coin, ClawbackMetadata] = {}
1676-
batch_size = request.get(
1677-
"batch_size", self.service.wallet_state_manager.config.get("auto_claim", {}).get("batch_size", 50)
1675+
batch_size = (
1676+
request.batch_size
1677+
if request.batch_size is not None
1678+
else self.service.wallet_state_manager.config.get("auto_claim", {}).get("batch_size", 50)
16781679
)
16791680
for coin_id, coin_record in coin_records.coin_id_to_record.items():
16801681
try:
@@ -1684,9 +1685,9 @@ async def spend_clawback_coins(
16841685
if len(coins) >= batch_size:
16851686
await self.service.wallet_state_manager.spend_clawback_coins(
16861687
coins,
1687-
tx_fee,
1688+
request.fee,
16881689
action_scope,
1689-
request.get("force", False),
1690+
request.force,
16901691
extra_conditions=extra_conditions,
16911692
)
16921693
coins = {}
@@ -1695,17 +1696,14 @@ async def spend_clawback_coins(
16951696
if len(coins) > 0:
16961697
await self.service.wallet_state_manager.spend_clawback_coins(
16971698
coins,
1698-
tx_fee,
1699+
request.fee,
16991700
action_scope,
1700-
request.get("force", False),
1701+
request.force,
17011702
extra_conditions=extra_conditions,
17021703
)
17031704

1704-
return {
1705-
"success": True,
1706-
"transaction_ids": None, # tx_endpoint wrapper will take care of this
1707-
"transactions": None, # tx_endpoint wrapper will take care of this
1708-
}
1705+
# tx_endpoint will fill in the default values here
1706+
return SpendClawbackCoinsResponse([], [], transaction_ids=[])
17091707

17101708
async def delete_unconfirmed_transactions(self, request: dict[str, Any]) -> EndpointResult:
17111709
wallet_id = uint32(request["wallet_id"])

chia/wallet/wallet_rpc_client.py

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@
154154
SendTransactionMultiResponse,
155155
SendTransactionResponse,
156156
SetWalletResyncOnStartup,
157+
SpendClawbackCoins,
158+
SpendClawbackCoinsResponse,
157159
SplitCoins,
158160
SplitCoinsResponse,
159161
SubmitTransactions,
@@ -340,23 +342,16 @@ async def send_transaction_multi(
340342

341343
async def spend_clawback_coins(
342344
self,
343-
coin_ids: list[bytes32],
344-
fee: int = 0,
345-
force: bool = False,
346-
push: bool = True,
345+
request: SpendClawbackCoins,
346+
tx_config: TXConfig,
347347
extra_conditions: tuple[Condition, ...] = tuple(),
348348
timelock_info: ConditionValidTimes = ConditionValidTimes(),
349-
) -> dict[str, Any]:
350-
request = {
351-
"coin_ids": [cid.hex() for cid in coin_ids],
352-
"fee": fee,
353-
"force": force,
354-
"extra_conditions": conditions_to_json_dicts(extra_conditions),
355-
"push": push,
356-
**timelock_info.to_json_dict(),
357-
}
358-
response = await self.fetch("spend_clawback_coins", request)
359-
return response
349+
) -> SpendClawbackCoinsResponse:
350+
return SpendClawbackCoinsResponse.from_json_dict(
351+
await self.fetch(
352+
"spend_clawback_coins", request.json_serialize_for_transport(tx_config, extra_conditions, timelock_info)
353+
)
354+
)
360355

361356
async def delete_unconfirmed_transactions(self, wallet_id: int) -> None:
362357
await self.fetch("delete_unconfirmed_transactions", {"wallet_id": wallet_id})

0 commit comments

Comments
 (0)