async def get_next_address(self, request: Dict) -> Dict: """ Returns a new address """ assert self.service.wallet_state_manager is not None if request["new_address"] is True: create_new = True else: create_new = False wallet_id = uint32(int(request["wallet_id"])) wallet = self.service.wallet_state_manager.wallets[wallet_id] selected = self.service.config["selected_network"] prefix = self.service.config["network_overrides"]["config"][selected][ "address_prefix"] if wallet.type() == WalletType.STANDARD_WALLET: raw_puzzle_hash = await wallet.get_puzzle_hash(create_new) address = encode_puzzle_hash(raw_puzzle_hash, prefix) elif wallet.type() == WalletType.COLOURED_COIN: raw_puzzle_hash = await wallet.get_puzzle_hash(create_new) address = encode_puzzle_hash(raw_puzzle_hash, prefix) else: raise ValueError( f"Wallet type {wallet.type()} cannot create puzzle hashes") return { "wallet_id": wallet_id, "address": address, }
async def setup_farmer( port, consensus_constants: ConsensusConstants, full_node_port: Optional[uint16] = None, ): config = bt.config["farmer"] config_pool = bt.config["pool"] config["xch_target_address"] = encode_puzzle_hash(bt.farmer_ph) config["pool_public_keys"] = [bytes(pk).hex() for pk in bt.pool_pubkeys] config["port"] = port config_pool["xch_target_address"] = encode_puzzle_hash(bt.pool_ph) if full_node_port: config["full_node_peer"]["host"] = self_hostname config["full_node_peer"]["port"] = full_node_port else: del config["full_node_peer"] kwargs = service_kwargs_for_farmer(bt.root_path, config, config_pool, bt.keychain, consensus_constants) kwargs.update( parse_cli_args=False, connect_to_daemon=False, ) service = Service(**kwargs) await service.start() yield service._api, service._node.server service.stop() await service.wait_closed()
async def get_transactions(self, request: Dict) -> Dict: assert self.service.wallet_state_manager is not None wallet_id = int(request["wallet_id"]) if "start" in request: start = request["start"] else: start = 0 if "end" in request: end = request["end"] else: end = 50 transactions = await self.service.wallet_state_manager.tx_store.get_transactions_between(wallet_id, start, end) formatted_transactions = [] for tx in transactions: formatted = tx.to_json_dict() formatted["to_address"] = encode_puzzle_hash(tx.to_puzzle_hash) formatted_transactions.append(formatted) return { "transactions": formatted_transactions, "wallet_id": wallet_id, }
def show_all_keys(): """ Prints all keys and mnemonics (if available). """ private_keys = keychain.get_all_private_keys() if len(private_keys) == 0: print("There are no saved private keys.") return print("Showing all private keys:") for sk, seed in private_keys: print("") print("Fingerprint:", sk.get_g1().get_fingerprint()) print("Master public key (m):", sk.get_g1()) print("Master private key (m):", bytes(sk).hex()) print( "Farmer public key (m/12381/8444/0/0)::", master_sk_to_farmer_sk(sk).get_g1(), ) print("Pool public key (m/12381/8444/1/0):", master_sk_to_pool_sk(sk).get_g1()) print( "First wallet key (m/12381/8444/2/0):", master_sk_to_wallet_sk(sk, uint32(0)).get_g1(), ) print( "First wallet address:", encode_puzzle_hash( create_puzzlehash_for_pk( master_sk_to_wallet_sk(sk, uint32(0)).get_g1())), ) assert seed is not None mnemonic = bytes_to_mnemonic(seed) print(" Mnemonic seed (24 secret words):") print(mnemonic)
def check_keys(new_root): keychain: Keychain = Keychain() all_sks = keychain.get_all_private_keys() if len(all_sks) == 0: print("No keys are present in the keychain. Generate them with 'chia keys generate'") return config: Dict = load_config(new_root, "config.yaml") pool_child_pubkeys = [master_sk_to_pool_sk(sk).get_g1() for sk, _ in all_sks] all_targets = [] stop_searching_for_farmer = "xch_target_address" not in config["farmer"] stop_searching_for_pool = "xch_target_address" not in config["pool"] number_of_ph_to_search = 500 selected = config["selected_network"] prefix = config["network_overrides"]["config"][selected]["address_prefix"] for i in range(number_of_ph_to_search): if stop_searching_for_farmer and stop_searching_for_pool and i > 0: break for sk, _ in all_sks: all_targets.append( encode_puzzle_hash(create_puzzlehash_for_pk(master_sk_to_wallet_sk(sk, uint32(i)).get_g1()), prefix) ) if all_targets[-1] == config["farmer"].get("xch_target_address"): stop_searching_for_farmer = True if all_targets[-1] == config["pool"].get("xch_target_address"): stop_searching_for_pool = True # Set the destinations if "xch_target_address" not in config["farmer"]: print(f"Setting the xch destination address for coinbase fees reward to {all_targets[0]}") config["farmer"]["xch_target_address"] = all_targets[0] elif config["farmer"]["xch_target_address"] not in all_targets: print( f"WARNING: using a farmer address which we don't have the private" f" keys for. We searched the first {number_of_ph_to_search} addresses. Consider overriding " f"{config['farmer']['xch_target_address']} with {all_targets[0]}" ) if "pool" not in config: config["pool"] = {} if "xch_target_address" not in config["pool"]: print(f"Setting the xch destination address for coinbase reward to {all_targets[0]}") config["pool"]["xch_target_address"] = all_targets[0] elif config["pool"]["xch_target_address"] not in all_targets: print( f"WARNING: using a pool address which we don't have the private" f" keys for. We searched the first {number_of_ph_to_search} addresses. Consider overriding " f"{config['pool']['xch_target_address']} with {all_targets[0]}" ) # Set the pool pks in the farmer pool_pubkeys_hex = set(bytes(pk).hex() for pk in pool_child_pubkeys) if "pool_public_keys" in config["farmer"]: for pk_hex in config["farmer"]["pool_public_keys"]: # Add original ones in config pool_pubkeys_hex.add(pk_hex) config["farmer"]["pool_public_keys"] = pool_pubkeys_hex save_config(new_root, "config.yaml", config)
async def get_next_address(self, request: Dict) -> Dict: """ Returns a new address """ assert self.service.wallet_state_manager is not None wallet_id = uint32(int(request["wallet_id"])) wallet = self.service.wallet_state_manager.wallets[wallet_id] if wallet.type() == WalletType.STANDARD_WALLET: raw_puzzle_hash = await wallet.get_new_puzzlehash() address = encode_puzzle_hash(raw_puzzle_hash) elif wallet.type() == WalletType.COLOURED_COIN: raw_puzzle_hash = await wallet.get_new_inner_hash() address = encode_puzzle_hash(raw_puzzle_hash) else: raise ValueError(f"Wallet type {wallet.type()} cannot create puzzle hashes") return { "wallet_id": wallet_id, "address": address, }
def print_transaction(tx: TransactionRecord, verbose: bool, name) -> None: if verbose: print(tx) else: chia_amount = Decimal(int(tx.amount)) / units["chia"] to_address = encode_puzzle_hash(tx.to_puzzle_hash, name) print(f"Transaction {tx.name}") print( f"Status: {'Confirmed' if tx.confirmed else ('In mempool' if tx.is_in_mempool() else 'Pending')}" ) print(f"Amount: {chia_amount} {name}") print(f"To address: {to_address}") print( "Created at:", datetime.fromtimestamp( tx.created_at_time).strftime("%Y-%m-%d %H:%M:%S")) print("")
def show_all_keys(): """ Prints all keys and mnemonics (if available). """ root_path = DEFAULT_ROOT_PATH config = load_config(root_path, "config.yaml") private_keys = keychain.get_all_private_keys() selected = config["selected_network"] prefix = config["network_overrides"]["config"][selected]["address_prefix"] if len(private_keys) == 0: print("There are no saved private keys") return print("Showing all private keys:") for sk, seed in private_keys: print("") print("Fingerprint:", sk.get_g1().get_fingerprint()) print("Master public key (m):", sk.get_g1()) print("Master private key (m):", bytes(sk).hex()) print( "Farmer public key (m/12381/8444/0/0)::", master_sk_to_farmer_sk(sk).get_g1(), ) print("Pool public key (m/12381/8444/1/0):", master_sk_to_pool_sk(sk).get_g1()) print( "First wallet key (m/12381/8444/2/0):", master_sk_to_wallet_sk(sk, uint32(0)).get_g1(), ) print( "First wallet address:", encode_puzzle_hash( create_puzzlehash_for_pk( master_sk_to_wallet_sk(sk, uint32(0)).get_g1()), prefix), ) assert seed is not None mnemonic = bytes_to_mnemonic(seed) print(" Mnemonic seed (24 secret words):") print(mnemonic)
async def test_wallet_make_transaction(self, two_wallet_nodes): test_rpc_port = uint16(21529) 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("localhost", uint16(full_node_server._port)), None) 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) config = bt.config hostname = config["self_hostname"] daemon_port = config["daemon_port"] def stop_node_cb(): pass 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, ) 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("localhost", test_rpc_port, bt.root_path, config) try: addr = encode_puzzle_hash( await wallet_node_2.wallet_state_manager.main_wallet. get_new_puzzlehash(), "xch") tx_amount = 15600000 try: await client.send_transaction("1", 100000000000000001, addr) raise Exception("Should not create high value tx") except ValueError: pass tx = await client.send_transaction("1", tx_amount, addr) 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 client.farm_block(encode_puzzle_hash(ph_2, "xch")) await asyncio.sleep(1) async def eventual_balance(): return ( await client.get_wallet_balance("1"))["confirmed_wallet_balance"] await time_out_assert(5, eventual_balance, initial_funds_eventually - tx_amount) address = await client.get_next_address("1") assert len(address) > 10 transactions = await client.get_transactions("1") assert len(transactions) > 1 pks = await client.get_public_keys() assert len(pks) == 1 assert (await client.get_height_info()) > 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_and_skip(pks[1]) sk_dict = await client.get_private_key(pks[1]) assert sk_dict["fingerprint"] == pks[1] await client.delete_key(pks[0]) await client.log_in_and_skip(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 test_wallet_backup_path = Path("test_wallet_backup_file") await client.create_backup(test_wallet_backup_path) assert test_wallet_backup_path.exists() test_wallet_backup_path.unlink() try: await client.send_transaction(wallets[0]["id"], 100, addr) raise Exception("Should not create tx if no balance") except ValueError: pass 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() await client.await_closed() await rpc_cleanup()
async def test1(self, simulation): test_rpc_port = uint16(21522) test_rpc_port_2 = uint16(21523) harvester, farmer_api = simulation def stop_node_cb(): pass def stop_node_cb_2(): pass config = bt.config hostname = config["self_hostname"] daemon_port = config["daemon_port"] farmer_rpc_api = FarmerRpcApi(farmer_api.farmer) harvester_rpc_api = HarvesterRpcApi(harvester) rpc_cleanup = await start_rpc_server( farmer_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( harvester_rpc_api, hostname, daemon_port, test_rpc_port_2, stop_node_cb_2, bt.root_path, config, connect_to_daemon=False, ) try: client = await FarmerRpcClient.create(self_hostname, test_rpc_port, bt.root_path, config) client_2 = await HarvesterRpcClient.create(self_hostname, test_rpc_port_2, bt.root_path, config) async def have_connections(): return len(await client.get_connections()) > 0 await time_out_assert(15, have_connections, True) assert (await client.get_signage_point(std_hash(b"2"))) is None assert len(await client.get_signage_points()) == 0 async def have_signage_points(): return len(await client.get_signage_points()) > 0 sp = farmer_protocol.NewSignagePoint(std_hash(b"1"), std_hash(b"2"), std_hash(b"3"), uint64(1), uint64(1000000), uint8(2)) await farmer_api.new_signage_point(sp) await time_out_assert(5, have_signage_points, True) assert (await client.get_signage_point(std_hash(b"2"))) is not None async def have_plots(): return len((await client_2.get_plots())["plots"]) > 0 await time_out_assert(5, have_plots, True) res = await client_2.get_plots() num_plots = len(res["plots"]) assert num_plots > 0 plot_dir = get_plot_dir() / "subdir" plot_dir.mkdir(parents=True, exist_ok=True) plot_dir_sub = get_plot_dir() / "subdir" / "subsubdir" plot_dir_sub.mkdir(parents=True, exist_ok=True) plotter = DiskPlotter() filename = "test_farmer_harvester_rpc_plot.plot" filename_2 = "test_farmer_harvester_rpc_plot2.plot" plotter.create_plot_disk( str(plot_dir), str(plot_dir), str(plot_dir), filename, 18, stream_plot_info_pk(bt.pool_pk, bt.farmer_pk, AugSchemeMPL.key_gen(bytes([4] * 32))), token_bytes(32), 128, 0, 2000, 0, False, ) # Making a plot with a puzzle hash encoded into it instead of pk plot_id_2 = token_bytes(32) plotter.create_plot_disk( str(plot_dir), str(plot_dir), str(plot_dir), filename_2, 18, stream_plot_info_ph(std_hash(b"random ph"), bt.farmer_pk, AugSchemeMPL.key_gen(bytes([5] * 32))), plot_id_2, 128, 0, 2000, 0, False, ) # Making the same plot, in a different dir. This should not be farmed plotter.create_plot_disk( str(plot_dir_sub), str(plot_dir_sub), str(plot_dir_sub), filename_2, 18, stream_plot_info_ph(std_hash(b"random ph"), bt.farmer_pk, AugSchemeMPL.key_gen(bytes([5] * 32))), plot_id_2, 128, 0, 2000, 0, False, ) res_2 = await client_2.get_plots() assert len(res_2["plots"]) == num_plots assert len(await client_2.get_plot_directories()) == 1 await client_2.add_plot_directory(str(plot_dir)) await client_2.add_plot_directory(str(plot_dir_sub)) assert len(await client_2.get_plot_directories()) == 3 res_2 = await client_2.get_plots() assert len(res_2["plots"]) == num_plots + 2 await client_2.delete_plot(str(plot_dir / filename)) await client_2.delete_plot(str(plot_dir / filename_2)) res_3 = await client_2.get_plots() assert len(res_3["plots"]) == num_plots await client_2.remove_plot_directory(str(plot_dir)) assert len(await client_2.get_plot_directories()) == 2 targets_1 = await client.get_reward_targets(False) assert "have_pool_sk" not in targets_1 assert "have_farmer_sk" not in targets_1 targets_2 = await client.get_reward_targets(True) assert targets_2["have_pool_sk"] and targets_2["have_farmer_sk"] new_ph: bytes32 = create_puzzlehash_for_pk( master_sk_to_wallet_sk(bt.farmer_master_sk, uint32(10)).get_g1()) new_ph_2: bytes32 = create_puzzlehash_for_pk( master_sk_to_wallet_sk(bt.pool_master_sk, uint32(472)).get_g1()) await client.set_reward_targets( encode_puzzle_hash(new_ph, "xch"), encode_puzzle_hash(new_ph_2, "xch")) targets_3 = await client.get_reward_targets(True) assert decode_puzzle_hash(targets_3["farmer_target"]) == new_ph assert decode_puzzle_hash(targets_3["pool_target"]) == new_ph_2 assert targets_3["have_pool_sk"] and targets_3["have_farmer_sk"] new_ph_3: bytes32 = create_puzzlehash_for_pk( master_sk_to_wallet_sk(bt.pool_master_sk, uint32(1888)).get_g1()) await client.set_reward_targets( None, encode_puzzle_hash(new_ph_3, "xch")) targets_4 = await client.get_reward_targets(True) assert decode_puzzle_hash(targets_4["farmer_target"]) == new_ph assert decode_puzzle_hash(targets_4["pool_target"]) == new_ph_3 assert not targets_4["have_pool_sk"] and targets_3["have_farmer_sk"] root_path = farmer_api.farmer._root_path config = load_config(root_path, "config.yaml") assert config["farmer"][ "xch_target_address"] == encode_puzzle_hash(new_ph, "xch") assert config["pool"]["xch_target_address"] == encode_puzzle_hash( new_ph_3, "xch") new_ph_3_encoded = encode_puzzle_hash(new_ph_3, "xch") added_char = new_ph_3_encoded + "a" with pytest.raises(ValueError): await client.set_reward_targets(None, added_char) replaced_char = new_ph_3_encoded[0:-1] + "a" with pytest.raises(ValueError): await client.set_reward_targets(None, replaced_char) finally: # Checks that the RPC manages to stop the node client.close() client_2.close() await client.await_closed() await client_2.await_closed() await rpc_cleanup() await rpc_cleanup_2()
async def show_async( rpc_port: int, state: bool, show_connections: bool, exit_node: bool, add_connection: str, remove_connection: str, block_header_hash_by_height: str, block_by_header_hash: str, ) -> None: import aiohttp import time import traceback from time import localtime, struct_time from typing import List, Optional from src.consensus.block_record import BlockRecord from src.rpc.full_node_rpc_client import FullNodeRpcClient from src.server.outbound_message import NodeType from src.types.full_block import FullBlock from src.util.bech32m import encode_puzzle_hash from src.util.byte_types import hexstr_to_bytes from src.util.config import load_config from src.util.default_root import DEFAULT_ROOT_PATH from src.util.ints import uint16 try: config = load_config(DEFAULT_ROOT_PATH, "config.yaml") self_hostname = config["self_hostname"] if rpc_port is None: rpc_port = config["full_node"]["rpc_port"] client = await FullNodeRpcClient.create(self_hostname, uint16(rpc_port), DEFAULT_ROOT_PATH, config) if state: blockchain_state = await client.get_blockchain_state() if blockchain_state is None: print("There is no blockchain found yet. Try again shortly") return peak: Optional[BlockRecord] = blockchain_state["peak"] difficulty = blockchain_state["difficulty"] sub_slot_iters = blockchain_state["sub_slot_iters"] synced = blockchain_state["sync"]["synced"] sync_mode = blockchain_state["sync"]["sync_mode"] total_iters = peak.total_iters if peak is not None else 0 num_blocks: int = 10 if sync_mode: sync_max_block = blockchain_state["sync"]["sync_tip_height"] sync_current_block = blockchain_state["sync"][ "sync_progress_height"] print( "Current Blockchain Status: Full Node syncing to block", sync_max_block, "\nCurrently synced to block:", sync_current_block, ) if synced: print("Current Blockchain Status: Full Node Synced") print("\nPeak: Hash:", peak.header_hash if peak is not None else "") elif peak is not None: print( f"Current Blockchain Status: Not Synced. Peak height: {peak.height}" ) else: print("\nSearching for an initial chain\n") print( "You may be able to expedite with 'chia show -a host:port' using a known node.\n" ) if peak is not None: if peak.is_transaction_block: peak_time = peak.timestamp else: peak_hash = peak.header_hash curr = await client.get_block_record(peak_hash) while curr is not None and not curr.is_transaction_block: curr = await client.get_block_record(curr.prev_hash) peak_time = curr.timestamp peak_time_struct = struct_time(localtime(peak_time)) print( " Time:", f"{time.strftime('%a %b %d %Y %T %Z', peak_time_struct)}", f" Height: {peak.height:>10}\n", ) print("Estimated network space: ", end="") network_space_human_readable = blockchain_state[ "space"] / 1024**4 if network_space_human_readable >= 1024: network_space_human_readable = network_space_human_readable / 1024 print(f"{network_space_human_readable:.3f} PiB") else: print(f"{network_space_human_readable:.3f} TiB") print(f"Current difficulty: {difficulty}") print(f"Current VDF sub_slot_iters: {sub_slot_iters}") print("Total iterations since the start of the blockchain:", total_iters) print("") print(" Height: | Hash:") added_blocks: List[BlockRecord] = [] curr = await client.get_block_record(peak.header_hash) while curr is not None and len( added_blocks) < num_blocks and curr.height > 0: added_blocks.append(curr) curr = await client.get_block_record(curr.prev_hash) for b in added_blocks: print(f"{b.height:>9} | {b.header_hash}") else: print("Blockchain has no blocks yet") # if called together with show_connections, leave a blank line if show_connections: print("") if show_connections: connections = await client.get_connections() print("Connections:") print( "Type IP Ports NodeID Last Connect" + " MiB Up|Dwn") for con in connections: last_connect_tuple = struct_time( localtime(con["last_message_time"])) last_connect = time.strftime("%b %d %T", last_connect_tuple) mb_down = con["bytes_read"] / (1024 * 1024) mb_up = con["bytes_written"] / (1024 * 1024) host = con["peer_host"] # Strip IPv6 brackets if host[0] == "[": host = host[1:39] # Nodetype length is 9 because INTRODUCER will be deprecated if NodeType(con["type"]) is NodeType.FULL_NODE: peak_height = con["peak_height"] peak_hash = con["peak_hash"] if peak_hash is None: peak_hash = "No Info" if peak_height is None: peak_height = 0 con_str = ( f"{NodeType(con['type']).name:9} {host:38} " f"{con['peer_port']:5}/{con['peer_server_port']:<5}" f" {con['node_id'].hex()[:8]}... " f"{last_connect} " f"{mb_up:7.1f}|{mb_down:<7.1f}" f"\n " f"-SB Height: {peak_height:8.0f} -Hash: {peak_hash[2:10]}..." ) else: con_str = ( f"{NodeType(con['type']).name:9} {host:38} " f"{con['peer_port']:5}/{con['peer_server_port']:<5}" f" {con['node_id'].hex()[:8]}... " f"{last_connect} " f"{mb_up:7.1f}|{mb_down:<7.1f}") print(con_str) # if called together with state, leave a blank line if state: print("") if exit_node: node_stop = await client.stop_node() print(node_stop, "Node stopped") if add_connection: if ":" not in add_connection: print( "Enter a valid IP and port in the following format: 10.5.4.3:8000" ) else: ip, port = ( ":".join(add_connection.split(":")[:-1]), add_connection.split(":")[-1], ) print(f"Connecting to {ip}, {port}") try: await client.open_connection(ip, int(port)) except Exception: print(f"Failed to connect to {ip}:{port}") if remove_connection: result_txt = "" if len(remove_connection) != 8: result_txt = "Invalid NodeID. Do not include '.'" else: connections = await client.get_connections() for con in connections: if remove_connection == con["node_id"].hex()[:8]: print("Attempting to disconnect", "NodeID", remove_connection) try: await client.close_connection(con["node_id"]) except Exception: result_txt = f"Failed to disconnect NodeID {remove_connection}" else: result_txt = f"NodeID {remove_connection}... {NodeType(con['type']).name} " f"{con['peer_host']} disconnected" elif result_txt == "": result_txt = f"NodeID {remove_connection}... not found" print(result_txt) if block_header_hash_by_height != "": block_header = await client.get_block_record_by_height( block_header_hash_by_height) if block_header is not None: print(f"Header hash of block {block_header_hash_by_height}: " f"{block_header.header_hash.hex()}") else: print("Block height", block_header_hash_by_height, "not found") if block_by_header_hash != "": block: Optional[BlockRecord] = await client.get_block_record( hexstr_to_bytes(block_by_header_hash)) full_block: Optional[FullBlock] = await client.get_block( hexstr_to_bytes(block_by_header_hash)) # Would like to have a verbose flag for this if block is not None: assert full_block is not None prev_b = await client.get_block_record(block.prev_hash) if prev_b is not None: difficulty = block.weight - prev_b.weight else: difficulty = block.weight if block.is_transaction_block: assert full_block.transactions_info is not None block_time = struct_time( localtime( full_block.foliage_transaction_block.timestamp if full_block.foliage_transaction_block else None)) block_time_string = time.strftime("%a %b %d %Y %T %Z", block_time) cost = str(full_block.transactions_info.cost) tx_filter_hash = "Not a transaction block" if full_block.foliage_transaction_block: tx_filter_hash = full_block.foliage_transaction_block.filter_hash else: block_time_string = "Not a transaction block" cost = "Not a transaction block" tx_filter_hash = "Not a transaction block" print("Block at height", block.height, ":") address_prefix = config["network_overrides"]["config"][ config["selected_network"]]["address_prefix"] farmer_address = encode_puzzle_hash(block.farmer_puzzle_hash, address_prefix) pool_address = encode_puzzle_hash(block.pool_puzzle_hash, address_prefix) print( f"Header Hash 0x{block.header_hash.hex()}\n" f"Timestamp {block_time_string}\n" f"Block Height {block.height}\n" f"Weight {block.weight}\n" f"Previous Block 0x{block.prev_hash.hex()}\n" f"Difficulty {difficulty}\n" f"Sub-slot iters {block.sub_slot_iters}\n" f"Cost {cost}\n" f"Total VDF Iterations {block.total_iters}\n" f"Is a Transaction Block?{block.is_transaction_block}\n" f"Deficit {block.deficit}\n" f"PoSpace 'k' Size {full_block.reward_chain_block.proof_of_space.size}\n" f"Plot Public Key 0x{full_block.reward_chain_block.proof_of_space.plot_public_key}\n" f"Pool Public Key 0x{full_block.reward_chain_block.proof_of_space.pool_public_key}\n" f"Pool Public Key " f"0x{full_block.reward_chain_block.proof_of_space.pool_contract_puzzle_hash}\n" f"{full_block.reward_chain_block.proof_of_space.pool_contract_puzzle_hash}\n" f"Tx Filter Hash {tx_filter_hash}\n" f"Farmer Address {farmer_address}\n" f"Pool Address {pool_address}\n" f"Fees Amount {block.fees}\n") else: print("Block with header hash", block_header_hash_by_height, "not found") except Exception as e: if isinstance(e, aiohttp.client_exceptions.ClientConnectorError): print( f"Connection error. Check if full node rpc is running at {rpc_port}" ) print("This is normal if full node is still starting up") else: tb = traceback.format_exc() print(f"Exception from 'show' {tb}") client.close() await client.await_closed()
async def test_create_rl_coin(self, three_wallet_nodes): num_blocks = 4 full_nodes, wallets = three_wallet_nodes full_node_api = full_nodes[0] full_node_server = full_node_api.server wallet_node, server_2 = wallets[0] wallet_node_1, wallet_server_1 = wallets[1] wallet_node_2, wallet_server_2 = wallets[2] wallet = wallet_node.wallet_state_manager.main_wallet ph = await wallet.get_new_puzzlehash() await server_2.start_client(PeerInfo(self_hostname, uint16(full_node_server._port)), None) await wallet_server_1.start_client(PeerInfo(self_hostname, uint16(full_node_server._port)), None) await wallet_server_2.start_client(PeerInfo(self_hostname, uint16(full_node_server._port)), None) await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph)) for i in range(0, num_blocks + 1): await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(32 * b"\0")) fund_owners_initial_balance = await wallet.get_confirmed_balance() api_user = WalletRpcApi(wallet_node_1) val = await api_user.create_new_wallet( {"wallet_type": "rl_wallet", "rl_type": "user", "host": f"{self_hostname}:5000"} ) assert isinstance(val, dict) if "success" in val: assert val["success"] assert val["id"] assert val["type"] == WalletType.RATE_LIMITED.value user_wallet_id = val["id"] pubkey = val["pubkey"] api_admin = WalletRpcApi(wallet_node) val = await api_admin.create_new_wallet( { "wallet_type": "rl_wallet", "rl_type": "admin", "interval": 2, "limit": 10, "pubkey": pubkey, "amount": 100, "fee": 1, "host": f"{self_hostname}:5000", } ) assert isinstance(val, dict) if "success" in val: assert val["success"] assert val["id"] assert val["type"] == WalletType.RATE_LIMITED.value assert val["origin"] assert val["pubkey"] admin_wallet_id = val["id"] admin_pubkey = val["pubkey"] origin: Coin = val["origin"] await api_user.rl_set_user_info( { "wallet_id": user_wallet_id, "interval": 2, "limit": 10, "origin": { "parent_coin_info": origin.parent_coin_info.hex(), "puzzle_hash": origin.puzzle_hash.hex(), "amount": origin.amount, }, "admin_pubkey": admin_pubkey, } ) assert (await api_user.get_wallet_balance({"wallet_id": user_wallet_id}))["wallet_balance"][ "confirmed_wallet_balance" ] == 0 for i in range(0, 2 * num_blocks): await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(32 * b"\0")) assert await wallet.get_confirmed_balance() == fund_owners_initial_balance - 101 async def check_balance(api, wallet_id): balance_response = await api.get_wallet_balance({"wallet_id": wallet_id}) balance = balance_response["wallet_balance"]["confirmed_wallet_balance"] return balance await time_out_assert(15, check_balance, 100, api_user, user_wallet_id) receiving_wallet = wallet_node_2.wallet_state_manager.main_wallet address = encode_puzzle_hash(await receiving_wallet.get_new_puzzlehash(), "xch") assert await receiving_wallet.get_spendable_balance() == 0 val = await api_user.send_transaction({"wallet_id": user_wallet_id, "amount": 3, "fee": 2, "address": address}) assert "transaction_id" in val async def is_transaction_in_mempool(api, tx_id: bytes32) -> bool: try: val = await api.get_transaction({"wallet_id": user_wallet_id, "transaction_id": tx_id.hex()}) except ValueError: return False for _, mis, _ in val["transaction"].sent_to: if ( MempoolInclusionStatus(mis) == MempoolInclusionStatus.SUCCESS or MempoolInclusionStatus(mis) == MempoolInclusionStatus.PENDING ): return True return False await time_out_assert(15, is_transaction_in_mempool, True, api_user, val["transaction_id"]) for i in range(0, num_blocks): await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(32 * b"\0")) await time_out_assert(15, check_balance, 95, api_user, user_wallet_id) await time_out_assert(15, receiving_wallet.get_spendable_balance, 3) val = await api_admin.add_rate_limited_funds({"wallet_id": admin_wallet_id, "amount": 100, "fee": 7}) assert val["status"] == "SUCCESS" for i in range(0, 50): await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(32 * b"\0")) await time_out_assert(15, check_balance, 195, api_user, user_wallet_id) # test spending puzzle_hash = encode_puzzle_hash(await receiving_wallet.get_new_puzzlehash(), "xch") val = await api_user.send_transaction( { "wallet_id": user_wallet_id, "amount": 105, "fee": 0, "address": puzzle_hash, } ) await time_out_assert(15, is_transaction_in_mempool, True, api_user, val["transaction_id"]) for i in range(0, num_blocks): await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(32 * b"\0")) await time_out_assert(15, check_balance, 90, api_user, user_wallet_id) await time_out_assert(15, receiving_wallet.get_spendable_balance, 108) val = await api_admin.send_clawback_transaction({"wallet_id": admin_wallet_id, "fee": 11}) await time_out_assert(15, is_transaction_in_mempool, True, api_admin, val["transaction_id"]) for i in range(0, num_blocks): await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(32 * b"\0")) await time_out_assert(15, check_balance, 0, api_user, user_wallet_id) await time_out_assert(15, check_balance, 0, api_admin, user_wallet_id) final_balance = await wallet.get_confirmed_balance() assert final_balance == fund_owners_initial_balance - 129