2022-11-18 00:32:03 +03:00
|
|
|
from __future__ import annotations
|
2021-03-26 06:25:45 +03:00
|
|
|
|
2022-11-18 00:32:03 +03:00
|
|
|
from typing import Any, Dict, List, Optional
|
2021-03-26 06:25:45 +03:00
|
|
|
|
2022-08-03 23:14:58 +03:00
|
|
|
from chia.cmds.cmds_util import get_any_service_client
|
2021-04-04 06:55:26 +03:00
|
|
|
from chia.cmds.units import units
|
|
|
|
from chia.consensus.block_record import BlockRecord
|
|
|
|
from chia.rpc.farmer_rpc_client import FarmerRpcClient
|
|
|
|
from chia.rpc.full_node_rpc_client import FullNodeRpcClient
|
|
|
|
from chia.rpc.wallet_rpc_client import WalletRpcClient
|
2022-11-18 00:32:03 +03:00
|
|
|
from chia.util.misc import format_bytes, format_minutes
|
2021-07-07 06:20:21 +03:00
|
|
|
from chia.util.network import is_localhost
|
2021-03-26 06:25:45 +03:00
|
|
|
|
|
|
|
SECONDS_PER_BLOCK = (24 * 3600) / 4608
|
|
|
|
|
|
|
|
|
2022-05-25 02:22:15 +03:00
|
|
|
async def get_harvesters_summary(farmer_rpc_port: Optional[int]) -> Optional[Dict[str, Any]]:
|
2023-04-24 21:50:40 +03:00
|
|
|
async with get_any_service_client(FarmerRpcClient, farmer_rpc_port) as (farmer_client, _):
|
2022-08-03 23:14:58 +03:00
|
|
|
if farmer_client is not None:
|
|
|
|
return await farmer_client.get_harvesters_summary()
|
|
|
|
return None
|
2021-03-26 06:25:45 +03:00
|
|
|
|
|
|
|
|
2021-07-15 20:25:56 +03:00
|
|
|
async def get_blockchain_state(rpc_port: Optional[int]) -> Optional[Dict[str, Any]]:
|
2023-04-24 21:50:40 +03:00
|
|
|
async with get_any_service_client(FullNodeRpcClient, rpc_port) as (client, _):
|
2022-08-03 23:14:58 +03:00
|
|
|
if client is not None:
|
|
|
|
return await client.get_blockchain_state()
|
|
|
|
return None
|
2021-03-26 06:25:45 +03:00
|
|
|
|
|
|
|
|
2021-07-15 20:25:56 +03:00
|
|
|
async def get_average_block_time(rpc_port: Optional[int]) -> float:
|
2023-04-24 21:50:40 +03:00
|
|
|
async with get_any_service_client(FullNodeRpcClient, rpc_port) as (client, _):
|
2022-08-03 23:14:58 +03:00
|
|
|
if client is not None:
|
|
|
|
blocks_to_compare = 500
|
|
|
|
blockchain_state = await client.get_blockchain_state()
|
|
|
|
curr: Optional[BlockRecord] = blockchain_state["peak"]
|
|
|
|
if curr is None or curr.height < (blocks_to_compare + 100):
|
|
|
|
return SECONDS_PER_BLOCK
|
|
|
|
while curr is not None and curr.height > 0 and not curr.is_transaction_block:
|
|
|
|
curr = await client.get_block_record(curr.prev_hash)
|
|
|
|
if curr is None or curr.timestamp is None or curr.height is None:
|
|
|
|
# stupid mypy
|
|
|
|
return SECONDS_PER_BLOCK
|
|
|
|
past_curr = await client.get_block_record_by_height(curr.height - blocks_to_compare)
|
|
|
|
while past_curr is not None and past_curr.height > 0 and not past_curr.is_transaction_block:
|
|
|
|
past_curr = await client.get_block_record(past_curr.prev_hash)
|
|
|
|
if past_curr is None or past_curr.timestamp is None or past_curr.height is None:
|
|
|
|
# stupid mypy
|
|
|
|
return SECONDS_PER_BLOCK
|
|
|
|
return (curr.timestamp - past_curr.timestamp) / (curr.height - past_curr.height)
|
2021-03-26 06:25:45 +03:00
|
|
|
return SECONDS_PER_BLOCK
|
|
|
|
|
|
|
|
|
2021-07-15 20:25:56 +03:00
|
|
|
async def get_wallets_stats(wallet_rpc_port: Optional[int]) -> Optional[Dict[str, Any]]:
|
2023-04-24 21:50:40 +03:00
|
|
|
async with get_any_service_client(WalletRpcClient, wallet_rpc_port) as (wallet_client, _):
|
2022-08-03 23:14:58 +03:00
|
|
|
if wallet_client is not None:
|
|
|
|
return await wallet_client.get_farmed_amount()
|
|
|
|
return None
|
2021-03-26 06:25:45 +03:00
|
|
|
|
|
|
|
|
2021-07-15 20:25:56 +03:00
|
|
|
async def get_challenges(farmer_rpc_port: Optional[int]) -> Optional[List[Dict[str, Any]]]:
|
2023-04-24 21:50:40 +03:00
|
|
|
async with get_any_service_client(FarmerRpcClient, farmer_rpc_port) as (farmer_client, _):
|
2022-08-03 23:14:58 +03:00
|
|
|
if farmer_client is not None:
|
|
|
|
return await farmer_client.get_signage_points()
|
|
|
|
return None
|
2021-03-26 06:25:45 +03:00
|
|
|
|
|
|
|
|
2021-07-15 20:25:56 +03:00
|
|
|
async def challenges(farmer_rpc_port: Optional[int], limit: int) -> None:
|
2021-03-26 06:25:45 +03:00
|
|
|
signage_points = await get_challenges(farmer_rpc_port)
|
|
|
|
if signage_points is None:
|
2021-05-11 08:05:45 +03:00
|
|
|
return None
|
2021-03-26 06:25:45 +03:00
|
|
|
|
|
|
|
signage_points.reverse()
|
|
|
|
if limit != 0:
|
|
|
|
signage_points = signage_points[:limit]
|
|
|
|
|
|
|
|
for signage_point in signage_points:
|
|
|
|
print(
|
|
|
|
(
|
2021-05-12 20:50:30 +03:00
|
|
|
f"Hash: {signage_point['signage_point']['challenge_hash']} "
|
2021-03-26 06:25:45 +03:00
|
|
|
f"Index: {signage_point['signage_point']['signage_point_index']}"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2021-07-15 20:25:56 +03:00
|
|
|
async def summary(
|
|
|
|
rpc_port: Optional[int],
|
|
|
|
wallet_rpc_port: Optional[int],
|
|
|
|
harvester_rpc_port: Optional[int],
|
|
|
|
farmer_rpc_port: Optional[int],
|
|
|
|
) -> None:
|
2022-05-25 02:22:15 +03:00
|
|
|
harvesters_summary = await get_harvesters_summary(farmer_rpc_port)
|
2021-03-26 06:25:45 +03:00
|
|
|
blockchain_state = await get_blockchain_state(rpc_port)
|
2022-08-03 23:14:58 +03:00
|
|
|
farmer_running = False if harvesters_summary is None else True # harvesters uses farmer rpc too
|
2021-03-26 06:25:45 +03:00
|
|
|
|
2021-06-12 19:09:03 +03:00
|
|
|
wallet_not_ready: bool = False
|
|
|
|
amounts = None
|
|
|
|
try:
|
|
|
|
amounts = await get_wallets_stats(wallet_rpc_port)
|
2022-08-03 23:14:58 +03:00
|
|
|
except Exception:
|
|
|
|
wallet_not_ready = True
|
|
|
|
wallet_not_running: bool = True if amounts is None else False
|
2021-06-12 19:09:03 +03:00
|
|
|
|
2021-03-26 06:25:45 +03:00
|
|
|
print("Farming status: ", end="")
|
|
|
|
if blockchain_state is None:
|
|
|
|
print("Not available")
|
|
|
|
elif blockchain_state["sync"]["sync_mode"]:
|
|
|
|
print("Syncing")
|
|
|
|
elif not blockchain_state["sync"]["synced"]:
|
|
|
|
print("Not synced or not connected to peers")
|
|
|
|
elif not farmer_running:
|
|
|
|
print("Not running")
|
|
|
|
else:
|
|
|
|
print("Farming")
|
|
|
|
|
|
|
|
if amounts is not None:
|
|
|
|
print(f"Total chia farmed: {amounts['farmed_amount'] / units['chia']}")
|
|
|
|
print(f"User transaction fees: {amounts['fee_amount'] / units['chia']}")
|
|
|
|
print(f"Block rewards: {(amounts['farmer_reward_amount'] + amounts['pool_reward_amount']) / units['chia']}")
|
|
|
|
print(f"Last height farmed: {amounts['last_height_farmed']}")
|
|
|
|
|
2021-07-07 06:20:21 +03:00
|
|
|
class PlotStats:
|
|
|
|
total_plot_size = 0
|
|
|
|
total_plots = 0
|
|
|
|
|
2022-05-25 02:22:15 +03:00
|
|
|
if harvesters_summary is not None:
|
|
|
|
harvesters_local: Dict[str, Dict[str, Any]] = {}
|
|
|
|
harvesters_remote: Dict[str, Dict[str, Any]] = {}
|
|
|
|
for harvester in harvesters_summary["harvesters"]:
|
2021-07-07 06:20:21 +03:00
|
|
|
ip = harvester["connection"]["host"]
|
|
|
|
if is_localhost(ip):
|
|
|
|
harvesters_local[harvester["connection"]["node_id"]] = harvester
|
|
|
|
else:
|
|
|
|
if ip not in harvesters_remote:
|
|
|
|
harvesters_remote[ip] = {}
|
|
|
|
harvesters_remote[ip][harvester["connection"]["node_id"]] = harvester
|
|
|
|
|
2023-03-06 20:37:21 +03:00
|
|
|
def process_harvesters(harvester_peers_in: Dict[str, Dict[str, Any]]) -> None:
|
2022-05-25 02:22:15 +03:00
|
|
|
for harvester_peer_id, harvester_dict in harvester_peers_in.items():
|
|
|
|
syncing = harvester_dict["syncing"]
|
|
|
|
if syncing is not None and syncing["initial"]:
|
|
|
|
print(f" Loading plots: {syncing['plot_files_processed']} / {syncing['plot_files_total']}")
|
|
|
|
else:
|
|
|
|
total_plot_size_harvester = harvester_dict["total_plot_size"]
|
|
|
|
plot_count_harvester = harvester_dict["plots"]
|
|
|
|
PlotStats.total_plot_size += total_plot_size_harvester
|
|
|
|
PlotStats.total_plots += plot_count_harvester
|
|
|
|
print(f" {plot_count_harvester} plots of size: {format_bytes(total_plot_size_harvester)}")
|
2021-07-07 06:20:21 +03:00
|
|
|
|
|
|
|
if len(harvesters_local) > 0:
|
|
|
|
print(f"Local Harvester{'s' if len(harvesters_local) > 1 else ''}")
|
|
|
|
process_harvesters(harvesters_local)
|
|
|
|
for harvester_ip, harvester_peers in harvesters_remote.items():
|
|
|
|
print(f"Remote Harvester{'s' if len(harvester_peers) > 1 else ''} for IP: {harvester_ip}")
|
|
|
|
process_harvesters(harvester_peers)
|
|
|
|
|
|
|
|
print(f"Plot count for all harvesters: {PlotStats.total_plots}")
|
2021-03-26 06:25:45 +03:00
|
|
|
|
|
|
|
print("Total size of plots: ", end="")
|
2021-07-07 06:20:21 +03:00
|
|
|
print(format_bytes(PlotStats.total_plot_size))
|
2021-03-26 06:25:45 +03:00
|
|
|
else:
|
|
|
|
print("Plot count: Unknown")
|
|
|
|
print("Total size of plots: Unknown")
|
|
|
|
|
|
|
|
if blockchain_state is not None:
|
|
|
|
print("Estimated network space: ", end="")
|
2021-05-25 08:14:29 +03:00
|
|
|
print(format_bytes(blockchain_state["space"]))
|
2021-03-26 06:25:45 +03:00
|
|
|
else:
|
|
|
|
print("Estimated network space: Unknown")
|
|
|
|
|
2021-03-27 10:18:19 +03:00
|
|
|
minutes = -1
|
2022-05-25 02:22:15 +03:00
|
|
|
if blockchain_state is not None and harvesters_summary is not None:
|
2021-07-07 06:20:21 +03:00
|
|
|
proportion = PlotStats.total_plot_size / blockchain_state["space"] if blockchain_state["space"] else -1
|
2021-03-27 10:18:19 +03:00
|
|
|
minutes = int((await get_average_block_time(rpc_port) / 60) / proportion) if proportion else -1
|
2021-06-12 19:09:03 +03:00
|
|
|
|
2022-05-25 02:22:15 +03:00
|
|
|
if harvesters_summary is not None and PlotStats.total_plots == 0:
|
2021-06-12 19:09:03 +03:00
|
|
|
print("Expected time to win: Never (no plots)")
|
|
|
|
else:
|
|
|
|
print("Expected time to win: " + format_minutes(minutes))
|
|
|
|
|
|
|
|
if amounts is None:
|
|
|
|
if wallet_not_running:
|
|
|
|
print("For details on farmed rewards and fees you should run 'chia start wallet' and 'chia wallet show'")
|
|
|
|
elif wallet_not_ready:
|
|
|
|
print("For details on farmed rewards and fees you should run 'chia wallet show'")
|
|
|
|
else:
|
|
|
|
print("Note: log into your key using 'chia wallet show' to see rewards for each key")
|