Skip to content

Commit 257ee14

Browse files
committed
Port spend_clawback_coins to @marshal
1 parent 11696e4 commit 257ee14

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
@@ -67,6 +67,8 @@
6767
RoyaltyAsset,
6868
SendTransaction,
6969
SendTransactionResponse,
70+
SpendClawbackCoins,
71+
SpendClawbackCoinsResponse,
7072
TakeOfferResponse,
7173
TransactionRecordWithMetadata,
7274
WalletInfoResponse,
@@ -539,18 +541,20 @@ def test_clawback(capsys: object, get_test_cli_clients: tuple[TestRpcClients, Pa
539541
class ClawbackWalletRpcClient(TestWalletRpcClient):
540542
async def spend_clawback_coins(
541543
self,
542-
coin_ids: list[bytes32],
543-
fee: int = 0,
544-
force: bool = False,
545-
push: bool = True,
544+
request: SpendClawbackCoins,
545+
tx_config: TXConfig,
546+
extra_conditions: tuple[Condition, ...] = tuple(),
546547
timelock_info: ConditionValidTimes = ConditionValidTimes(),
547-
) -> dict[str, Any]:
548-
self.add_to_log("spend_clawback_coins", (coin_ids, fee, force, push, timelock_info))
549-
tx_hex_list = [get_bytes32(6).hex(), get_bytes32(7).hex(), get_bytes32(8).hex()]
550-
return {
551-
"transaction_ids": tx_hex_list,
552-
"transactions": [STD_TX.to_json_dict()],
553-
}
548+
) -> SpendClawbackCoinsResponse:
549+
self.add_to_log(
550+
"spend_clawback_coins", (request.coin_ids, request.fee, request.force, request.push, timelock_info)
551+
)
552+
tx_list = [get_bytes32(6), get_bytes32(7), get_bytes32(8)]
553+
return SpendClawbackCoinsResponse(
554+
transaction_ids=tx_list,
555+
transactions=[STD_TX],
556+
unsigned_transactions=[STD_UTX],
557+
)
554558

555559
inst_rpc_client = ClawbackWalletRpcClient()
556560
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
@@ -143,6 +143,7 @@
143143
RoyaltyAsset,
144144
SendTransaction,
145145
SetWalletResyncOnStartup,
146+
SpendClawbackCoins,
146147
SplitCoins,
147148
VerifySignature,
148149
VerifySignatureResponse,
@@ -833,7 +834,6 @@ async def test_spend_clawback_coins(wallet_rpc_environment: WalletRpcTestEnviron
833834
wallet_1 = wallet_1_node.wallet_state_manager.main_wallet
834835
wallet_2 = wallet_2_node.wallet_state_manager.main_wallet
835836
full_node_api: FullNodeSimulator = env.full_node.api
836-
wallet_2_api = WalletRpcApi(wallet_2_node)
837837

838838
generated_funds = await generate_funds(full_node_api, env.wallet_1, 1)
839839
await generate_funds(full_node_api, env.wallet_2, 1)
@@ -876,41 +876,39 @@ async def test_spend_clawback_coins(wallet_rpc_environment: WalletRpcTestEnviron
876876
await time_out_assert(20, get_confirmed_balance, generated_funds - 500, wallet_1_rpc, 1)
877877
await time_out_assert(20, get_confirmed_balance, generated_funds - 500, wallet_2_rpc, 1)
878878
await asyncio.sleep(10)
879-
# Test missing coin_ids
880-
has_exception = False
881-
try:
882-
await wallet_2_api.spend_clawback_coins({})
883-
except ValueError:
884-
has_exception = True
885-
assert has_exception
886879
# Test coin ID is not a Clawback coin
887880
invalid_coin_id = tx.removals[0].name()
888-
resp = await wallet_2_rpc.spend_clawback_coins([invalid_coin_id], 500)
889-
assert resp["success"]
890-
assert resp["transaction_ids"] == []
881+
resp = await wallet_2_rpc.spend_clawback_coins(
882+
SpendClawbackCoins(coin_ids=[invalid_coin_id], fee=uint64(500), push=True), tx_config=DEFAULT_TX_CONFIG
883+
)
884+
assert resp.transaction_ids == []
891885
# Test unsupported wallet
892886
coin_record = await wallet_1_node.wallet_state_manager.coin_store.get_coin_record(clawback_coin_id_1)
893887
assert coin_record is not None
894888
await wallet_1_node.wallet_state_manager.coin_store.add_coin_record(
895889
dataclasses.replace(coin_record, wallet_type=WalletType.CAT)
896890
)
897-
resp = await wallet_1_rpc.spend_clawback_coins([clawback_coin_id_1], 100)
898-
assert resp["success"]
899-
assert len(resp["transaction_ids"]) == 0
891+
resp = await wallet_1_rpc.spend_clawback_coins(
892+
SpendClawbackCoins(coin_ids=[clawback_coin_id_1], fee=uint64(100), push=True), tx_config=DEFAULT_TX_CONFIG
893+
)
894+
assert len(resp.transaction_ids) == 0
900895
# Test missing metadata
901896
await wallet_1_node.wallet_state_manager.coin_store.add_coin_record(dataclasses.replace(coin_record, metadata=None))
902-
resp = await wallet_1_rpc.spend_clawback_coins([clawback_coin_id_1], 100)
903-
assert resp["success"]
904-
assert len(resp["transaction_ids"]) == 0
897+
resp = await wallet_1_rpc.spend_clawback_coins(
898+
SpendClawbackCoins(coin_ids=[clawback_coin_id_1], fee=uint64(100), push=True), tx_config=DEFAULT_TX_CONFIG
899+
)
900+
assert len(resp.transaction_ids) == 0
905901
# Test missing incoming tx
906902
coin_record = await wallet_1_node.wallet_state_manager.coin_store.get_coin_record(clawback_coin_id_2)
907903
assert coin_record is not None
908904
fake_coin = Coin(coin_record.coin.parent_coin_info, wallet_2_puzhash, coin_record.coin.amount)
909905
await wallet_1_node.wallet_state_manager.coin_store.add_coin_record(
910906
dataclasses.replace(coin_record, coin=fake_coin)
911907
)
912-
resp = await wallet_1_rpc.spend_clawback_coins([fake_coin.name()], 100)
913-
assert resp["transaction_ids"] == []
908+
resp = await wallet_1_rpc.spend_clawback_coins(
909+
SpendClawbackCoins(coin_ids=[fake_coin.name()], fee=uint64(100), push=True), tx_config=DEFAULT_TX_CONFIG
910+
)
911+
assert resp.transaction_ids == []
914912
# Test coin puzzle hash doesn't match the puzzle
915913
farmed_tx = (await wallet_1.wallet_state_manager.tx_store.get_farming_rewards())[0]
916914
await wallet_1.wallet_state_manager.tx_store.add_transaction_record(
@@ -919,8 +917,10 @@ async def test_spend_clawback_coins(wallet_rpc_environment: WalletRpcTestEnviron
919917
await wallet_1_node.wallet_state_manager.coin_store.add_coin_record(
920918
dataclasses.replace(coin_record, coin=fake_coin)
921919
)
922-
resp = await wallet_1_rpc.spend_clawback_coins([fake_coin.name()], 100)
923-
assert resp["transaction_ids"] == []
920+
resp = await wallet_1_rpc.spend_clawback_coins(
921+
SpendClawbackCoins(coin_ids=[fake_coin.name()], fee=uint64(100), push=True), tx_config=DEFAULT_TX_CONFIG
922+
)
923+
assert resp.transaction_ids == []
924924
# Test claim spend
925925
await wallet_2_rpc.set_auto_claim(
926926
AutoClaimSettings(
@@ -930,21 +930,23 @@ async def test_spend_clawback_coins(wallet_rpc_environment: WalletRpcTestEnviron
930930
batch_size=uint16(1),
931931
)
932932
)
933-
resp = await wallet_2_rpc.spend_clawback_coins([clawback_coin_id_1, clawback_coin_id_2], 100)
934-
assert resp["success"]
935-
assert len(resp["transaction_ids"]) == 2
936-
for _tx in resp["transactions"]:
937-
clawback_tx = TransactionRecord.from_json_dict(_tx)
933+
resp = await wallet_2_rpc.spend_clawback_coins(
934+
SpendClawbackCoins(coin_ids=[clawback_coin_id_1, clawback_coin_id_2], fee=uint64(100), push=True),
935+
tx_config=DEFAULT_TX_CONFIG,
936+
)
937+
assert len(resp.transaction_ids) == 2
938+
for clawback_tx in resp.transactions:
938939
if clawback_tx.spend_bundle is not None:
939940
await time_out_assert_not_none(
940941
10, full_node_api.full_node.mempool_manager.get_spendbundle, clawback_tx.spend_bundle.name()
941942
)
942943
await farm_transaction_block(full_node_api, wallet_2_node)
943944
await time_out_assert(20, get_confirmed_balance, generated_funds + 300, wallet_2_rpc, 1)
944945
# Test spent coin
945-
resp = await wallet_2_rpc.spend_clawback_coins([clawback_coin_id_1], 500)
946-
assert resp["success"]
947-
assert resp["transaction_ids"] == []
946+
resp = await wallet_2_rpc.spend_clawback_coins(
947+
SpendClawbackCoins(coin_ids=[clawback_coin_id_1], fee=uint64(500), push=True), tx_config=DEFAULT_TX_CONFIG
948+
)
949+
assert resp.transaction_ids == []
948950

949951

950952
@pytest.mark.anyio
@@ -2861,12 +2863,11 @@ async def test_set_wallet_resync_on_startup(wallet_rpc_environment: WalletRpcTes
28612863
await farm_transaction(full_node_api, wallet_node, tx.spend_bundle)
28622864
await time_out_assert(20, check_client_synced, True, wc)
28632865
await asyncio.sleep(10)
2864-
resp = await wc.spend_clawback_coins([clawback_coin_id], 0)
2865-
assert resp["success"]
2866-
assert len(resp["transaction_ids"]) == 1
2867-
await time_out_assert_not_none(
2868-
10, full_node_api.full_node.mempool_manager.get_spendbundle, bytes32.from_hexstr(resp["transaction_ids"][0])
2866+
resp = await wc.spend_clawback_coins(
2867+
SpendClawbackCoins(coin_ids=[clawback_coin_id], fee=uint64(0), push=True), tx_config=DEFAULT_TX_CONFIG
28692868
)
2869+
assert len(resp.transaction_ids) == 1
2870+
await time_out_assert_not_none(10, full_node_api.full_node.mempool_manager.get_spendbundle, resp.transaction_ids[0])
28702871
await farm_transaction_block(full_node_api, wallet_node)
28712872
await time_out_assert(20, check_client_synced, True, wc)
28722873
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
@@ -79,6 +80,7 @@
7980
SignMessageByAddressResponse,
8081
SignMessageByID,
8182
SignMessageByIDResponse,
83+
SpendClawbackCoins,
8284
VCAddProofs,
8385
VCGet,
8486
VCGetList,
@@ -1684,14 +1686,12 @@ async def spend_clawback(
16841686
print("Batch fee cannot be negative.")
16851687
return []
16861688
response = await wallet_client.spend_clawback_coins(
1687-
tx_ids,
1688-
fee,
1689-
force,
1690-
push=push,
1689+
SpendClawbackCoins(coin_ids=tx_ids, fee=fee, force=force, push=push),
1690+
tx_config=DEFAULT_TX_CONFIG,
16911691
timelock_info=condition_valid_times,
16921692
)
16931693
print(str(response))
1694-
return [TransactionRecord.from_json_dict(tx) for tx in response["transactions"]]
1694+
return response.transactions
16951695

16961696

16971697
async def mint_vc(

chia/wallet/wallet_request_types.py

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

11481148

1149+
@streamable
1150+
@dataclass(frozen=True)
1151+
class SpendClawbackCoins(TransactionEndpointRequest):
1152+
coin_ids: list[bytes32] = field(default_factory=default_raise)
1153+
batch_size: Optional[uint16] = None
1154+
force: bool = False
1155+
1156+
1157+
@streamable
1158+
@dataclass(frozen=True)
1159+
class SpendClawbackCoinsResponse(TransactionEndpointResponse):
1160+
transaction_ids: list[bytes32]
1161+
1162+
11491163
@streamable
11501164
@dataclass(frozen=True)
11511165
class PushTransactions(TransactionEndpointRequest):

chia/wallet/wallet_rpc_api.py

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,8 @@
249249
SignMessageByAddressResponse,
250250
SignMessageByID,
251251
SignMessageByIDResponse,
252+
SpendClawbackCoins,
253+
SpendClawbackCoinsResponse,
252254
SplitCoins,
253255
SplitCoinsResponse,
254256
SubmitTransactions,
@@ -1655,34 +1657,33 @@ async def send_transaction_multi(self, request: dict[str, Any]) -> EndpointResul
16551657
}
16561658

16571659
@tx_endpoint(push=True, merge_spends=False)
1660+
@marshal
16581661
async def spend_clawback_coins(
16591662
self,
1660-
request: dict[str, Any],
1663+
request: SpendClawbackCoins,
16611664
action_scope: WalletActionScope,
16621665
extra_conditions: tuple[Condition, ...] = tuple(),
1663-
) -> EndpointResult:
1666+
) -> SpendClawbackCoinsResponse:
16641667
"""Spend clawback coins that were sent (to claw them back) or received (to claim them).
16651668
16661669
:param coin_ids: list of coin ids to be spent
16671670
:param batch_size: number of coins to spend per bundle
16681671
:param fee: transaction fee in mojos
16691672
:return:
16701673
"""
1671-
if "coin_ids" not in request:
1672-
raise ValueError("Coin IDs are required.")
1673-
coin_ids: list[bytes32] = [bytes32.from_hexstr(coin) for coin in request["coin_ids"]]
1674-
tx_fee: uint64 = uint64(request.get("fee", 0))
16751674
# Get inner puzzle
16761675
coin_records = await self.service.wallet_state_manager.coin_store.get_coin_records(
1677-
coin_id_filter=HashFilter.include(coin_ids),
1676+
coin_id_filter=HashFilter.include(request.coin_ids),
16781677
coin_type=CoinType.CLAWBACK,
16791678
wallet_type=WalletType.STANDARD_WALLET,
16801679
spent_range=UInt32Range(stop=uint32(0)),
16811680
)
16821681

16831682
coins: dict[Coin, ClawbackMetadata] = {}
1684-
batch_size = request.get(
1685-
"batch_size", self.service.wallet_state_manager.config.get("auto_claim", {}).get("batch_size", 50)
1683+
batch_size = (
1684+
request.batch_size
1685+
if request.batch_size is not None
1686+
else self.service.wallet_state_manager.config.get("auto_claim", {}).get("batch_size", 50)
16861687
)
16871688
for coin_id, coin_record in coin_records.coin_id_to_record.items():
16881689
try:
@@ -1692,9 +1693,9 @@ async def spend_clawback_coins(
16921693
if len(coins) >= batch_size:
16931694
await self.service.wallet_state_manager.spend_clawback_coins(
16941695
coins,
1695-
tx_fee,
1696+
request.fee,
16961697
action_scope,
1697-
request.get("force", False),
1698+
request.force,
16981699
extra_conditions=extra_conditions,
16991700
)
17001701
coins = {}
@@ -1703,17 +1704,14 @@ async def spend_clawback_coins(
17031704
if len(coins) > 0:
17041705
await self.service.wallet_state_manager.spend_clawback_coins(
17051706
coins,
1706-
tx_fee,
1707+
request.fee,
17071708
action_scope,
1708-
request.get("force", False),
1709+
request.force,
17091710
extra_conditions=extra_conditions,
17101711
)
17111712

1712-
return {
1713-
"success": True,
1714-
"transaction_ids": None, # tx_endpoint wrapper will take care of this
1715-
"transactions": None, # tx_endpoint wrapper will take care of this
1716-
}
1713+
# tx_endpoint will fill in the default values here
1714+
return SpendClawbackCoinsResponse([], [], transaction_ids=[])
17171715

17181716
@marshal
17191717
async def delete_unconfirmed_transactions(self, request: DeleteUnconfirmedTransactions) -> Empty:

chia/wallet/wallet_rpc_client.py

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@
165165
SignMessageByAddressResponse,
166166
SignMessageByID,
167167
SignMessageByIDResponse,
168+
SpendClawbackCoins,
169+
SpendClawbackCoinsResponse,
168170
SplitCoins,
169171
SplitCoinsResponse,
170172
SubmitTransactions,
@@ -341,23 +343,16 @@ async def send_transaction_multi(
341343

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

362357
async def delete_unconfirmed_transactions(self, request: DeleteUnconfirmedTransactions) -> None:
363358
await self.fetch("delete_unconfirmed_transactions", request.to_json_dict())

0 commit comments

Comments
 (0)