-
Notifications
You must be signed in to change notification settings - Fork 2k
/
test_wallet_rpc.py
674 lines (564 loc) · 30.9 KB
/
test_wallet_rpc.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
import asyncio
import logging
from operator import attrgetter
from typing import Dict, Optional
import pytest
from blspy import G2Element
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_api import FullNodeRpcApi
from chia.rpc.full_node_rpc_client import FullNodeRpcClient
from chia.rpc.rpc_server import start_rpc_server
from chia.rpc.wallet_rpc_api import WalletRpcApi
from chia.rpc.wallet_rpc_client import WalletRpcClient
from chia.simulator.simulator_protocol import FarmNewBlockProtocol
from chia.types.announcement import Announcement
from chia.types.blockchain_format.program import Program
from chia.types.coin_record import CoinRecord
from chia.types.coin_spend import CoinSpend
from chia.types.peer_info import PeerInfo
from chia.types.spend_bundle import SpendBundle
from chia.util.bech32m import decode_puzzle_hash, encode_puzzle_hash
from chia.util.config import lock_and_load_config, save_config
from chia.util.hash import std_hash
from chia.util.ints import uint16, uint32, uint64
from chia.wallet.cat_wallet.cat_constants import DEFAULT_CATS
from chia.wallet.cat_wallet.cat_wallet import CATWallet
from chia.wallet.derive_keys import master_sk_to_wallet_sk
from chia.wallet.trading.trade_status import TradeStatus
from chia.wallet.transaction_record import TransactionRecord
from chia.wallet.transaction_sorting import SortKey
from chia.wallet.util.compute_memos import compute_memos
from chia.wallet.util.wallet_types import WalletType
from tests.pools.test_pool_rpc import wallet_is_synced
from tests.time_out_assert import time_out_assert
from tests.util.socket import find_available_listen_port
log = logging.getLogger(__name__)
async def assert_wallet_types(client: WalletRpcClient, expected: Dict[WalletType, int]) -> None:
for wallet_type in WalletType:
wallets = await client.get_wallets(wallet_type)
wallet_count = len(wallets)
if wallet_type in expected:
assert wallet_count == expected.get(wallet_type, 0)
for wallet in wallets:
assert wallet["type"] == wallet_type.value
class TestWalletRpc:
@pytest.mark.parametrize(
"trusted",
[True, False],
)
@pytest.mark.asyncio
async def test_wallet_rpc(self, two_wallet_nodes, trusted, bt, self_hostname):
test_rpc_port = find_available_listen_port()
test_rpc_port_2 = find_available_listen_port()
test_rpc_port_node = find_available_listen_port()
num_blocks = 5
full_nodes, wallets = two_wallet_nodes
full_node_api = full_nodes[0]
full_node_server = full_node_api.full_node.server
wallet_node, server_2 = wallets[0]
wallet_node_2, server_3 = wallets[1]
wallet = wallet_node.wallet_state_manager.main_wallet
wallet_2 = wallet_node_2.wallet_state_manager.main_wallet
ph = await wallet.get_new_puzzlehash()
ph_2 = await wallet_2.get_new_puzzlehash()
await server_2.start_client(PeerInfo(self_hostname, uint16(full_node_server._port)), None)
await server_3.start_client(PeerInfo(self_hostname, uint16(full_node_server._port)), None)
if trusted:
wallet_node.config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
wallet_node_2.config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
else:
wallet_node.config["trusted_peers"] = {}
wallet_node_2.config["trusted_peers"] = {}
for i in range(0, num_blocks):
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
initial_funds = sum(
[calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i)) for i in range(1, num_blocks)]
)
initial_funds_eventually = sum(
[
calculate_pool_reward(uint32(i)) + calculate_base_farmer_reward(uint32(i))
for i in range(1, num_blocks + 1)
]
)
wallet_rpc_api = WalletRpcApi(wallet_node)
wallet_rpc_api_2 = WalletRpcApi(wallet_node_2)
config = bt.config
hostname = config["self_hostname"]
daemon_port = config["daemon_port"]
def stop_node_cb():
pass
full_node_rpc_api = FullNodeRpcApi(full_node_api.full_node)
rpc_cleanup_node = await start_rpc_server(
full_node_rpc_api,
hostname,
daemon_port,
test_rpc_port_node,
stop_node_cb,
bt.root_path,
config,
connect_to_daemon=False,
)
rpc_cleanup = await start_rpc_server(
wallet_rpc_api,
hostname,
daemon_port,
test_rpc_port,
stop_node_cb,
bt.root_path,
config,
connect_to_daemon=False,
)
rpc_cleanup_2 = await start_rpc_server(
wallet_rpc_api_2,
hostname,
daemon_port,
test_rpc_port_2,
stop_node_cb,
bt.root_path,
config,
connect_to_daemon=False,
)
await time_out_assert(5, wallet.get_confirmed_balance, initial_funds)
await time_out_assert(5, wallet.get_unconfirmed_balance, initial_funds)
client = await WalletRpcClient.create(hostname, test_rpc_port, bt.root_path, config)
client_2 = await WalletRpcClient.create(hostname, test_rpc_port_2, bt.root_path, config)
client_node = await FullNodeRpcClient.create(hostname, test_rpc_port_node, bt.root_path, config)
try:
await assert_wallet_types(client, {WalletType.STANDARD_WALLET: 1})
await assert_wallet_types(client_2, {WalletType.STANDARD_WALLET: 1})
await time_out_assert(5, client.get_synced)
addr = encode_puzzle_hash(await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash(), "txch")
tx_amount = 15600000
try:
await client.send_transaction("1", 100000000000000001, addr)
raise Exception("Should not create high value tx")
except ValueError:
pass
# Tests sending a basic transaction
tx = await client.send_transaction("1", tx_amount, addr, memos=["this is a basic tx"])
transaction_id = tx.name
async def tx_in_mempool():
tx = await client.get_transaction("1", transaction_id)
return tx.is_in_mempool()
await time_out_assert(5, tx_in_mempool, True)
await time_out_assert(5, wallet.get_unconfirmed_balance, initial_funds - tx_amount)
assert (await client.get_wallet_balance("1"))["unconfirmed_wallet_balance"] == initial_funds - tx_amount
assert (await client.get_wallet_balance("1"))["confirmed_wallet_balance"] == initial_funds
for i in range(0, 5):
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_2))
async def eventual_balance():
return (await client.get_wallet_balance("1"))["confirmed_wallet_balance"]
async def eventual_balance_det(c, wallet_id: str):
return (await c.get_wallet_balance(wallet_id))["confirmed_wallet_balance"]
await time_out_assert(5, wallet_is_synced, True, wallet_node, full_node_api)
# Checks that the memo can be retrieved
tx_confirmed = await client.get_transaction("1", transaction_id)
assert tx_confirmed.confirmed
assert len(tx_confirmed.get_memos()) == 1
assert [b"this is a basic tx"] in tx_confirmed.get_memos().values()
assert list(tx_confirmed.get_memos().keys())[0] in [a.name() for a in tx.spend_bundle.additions()]
await time_out_assert(5, eventual_balance, initial_funds_eventually - tx_amount)
# Tests offline signing
ph_3 = await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash()
ph_4 = await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash()
ph_5 = await wallet_node_2.wallet_state_manager.main_wallet.get_new_puzzlehash()
# Test basic transaction to one output and coin announcement
signed_tx_amount = 888000
tx_coin_announcements = [
Announcement(
std_hash(b"coin_id_1"),
std_hash(b"message"),
b"\xca",
),
Announcement(
std_hash(b"coin_id_2"),
bytes(Program.to("a string")),
),
]
tx_res: TransactionRecord = await client.create_signed_transaction(
[{"amount": signed_tx_amount, "puzzle_hash": ph_3}], coin_announcements=tx_coin_announcements
)
assert tx_res.fee_amount == 0
assert tx_res.amount == signed_tx_amount
assert len(tx_res.additions) == 2 # The output and the change
assert any([addition.amount == signed_tx_amount for addition in tx_res.additions])
# check error for a ASSERT_ANNOUNCE_CONSUMED_FAILED and if the error is not there throw a value error
try:
push_res = await client_node.push_tx(tx_res.spend_bundle)
except ValueError as error:
error_string = error.args[0]["error"] # noqa: # pylint: disable=E1126
if error_string.find("ASSERT_ANNOUNCE_CONSUMED_FAILED") == -1:
raise ValueError from error
# # Test basic transaction to one output and puzzle announcement
signed_tx_amount = 888000
tx_puzzle_announcements = [
Announcement(
std_hash(b"puzzle_hash_1"),
b"message",
b"\xca",
),
Announcement(
std_hash(b"puzzle_hash_2"),
bytes(Program.to("a string")),
),
]
tx_res: TransactionRecord = await client.create_signed_transaction(
[{"amount": signed_tx_amount, "puzzle_hash": ph_3}], puzzle_announcements=tx_puzzle_announcements
)
assert tx_res.fee_amount == 0
assert tx_res.amount == signed_tx_amount
assert len(tx_res.additions) == 2 # The output and the change
assert any([addition.amount == signed_tx_amount for addition in tx_res.additions])
# check error for a ASSERT_ANNOUNCE_CONSUMED_FAILED and if the error is not there throw a value error
try:
push_res = await client_node.push_tx(tx_res.spend_bundle)
except ValueError as error:
error_string = error.args[0]["error"] # noqa: # pylint: disable=E1126
if error_string.find("ASSERT_ANNOUNCE_CONSUMED_FAILED") == -1:
raise ValueError from error
# Test basic transaction to one output
signed_tx_amount = 888000
tx_res: TransactionRecord = await client.create_signed_transaction(
[{"amount": signed_tx_amount, "puzzle_hash": ph_3, "memos": ["My memo"]}]
)
assert tx_res.fee_amount == 0
assert tx_res.amount == signed_tx_amount
assert len(tx_res.additions) == 2 # The output and the change
assert any([addition.amount == signed_tx_amount for addition in tx_res.additions])
push_res = await client.push_tx(tx_res.spend_bundle)
assert push_res["success"]
assert (await client.get_wallet_balance("1"))[
"confirmed_wallet_balance"
] == initial_funds_eventually - tx_amount
for i in range(0, 5):
await client.farm_block(encode_puzzle_hash(ph_2, "txch"))
await asyncio.sleep(0.5)
await time_out_assert(5, eventual_balance, initial_funds_eventually - tx_amount - signed_tx_amount)
# Test transaction to two outputs, from a specified coin, with a fee
coin_to_spend = None
for addition in tx_res.additions:
if addition.amount != signed_tx_amount:
coin_to_spend = addition
assert coin_to_spend is not None
tx_res = await client.create_signed_transaction(
[{"amount": 444, "puzzle_hash": ph_4, "memos": ["hhh"]}, {"amount": 999, "puzzle_hash": ph_5}],
coins=[coin_to_spend],
fee=100,
)
assert tx_res.fee_amount == 100
assert tx_res.amount == 444 + 999
assert len(tx_res.additions) == 3 # The outputs and the change
assert any([addition.amount == 444 for addition in tx_res.additions])
assert any([addition.amount == 999 for addition in tx_res.additions])
assert sum([rem.amount for rem in tx_res.removals]) - sum([ad.amount for ad in tx_res.additions]) == 100
push_res = await client_node.push_tx(tx_res.spend_bundle)
assert push_res["success"]
for i in range(0, 5):
await client.farm_block(encode_puzzle_hash(ph_2, "txch"))
await asyncio.sleep(0.5)
found: bool = False
for addition in tx_res.spend_bundle.additions():
if addition.amount == 444:
cr: Optional[CoinRecord] = await client_node.get_coin_record_by_name(addition.name())
assert cr is not None
spend: CoinSpend = await client_node.get_puzzle_and_solution(
addition.parent_coin_info, cr.confirmed_block_index
)
sb: SpendBundle = SpendBundle([spend], G2Element())
assert compute_memos(sb) == {addition.name(): [b"hhh"]}
found = True
assert found
new_balance = initial_funds_eventually - tx_amount - signed_tx_amount - 444 - 999 - 100
await time_out_assert(5, eventual_balance, new_balance)
send_tx_res: TransactionRecord = await client.send_transaction_multi(
"1",
[
{"amount": 555, "puzzle_hash": ph_4, "memos": ["FiMemo"]},
{"amount": 666, "puzzle_hash": ph_5, "memos": ["SeMemo"]},
],
fee=200,
)
assert send_tx_res is not None
assert send_tx_res.fee_amount == 200
assert send_tx_res.amount == 555 + 666
assert len(send_tx_res.additions) == 3 # The outputs and the change
assert any([addition.amount == 555 for addition in send_tx_res.additions])
assert any([addition.amount == 666 for addition in send_tx_res.additions])
assert (
sum([rem.amount for rem in send_tx_res.removals]) - sum([ad.amount for ad in send_tx_res.additions])
== 200
)
await asyncio.sleep(3)
for i in range(0, 5):
await client.farm_block(encode_puzzle_hash(ph_2, "txch"))
await asyncio.sleep(0.5)
new_balance = new_balance - 555 - 666 - 200
await time_out_assert(5, eventual_balance, new_balance)
address = await client.get_next_address("1", True)
assert len(address) > 10
transactions = await client.get_transactions("1")
assert len(transactions) > 1
all_transactions = await client.get_transactions("1")
# Test transaction pagination
some_transactions = await client.get_transactions("1", 0, 5)
some_transactions_2 = await client.get_transactions("1", 5, 10)
assert some_transactions == all_transactions[0:5]
assert some_transactions_2 == all_transactions[5:10]
# Testing sorts
# Test the default sort (CONFIRMED_AT_HEIGHT)
assert all_transactions == sorted(all_transactions, key=attrgetter("confirmed_at_height"))
all_transactions = await client.get_transactions("1", reverse=True)
assert all_transactions == sorted(all_transactions, key=attrgetter("confirmed_at_height"), reverse=True)
# Test RELEVANCE
await client.send_transaction("1", 1, encode_puzzle_hash(ph_2, "txch")) # Create a pending tx
all_transactions = await client.get_transactions("1", sort_key=SortKey.RELEVANCE)
sorted_transactions = sorted(all_transactions, key=attrgetter("created_at_time"), reverse=True)
sorted_transactions = sorted(sorted_transactions, key=attrgetter("confirmed_at_height"), reverse=True)
sorted_transactions = sorted(sorted_transactions, key=attrgetter("confirmed"))
assert all_transactions == sorted_transactions
all_transactions = await client.get_transactions("1", sort_key=SortKey.RELEVANCE, reverse=True)
sorted_transactions = sorted(all_transactions, key=attrgetter("created_at_time"))
sorted_transactions = sorted(sorted_transactions, key=attrgetter("confirmed_at_height"))
sorted_transactions = sorted(sorted_transactions, key=attrgetter("confirmed"), reverse=True)
assert all_transactions == sorted_transactions
# Checks that the memo can be retrieved
tx_confirmed = await client.get_transaction("1", send_tx_res.name)
assert tx_confirmed.confirmed
if isinstance(tx_confirmed, SpendBundle):
memos = compute_memos(tx_confirmed)
else:
memos = tx_confirmed.get_memos()
assert len(memos) == 2
print(memos)
assert [b"FiMemo"] in memos.values()
assert [b"SeMemo"] in memos.values()
assert list(memos.keys())[0] in [a.name() for a in send_tx_res.spend_bundle.additions()]
assert list(memos.keys())[1] in [a.name() for a in send_tx_res.spend_bundle.additions()]
# Test get_transactions to address
ph_by_addr = await wallet.get_new_puzzlehash()
await client.send_transaction("1", 1, encode_puzzle_hash(ph_by_addr, "txch"))
await client.farm_block(encode_puzzle_hash(ph_by_addr, "txch"))
await time_out_assert(10, wallet_is_synced, True, wallet_node, full_node_api)
tx_for_address = await wallet_rpc_api.get_transactions(
{"wallet_id": "1", "to_address": encode_puzzle_hash(ph_by_addr, "txch")}
)
assert len(tx_for_address["transactions"]) == 1
assert decode_puzzle_hash(tx_for_address["transactions"][0]["to_address"]) == ph_by_addr
# Test coin selection
selected_coins = await client.select_coins(amount=1, wallet_id=1)
assert len(selected_coins) > 0
##############
# CATS #
##############
# Creates a CAT wallet with 100 mojos and a CAT with 20 mojos
await client.create_new_cat_and_wallet(100)
res = await client.create_new_cat_and_wallet(20)
assert res["success"]
cat_0_id = res["wallet_id"]
asset_id = bytes.fromhex(res["asset_id"])
assert len(asset_id) > 0
await assert_wallet_types(client, {WalletType.STANDARD_WALLET: 1, WalletType.CAT: 2})
await assert_wallet_types(client_2, {WalletType.STANDARD_WALLET: 1})
bal_0 = await client.get_wallet_balance(cat_0_id)
assert bal_0["confirmed_wallet_balance"] == 0
assert bal_0["pending_coin_removal_count"] == 1
col = await client.get_cat_asset_id(cat_0_id)
assert col == asset_id
assert (await client.get_cat_name(cat_0_id)) == CATWallet.default_wallet_name_for_unknown_cat(
asset_id.hex()
)
await client.set_cat_name(cat_0_id, "My cat")
assert (await client.get_cat_name(cat_0_id)) == "My cat"
wid, name = await client.cat_asset_id_to_name(col)
assert wid == cat_0_id
assert name == "My cat"
should_be_none = await client.cat_asset_id_to_name(bytes([0] * 32))
assert should_be_none is None
verified_asset_id = next(iter(DEFAULT_CATS.items()))[1]["asset_id"]
should_be_none, name = await client.cat_asset_id_to_name(bytes.fromhex(verified_asset_id))
assert should_be_none is None
assert name == next(iter(DEFAULT_CATS.items()))[1]["name"]
await asyncio.sleep(1)
for i in range(0, 5):
await client.farm_block(encode_puzzle_hash(ph_2, "txch"))
await asyncio.sleep(0.5)
await time_out_assert(10, eventual_balance_det, 20, client, cat_0_id)
bal_0 = await client.get_wallet_balance(cat_0_id)
assert bal_0["pending_coin_removal_count"] == 0
assert bal_0["unspent_coin_count"] == 1
# Creates a second wallet with the same CAT
res = await client_2.create_wallet_for_existing_cat(asset_id)
assert res["success"]
cat_1_id = res["wallet_id"]
cat_1_asset_id = bytes.fromhex(res["asset_id"])
assert cat_1_asset_id == asset_id
await assert_wallet_types(client, {WalletType.STANDARD_WALLET: 1, WalletType.CAT: 2})
await assert_wallet_types(client_2, {WalletType.STANDARD_WALLET: 1, WalletType.CAT: 1})
await asyncio.sleep(1)
for i in range(0, 5):
await client.farm_block(encode_puzzle_hash(ph_2, "txch"))
await asyncio.sleep(0.5)
bal_1 = await client_2.get_wallet_balance(cat_1_id)
assert bal_1["confirmed_wallet_balance"] == 0
addr_0 = await client.get_next_address(cat_0_id, False)
addr_1 = await client_2.get_next_address(cat_1_id, False)
assert addr_0 != addr_1
await client.cat_spend(cat_0_id, 4, addr_1, 0, ["the cat memo"])
await asyncio.sleep(1)
for i in range(0, 5):
await client.farm_block(encode_puzzle_hash(ph_2, "txch"))
await asyncio.sleep(0.5)
await time_out_assert(10, eventual_balance_det, 16, client, cat_0_id)
await time_out_assert(10, eventual_balance_det, 4, client_2, cat_1_id)
# Test CAT coin selection
selected_coins = await client.select_coins(amount=1, wallet_id=cat_0_id)
assert len(selected_coins) > 0
##########
# Offers #
##########
# Create an offer of 5 chia for one CAT
offer, trade_record = await client.create_offer_for_ids({uint32(1): -5, cat_0_id: 1}, validate_only=True)
all_offers = await client.get_all_offers()
assert len(all_offers) == 0
assert offer is None
offer, trade_record = await client.create_offer_for_ids({uint32(1): -5, cat_0_id: 1}, fee=uint64(1))
summary = await client.get_offer_summary(offer)
assert summary == {"offered": {"xch": 5}, "requested": {col.hex(): 1}, "fees": 1}
assert await client.check_offer_validity(offer)
all_offers = await client.get_all_offers(file_contents=True)
assert len(all_offers) == 1
assert TradeStatus(all_offers[0].status) == TradeStatus.PENDING_ACCEPT
assert all_offers[0].offer == bytes(offer)
trade_record = await client_2.take_offer(offer, fee=uint64(1))
assert TradeStatus(trade_record.status) == TradeStatus.PENDING_CONFIRM
await client.cancel_offer(offer.name(), secure=False)
trade_record = await client.get_offer(offer.name(), file_contents=True)
assert trade_record.offer == bytes(offer)
assert TradeStatus(trade_record.status) == TradeStatus.CANCELLED
await client.cancel_offer(offer.name(), fee=uint64(1), secure=True)
trade_record = await client.get_offer(offer.name())
assert TradeStatus(trade_record.status) == TradeStatus.PENDING_CANCEL
new_offer, new_trade_record = await client.create_offer_for_ids({uint32(1): -5, cat_0_id: 1}, fee=uint64(1))
all_offers = await client.get_all_offers()
assert len(all_offers) == 2
await asyncio.sleep(1)
for i in range(0, 5):
await client.farm_block(encode_puzzle_hash(ph_2, "txch"))
await asyncio.sleep(0.5)
async def is_trade_confirmed(client, trade) -> bool:
trade_record = await client.get_offer(trade.name())
return TradeStatus(trade_record.status) == TradeStatus.CONFIRMED
await time_out_assert(15, is_trade_confirmed, True, client, offer)
# Test trade sorting
def only_ids(trades):
return [t.trade_id for t in trades]
trade_record = await client.get_offer(offer.name())
all_offers = await client.get_all_offers(include_completed=True) # confirmed at index descending
assert len(all_offers) == 2
assert only_ids(all_offers) == only_ids([trade_record, new_trade_record])
all_offers = await client.get_all_offers(
include_completed=True, reverse=True
) # confirmed at index ascending
assert only_ids(all_offers) == only_ids([new_trade_record, trade_record])
all_offers = await client.get_all_offers(include_completed=True, sort_key="RELEVANCE") # most relevant
assert only_ids(all_offers) == only_ids([new_trade_record, trade_record])
all_offers = await client.get_all_offers(
include_completed=True, sort_key="RELEVANCE", reverse=True
) # least relevant
assert only_ids(all_offers) == only_ids([trade_record, new_trade_record])
# Test pagination
all_offers = await client.get_all_offers(include_completed=True, start=0, end=1)
assert len(all_offers) == 1
all_offers = await client.get_all_offers(include_completed=True, start=50)
assert len(all_offers) == 0
all_offers = await client.get_all_offers(include_completed=True, start=0, end=50)
assert len(all_offers) == 2
# Keys and addresses
address = await client.get_next_address("1", True)
assert len(address) > 10
all_transactions = await client.get_transactions("1")
some_transactions = await client.get_transactions("1", 0, 5)
some_transactions_2 = await client.get_transactions("1", 5, 10)
assert len(all_transactions) > 1
assert some_transactions == all_transactions[0:5]
assert some_transactions_2 == all_transactions[5:10]
transaction_count = await client.get_transaction_count("1")
assert transaction_count == len(all_transactions)
pks = await client.get_public_keys()
assert len(pks) == 1
assert (await client.get_height_info()) > 0
created_tx = await client.send_transaction("1", tx_amount, addr)
async def tx_in_mempool_2():
tx = await client.get_transaction("1", created_tx.name)
return tx.is_in_mempool()
await time_out_assert(5, tx_in_mempool_2, True)
assert len(await wallet.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(1)) == 1
await client.delete_unconfirmed_transactions("1")
assert len(await wallet.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(1)) == 0
sk_dict = await client.get_private_key(pks[0])
assert sk_dict["fingerprint"] == pks[0]
assert sk_dict["sk"] is not None
assert sk_dict["pk"] is not None
assert sk_dict["seed"] is not None
mnemonic = await client.generate_mnemonic()
assert len(mnemonic) == 24
await client.add_key(mnemonic)
pks = await client.get_public_keys()
assert len(pks) == 2
await client.log_in(pks[1])
sk_dict = await client.get_private_key(pks[1])
assert sk_dict["fingerprint"] == pks[1]
# Add in reward addresses into farmer and pool for testing delete key checks
# set farmer to first private key
sk = await wallet_node.get_key_for_fingerprint(pks[0])
test_ph = create_puzzlehash_for_pk(master_sk_to_wallet_sk(sk, uint32(0)).get_g1())
with lock_and_load_config(wallet_node.root_path, "config.yaml") as test_config:
test_config["farmer"]["xch_target_address"] = encode_puzzle_hash(test_ph, "txch")
# set pool to second private key
sk = await wallet_node.get_key_for_fingerprint(pks[1])
test_ph = create_puzzlehash_for_pk(master_sk_to_wallet_sk(sk, uint32(0)).get_g1())
test_config["pool"]["xch_target_address"] = encode_puzzle_hash(test_ph, "txch")
save_config(wallet_node.root_path, "config.yaml", test_config)
# Check first key
sk_dict = await client.check_delete_key(pks[0])
assert sk_dict["fingerprint"] == pks[0]
assert sk_dict["used_for_farmer_rewards"] is True
assert sk_dict["used_for_pool_rewards"] is False
# Check second key
sk_dict = await client.check_delete_key(pks[1])
assert sk_dict["fingerprint"] == pks[1]
assert sk_dict["used_for_farmer_rewards"] is False
assert sk_dict["used_for_pool_rewards"] is True
# Check unknown key
sk_dict = await client.check_delete_key(123456)
assert sk_dict["fingerprint"] == 123456
assert sk_dict["used_for_farmer_rewards"] is False
assert sk_dict["used_for_pool_rewards"] is False
await client.delete_key(pks[0])
await client.log_in(pks[1])
assert len(await client.get_public_keys()) == 1
assert not (await client.get_sync_status())
wallets = await client.get_wallets()
assert len(wallets) == 1
balance = await client.get_wallet_balance(wallets[0]["id"])
assert balance["unconfirmed_wallet_balance"] == 0
try:
await client.send_transaction(wallets[0]["id"], 100, addr)
raise Exception("Should not create tx if no balance")
except ValueError:
pass
# Delete all keys
await client.delete_all_keys()
assert len(await client.get_public_keys()) == 0
finally:
# Checks that the RPC manages to stop the node
client.close()
client_2.close()
client_node.close()
await client.await_closed()
await client_2.await_closed()
await client_node.await_closed()
await rpc_cleanup()
await rpc_cleanup_2()
await rpc_cleanup_node()