bittensor-cli 8.4.4__py3-none-any.whl → 9.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bittensor_cli/__init__.py +1 -1
- bittensor_cli/cli.py +1827 -1394
- bittensor_cli/src/__init__.py +623 -168
- bittensor_cli/src/bittensor/balances.py +41 -8
- bittensor_cli/src/bittensor/chain_data.py +557 -428
- bittensor_cli/src/bittensor/extrinsics/registration.py +129 -23
- bittensor_cli/src/bittensor/extrinsics/root.py +3 -3
- bittensor_cli/src/bittensor/extrinsics/transfer.py +6 -11
- bittensor_cli/src/bittensor/minigraph.py +46 -8
- bittensor_cli/src/bittensor/subtensor_interface.py +567 -250
- bittensor_cli/src/bittensor/utils.py +370 -25
- bittensor_cli/src/commands/stake/__init__.py +154 -0
- bittensor_cli/src/commands/stake/add.py +625 -0
- bittensor_cli/src/commands/stake/children_hotkeys.py +103 -75
- bittensor_cli/src/commands/stake/list.py +687 -0
- bittensor_cli/src/commands/stake/move.py +1000 -0
- bittensor_cli/src/commands/stake/remove.py +1146 -0
- bittensor_cli/src/commands/subnets/__init__.py +0 -0
- bittensor_cli/src/commands/subnets/price.py +867 -0
- bittensor_cli/src/commands/subnets/subnets.py +2028 -0
- bittensor_cli/src/commands/sudo.py +554 -12
- bittensor_cli/src/commands/wallets.py +225 -531
- bittensor_cli/src/commands/weights.py +2 -2
- {bittensor_cli-8.4.4.dist-info → bittensor_cli-9.0.0.dist-info}/METADATA +7 -4
- bittensor_cli-9.0.0.dist-info/RECORD +34 -0
- bittensor_cli/src/bittensor/async_substrate_interface.py +0 -2748
- bittensor_cli/src/commands/root.py +0 -1787
- bittensor_cli/src/commands/stake/stake.py +0 -1448
- bittensor_cli/src/commands/subnets.py +0 -897
- bittensor_cli-8.4.4.dist-info/RECORD +0 -31
- {bittensor_cli-8.4.4.dist-info → bittensor_cli-9.0.0.dist-info}/WHEEL +0 -0
- {bittensor_cli-8.4.4.dist-info → bittensor_cli-9.0.0.dist-info}/entry_points.txt +0 -0
- {bittensor_cli-8.4.4.dist-info → bittensor_cli-9.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,2028 @@
|
|
1
|
+
import asyncio
|
2
|
+
import json
|
3
|
+
import sqlite3
|
4
|
+
from typing import TYPE_CHECKING, Optional, cast
|
5
|
+
import typer
|
6
|
+
|
7
|
+
from bittensor_wallet import Wallet
|
8
|
+
from bittensor_wallet.errors import KeyFileError
|
9
|
+
from rich.prompt import Confirm, Prompt
|
10
|
+
from rich.console import Group
|
11
|
+
from rich.progress import Progress, BarColumn, TextColumn
|
12
|
+
from rich.table import Column, Table
|
13
|
+
from rich import box
|
14
|
+
|
15
|
+
from bittensor_cli.src import COLOR_PALETTE
|
16
|
+
from bittensor_cli.src.bittensor.balances import Balance
|
17
|
+
from bittensor_cli.src.bittensor.extrinsics.registration import (
|
18
|
+
register_extrinsic,
|
19
|
+
burned_register_extrinsic,
|
20
|
+
)
|
21
|
+
from bittensor_cli.src.bittensor.extrinsics.root import root_register_extrinsic
|
22
|
+
from rich.live import Live
|
23
|
+
from bittensor_cli.src.bittensor.minigraph import MiniGraph
|
24
|
+
from bittensor_cli.src.commands.wallets import set_id, get_id
|
25
|
+
from bittensor_cli.src.bittensor.utils import (
|
26
|
+
console,
|
27
|
+
create_table,
|
28
|
+
err_console,
|
29
|
+
print_verbose,
|
30
|
+
print_error,
|
31
|
+
format_error_message,
|
32
|
+
get_metadata_table,
|
33
|
+
millify_tao,
|
34
|
+
render_table,
|
35
|
+
update_metadata_table,
|
36
|
+
prompt_for_identity,
|
37
|
+
get_subnet_name,
|
38
|
+
)
|
39
|
+
|
40
|
+
if TYPE_CHECKING:
|
41
|
+
from bittensor_cli.src.bittensor.subtensor_interface import SubtensorInterface
|
42
|
+
|
43
|
+
TAO_WEIGHT = 0.18
|
44
|
+
|
45
|
+
# helpers and extrinsics
|
46
|
+
|
47
|
+
|
48
|
+
async def register_subnetwork_extrinsic(
|
49
|
+
subtensor: "SubtensorInterface",
|
50
|
+
wallet: Wallet,
|
51
|
+
subnet_identity: dict,
|
52
|
+
wait_for_inclusion: bool = False,
|
53
|
+
wait_for_finalization: bool = True,
|
54
|
+
prompt: bool = False,
|
55
|
+
) -> bool:
|
56
|
+
"""Registers a new subnetwork.
|
57
|
+
|
58
|
+
wallet (bittensor.wallet):
|
59
|
+
bittensor wallet object.
|
60
|
+
wait_for_inclusion (bool):
|
61
|
+
If set, waits for the extrinsic to enter a block before returning ``true``, or returns ``false`` if the extrinsic fails to enter the block within the timeout.
|
62
|
+
wait_for_finalization (bool):
|
63
|
+
If set, waits for the extrinsic to be finalized on the chain before returning ``true``, or returns ``false`` if the extrinsic fails to be finalized within the timeout.
|
64
|
+
prompt (bool):
|
65
|
+
If true, the call waits for confirmation from the user before proceeding.
|
66
|
+
Returns:
|
67
|
+
success (bool):
|
68
|
+
Flag is ``true`` if extrinsic was finalized or included in the block.
|
69
|
+
If we did not wait for finalization / inclusion, the response is ``true``.
|
70
|
+
"""
|
71
|
+
|
72
|
+
async def _find_event_attributes_in_extrinsic_receipt(
|
73
|
+
response_, event_name: str
|
74
|
+
) -> list:
|
75
|
+
"""
|
76
|
+
Searches for the attributes of a specified event within an extrinsic receipt.
|
77
|
+
|
78
|
+
:param response_: The receipt of the extrinsic to be searched.
|
79
|
+
:param event_name: The name of the event to search for.
|
80
|
+
|
81
|
+
:return: A list of attributes for the specified event. Returns [-1] if the event is not found.
|
82
|
+
"""
|
83
|
+
for event in await response_.triggered_events:
|
84
|
+
# Access the event details
|
85
|
+
event_details = event["event"]
|
86
|
+
# Check if the event_id is 'NetworkAdded'
|
87
|
+
if event_details["event_id"] == event_name:
|
88
|
+
# Once found, you can access the attributes of the event_name
|
89
|
+
return event_details["attributes"]
|
90
|
+
return [-1]
|
91
|
+
|
92
|
+
print_verbose("Fetching balance")
|
93
|
+
your_balance = await subtensor.get_balance(wallet.coldkeypub.ss58_address)
|
94
|
+
|
95
|
+
print_verbose("Fetching burn_cost")
|
96
|
+
sn_burn_cost = await burn_cost(subtensor)
|
97
|
+
if sn_burn_cost > your_balance:
|
98
|
+
err_console.print(
|
99
|
+
f"Your balance of: [{COLOR_PALETTE['POOLS']['TAO']}]{your_balance}[{COLOR_PALETTE['POOLS']['TAO']}] is not enough to pay the subnet lock cost of: "
|
100
|
+
f"[{COLOR_PALETTE['POOLS']['TAO']}]{sn_burn_cost}[{COLOR_PALETTE['POOLS']['TAO']}]"
|
101
|
+
)
|
102
|
+
return False
|
103
|
+
|
104
|
+
if prompt:
|
105
|
+
console.print(
|
106
|
+
f"Your balance is: [{COLOR_PALETTE['POOLS']['TAO']}]{your_balance}"
|
107
|
+
)
|
108
|
+
if not Confirm.ask(
|
109
|
+
f"Do you want to register a subnet for [{COLOR_PALETTE['POOLS']['TAO']}]{sn_burn_cost}?"
|
110
|
+
):
|
111
|
+
return False
|
112
|
+
|
113
|
+
has_identity = any(subnet_identity.values())
|
114
|
+
if has_identity:
|
115
|
+
identity_data = {
|
116
|
+
"subnet_name": subnet_identity["subnet_name"].encode()
|
117
|
+
if subnet_identity.get("subnet_name")
|
118
|
+
else b"",
|
119
|
+
"github_repo": subnet_identity["github_repo"].encode()
|
120
|
+
if subnet_identity.get("github_repo")
|
121
|
+
else b"",
|
122
|
+
"subnet_contact": subnet_identity["subnet_contact"].encode()
|
123
|
+
if subnet_identity.get("subnet_contact")
|
124
|
+
else b"",
|
125
|
+
"subnet_url": subnet_identity["subnet_url"].encode()
|
126
|
+
if subnet_identity.get("subnet_url")
|
127
|
+
else b"",
|
128
|
+
"discord": subnet_identity["discord"].encode()
|
129
|
+
if subnet_identity.get("discord")
|
130
|
+
else b"",
|
131
|
+
"description": subnet_identity["description"].encode()
|
132
|
+
if subnet_identity.get("description")
|
133
|
+
else b"",
|
134
|
+
"additional": subnet_identity["additional"].encode()
|
135
|
+
if subnet_identity.get("additional")
|
136
|
+
else b"",
|
137
|
+
}
|
138
|
+
for field, value in identity_data.items():
|
139
|
+
max_size = 64 # bytes
|
140
|
+
if len(value) > max_size:
|
141
|
+
err_console.print(
|
142
|
+
f"[red]Error:[/red] Identity field [white]{field}[/white] must be <= {max_size} bytes.\n"
|
143
|
+
f"Value '{value.decode()}' is {len(value)} bytes."
|
144
|
+
)
|
145
|
+
return False
|
146
|
+
|
147
|
+
try:
|
148
|
+
wallet.unlock_coldkey()
|
149
|
+
except KeyFileError:
|
150
|
+
err_console.print("Error decrypting coldkey (possibly incorrect password)")
|
151
|
+
return False
|
152
|
+
|
153
|
+
with console.status(":satellite: Registering subnet...", spinner="earth"):
|
154
|
+
call_params = {
|
155
|
+
"hotkey": wallet.hotkey.ss58_address,
|
156
|
+
"mechid": 1,
|
157
|
+
}
|
158
|
+
call_function = "register_network"
|
159
|
+
if has_identity:
|
160
|
+
call_params["identity"] = identity_data
|
161
|
+
call_function = "register_network_with_identity"
|
162
|
+
|
163
|
+
substrate = subtensor.substrate
|
164
|
+
# create extrinsic call
|
165
|
+
call = await substrate.compose_call(
|
166
|
+
call_module="SubtensorModule",
|
167
|
+
call_function=call_function,
|
168
|
+
call_params=call_params,
|
169
|
+
)
|
170
|
+
extrinsic = await substrate.create_signed_extrinsic(
|
171
|
+
call=call, keypair=wallet.coldkey
|
172
|
+
)
|
173
|
+
response = await substrate.submit_extrinsic(
|
174
|
+
extrinsic,
|
175
|
+
wait_for_inclusion=wait_for_inclusion,
|
176
|
+
wait_for_finalization=wait_for_finalization,
|
177
|
+
)
|
178
|
+
|
179
|
+
# We only wait here if we expect finalization.
|
180
|
+
if not wait_for_finalization and not wait_for_inclusion:
|
181
|
+
return True
|
182
|
+
|
183
|
+
await response.process_events()
|
184
|
+
if not await response.is_success:
|
185
|
+
err_console.print(
|
186
|
+
f":cross_mark: [red]Failed[/red]: {format_error_message(await response.error_message, substrate)}"
|
187
|
+
)
|
188
|
+
await asyncio.sleep(0.5)
|
189
|
+
return False
|
190
|
+
|
191
|
+
# Successful registration, final check for membership
|
192
|
+
else:
|
193
|
+
attributes = await _find_event_attributes_in_extrinsic_receipt(
|
194
|
+
response, "NetworkAdded"
|
195
|
+
)
|
196
|
+
console.print(
|
197
|
+
f":white_heavy_check_mark: [dark_sea_green3]Registered subnetwork with netuid: {attributes[0]}"
|
198
|
+
)
|
199
|
+
return True
|
200
|
+
|
201
|
+
|
202
|
+
# commands
|
203
|
+
|
204
|
+
|
205
|
+
async def subnets_list(
|
206
|
+
subtensor: "SubtensorInterface",
|
207
|
+
reuse_last: bool,
|
208
|
+
html_output: bool,
|
209
|
+
no_cache: bool,
|
210
|
+
verbose: bool,
|
211
|
+
live: bool,
|
212
|
+
):
|
213
|
+
"""List all subnet netuids in the network."""
|
214
|
+
|
215
|
+
async def fetch_subnet_data():
|
216
|
+
block_number = await subtensor.substrate.get_block_number(None)
|
217
|
+
subnets = await subtensor.all_subnets()
|
218
|
+
|
219
|
+
# Sort subnets by market cap, keeping the root subnet in the first position
|
220
|
+
root_subnet = next(s for s in subnets if s.netuid == 0)
|
221
|
+
other_subnets = sorted(
|
222
|
+
[s for s in subnets if s.netuid != 0],
|
223
|
+
key=lambda x: (x.alpha_in.tao + x.alpha_out.tao) * x.price.tao,
|
224
|
+
reverse=True,
|
225
|
+
)
|
226
|
+
sorted_subnets = [root_subnet] + other_subnets
|
227
|
+
return sorted_subnets, block_number
|
228
|
+
|
229
|
+
def calculate_emission_stats(
|
230
|
+
subnets: list, block_number: int
|
231
|
+
) -> tuple[Balance, str]:
|
232
|
+
# We do not include the root subnet in the emission calculation
|
233
|
+
total_tao_emitted = sum(
|
234
|
+
subnet.tao_in.tao for subnet in subnets if subnet.netuid != 0
|
235
|
+
)
|
236
|
+
emission_percentage = (total_tao_emitted / block_number) * 100
|
237
|
+
percentage_color = "dark_sea_green" if emission_percentage < 100 else "red"
|
238
|
+
formatted_percentage = (
|
239
|
+
f"[{percentage_color}]{emission_percentage:.2f}%[/{percentage_color}]"
|
240
|
+
)
|
241
|
+
if not verbose:
|
242
|
+
percentage_string = f"τ {millify_tao(total_tao_emitted)}/{millify_tao(block_number)} ({formatted_percentage})"
|
243
|
+
else:
|
244
|
+
percentage_string = (
|
245
|
+
f"τ {total_tao_emitted:.1f}/{block_number} ({formatted_percentage})"
|
246
|
+
)
|
247
|
+
return total_tao_emitted, percentage_string
|
248
|
+
|
249
|
+
def define_table(
|
250
|
+
total_emissions: float,
|
251
|
+
total_rate: float,
|
252
|
+
total_netuids: int,
|
253
|
+
tao_emission_percentage: str,
|
254
|
+
):
|
255
|
+
table = Table(
|
256
|
+
title=f"\n[{COLOR_PALETTE['GENERAL']['HEADER']}]Subnets"
|
257
|
+
f"\nNetwork: [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{subtensor.network}\n\n",
|
258
|
+
show_footer=True,
|
259
|
+
show_edge=False,
|
260
|
+
header_style="bold white",
|
261
|
+
border_style="bright_black",
|
262
|
+
style="bold",
|
263
|
+
title_justify="center",
|
264
|
+
show_lines=False,
|
265
|
+
pad_edge=True,
|
266
|
+
)
|
267
|
+
|
268
|
+
table.add_column(
|
269
|
+
"[bold white]Netuid",
|
270
|
+
style="grey89",
|
271
|
+
justify="center",
|
272
|
+
footer=str(total_netuids),
|
273
|
+
)
|
274
|
+
table.add_column("[bold white]Name", style="cyan", justify="left")
|
275
|
+
table.add_column(
|
276
|
+
f"[bold white]Price \n({Balance.get_unit(0)}_in/{Balance.get_unit(1)}_in)",
|
277
|
+
style="dark_sea_green2",
|
278
|
+
justify="left",
|
279
|
+
footer=f"τ {total_rate}",
|
280
|
+
)
|
281
|
+
table.add_column(
|
282
|
+
f"[bold white]Market Cap \n({Balance.get_unit(1)} * Price)",
|
283
|
+
style="steel_blue3",
|
284
|
+
justify="left",
|
285
|
+
)
|
286
|
+
table.add_column(
|
287
|
+
f"[bold white]Emission ({Balance.get_unit(0)})",
|
288
|
+
style=COLOR_PALETTE["POOLS"]["EMISSION"],
|
289
|
+
justify="left",
|
290
|
+
footer=f"τ {total_emissions}",
|
291
|
+
)
|
292
|
+
table.add_column(
|
293
|
+
f"[bold white]P ({Balance.get_unit(0)}_in, {Balance.get_unit(1)}_in)",
|
294
|
+
style=COLOR_PALETTE["STAKE"]["TAO"],
|
295
|
+
justify="left",
|
296
|
+
footer=f"{tao_emission_percentage}",
|
297
|
+
)
|
298
|
+
table.add_column(
|
299
|
+
f"[bold white]Stake ({Balance.get_unit(1)}_out)",
|
300
|
+
style=COLOR_PALETTE["STAKE"]["STAKE_ALPHA"],
|
301
|
+
justify="left",
|
302
|
+
)
|
303
|
+
table.add_column(
|
304
|
+
f"[bold white]Supply ({Balance.get_unit(1)})",
|
305
|
+
style=COLOR_PALETTE["POOLS"]["ALPHA_IN"],
|
306
|
+
justify="left",
|
307
|
+
)
|
308
|
+
|
309
|
+
table.add_column(
|
310
|
+
"[bold white]Tempo (k/n)",
|
311
|
+
style=COLOR_PALETTE["GENERAL"]["TEMPO"],
|
312
|
+
justify="left",
|
313
|
+
overflow="fold",
|
314
|
+
)
|
315
|
+
return table
|
316
|
+
|
317
|
+
# Non-live mode
|
318
|
+
def create_table(subnets, block_number):
|
319
|
+
rows = []
|
320
|
+
_, percentage_string = calculate_emission_stats(subnets, block_number)
|
321
|
+
|
322
|
+
for subnet in subnets:
|
323
|
+
netuid = subnet.netuid
|
324
|
+
symbol = f"{subnet.symbol}\u200e"
|
325
|
+
|
326
|
+
if netuid == 0:
|
327
|
+
emission_tao = 0.0
|
328
|
+
else:
|
329
|
+
emission_tao = subnet.tao_in_emission.tao
|
330
|
+
|
331
|
+
alpha_in_value = (
|
332
|
+
f"{millify_tao(subnet.alpha_in.tao)}"
|
333
|
+
if not verbose
|
334
|
+
else f"{subnet.alpha_in.tao:,.4f}"
|
335
|
+
)
|
336
|
+
alpha_out_value = (
|
337
|
+
f"{millify_tao(subnet.alpha_out.tao)}"
|
338
|
+
if not verbose
|
339
|
+
else f"{subnet.alpha_out.tao:,.4f}"
|
340
|
+
)
|
341
|
+
price_value = f"{subnet.price.tao:,.4f}"
|
342
|
+
|
343
|
+
# Market Cap
|
344
|
+
market_cap = (subnet.alpha_in.tao + subnet.alpha_out.tao) * subnet.price.tao
|
345
|
+
market_cap_value = (
|
346
|
+
f"{millify_tao(market_cap)}" if not verbose else f"{market_cap:,.4f}"
|
347
|
+
)
|
348
|
+
|
349
|
+
# Liquidity
|
350
|
+
tao_in_cell = (
|
351
|
+
(
|
352
|
+
f"τ {millify_tao(subnet.tao_in.tao)}"
|
353
|
+
if not verbose
|
354
|
+
else f"τ {subnet.tao_in.tao:,.4f}"
|
355
|
+
)
|
356
|
+
if netuid != 0
|
357
|
+
else "-"
|
358
|
+
)
|
359
|
+
alpha_in_cell = f"{alpha_in_value} {symbol}" if netuid != 0 else "-"
|
360
|
+
liquidity_cell = f"{tao_in_cell}, {alpha_in_cell}"
|
361
|
+
|
362
|
+
# Supply
|
363
|
+
supply = subnet.alpha_in.tao + subnet.alpha_out.tao
|
364
|
+
supply_value = f"{millify_tao(supply)}" if not verbose else f"{supply:,.4f}"
|
365
|
+
|
366
|
+
# Prepare cells
|
367
|
+
netuid_cell = str(netuid)
|
368
|
+
subnet_name_cell = (
|
369
|
+
f"[{COLOR_PALETTE['GENERAL']['SYMBOL']}]{subnet.symbol if netuid != 0 else 'τ'}[/{COLOR_PALETTE['GENERAL']['SYMBOL']}]"
|
370
|
+
f" {get_subnet_name(subnet)}"
|
371
|
+
)
|
372
|
+
emission_cell = f"τ {emission_tao:,.4f}"
|
373
|
+
price_cell = f"{price_value} τ/{symbol}"
|
374
|
+
alpha_out_cell = (
|
375
|
+
f"{alpha_out_value} {symbol}"
|
376
|
+
if netuid != 0
|
377
|
+
else f"{symbol} {alpha_out_value}"
|
378
|
+
)
|
379
|
+
market_cap_cell = f"τ {market_cap_value}"
|
380
|
+
supply_cell = f"{supply_value} {symbol} [#806DAF]/21M"
|
381
|
+
|
382
|
+
if netuid != 0:
|
383
|
+
tempo_cell = f"{subnet.blocks_since_last_step}/{subnet.tempo}"
|
384
|
+
else:
|
385
|
+
tempo_cell = "-/-"
|
386
|
+
|
387
|
+
rows.append(
|
388
|
+
(
|
389
|
+
netuid_cell, # Netuid
|
390
|
+
subnet_name_cell, # Name
|
391
|
+
price_cell, # Rate τ_in/α_in
|
392
|
+
market_cap_cell, # Market Cap
|
393
|
+
emission_cell, # Emission (τ)
|
394
|
+
liquidity_cell, # Liquidity (t_in, a_in)
|
395
|
+
alpha_out_cell, # Stake α_out
|
396
|
+
supply_cell, # Supply
|
397
|
+
tempo_cell, # Tempo k/n
|
398
|
+
)
|
399
|
+
)
|
400
|
+
|
401
|
+
total_emissions = round(
|
402
|
+
sum(subnet.tao_in_emission.tao for subnet in subnets if subnet.netuid != 0),
|
403
|
+
4,
|
404
|
+
)
|
405
|
+
total_rate = round(
|
406
|
+
sum(float(subnet.price.tao) for subnet in subnets if subnet.netuid != 0), 4
|
407
|
+
)
|
408
|
+
total_netuids = len(subnets)
|
409
|
+
table = define_table(
|
410
|
+
total_emissions, total_rate, total_netuids, percentage_string
|
411
|
+
)
|
412
|
+
|
413
|
+
for row in rows:
|
414
|
+
table.add_row(*row)
|
415
|
+
return table
|
416
|
+
|
417
|
+
# Live mode
|
418
|
+
def create_table_live(subnets, previous_data, block_number):
|
419
|
+
def format_cell(
|
420
|
+
value, previous_value, unit="", unit_first=False, precision=4, millify=False
|
421
|
+
):
|
422
|
+
if previous_value is not None:
|
423
|
+
change = value - previous_value
|
424
|
+
if abs(change) > 10 ** (-precision):
|
425
|
+
formatted_change = (
|
426
|
+
f"{change:.{precision}f}"
|
427
|
+
if not millify
|
428
|
+
else f"{millify_tao(change)}"
|
429
|
+
)
|
430
|
+
change_text = (
|
431
|
+
f" [pale_green3](+{formatted_change})[/pale_green3]"
|
432
|
+
if change > 0
|
433
|
+
else f" [hot_pink3]({formatted_change})[/hot_pink3]"
|
434
|
+
)
|
435
|
+
else:
|
436
|
+
change_text = ""
|
437
|
+
else:
|
438
|
+
change_text = ""
|
439
|
+
formatted_value = (
|
440
|
+
f"{value:,.{precision}f}" if not millify else millify_tao(value)
|
441
|
+
)
|
442
|
+
return (
|
443
|
+
f"{formatted_value} {unit}{change_text}"
|
444
|
+
if not unit_first
|
445
|
+
else f"{unit} {formatted_value}{change_text}"
|
446
|
+
)
|
447
|
+
|
448
|
+
def format_liquidity_cell(
|
449
|
+
tao_val,
|
450
|
+
alpha_val,
|
451
|
+
prev_tao,
|
452
|
+
prev_alpha,
|
453
|
+
symbol,
|
454
|
+
precision=4,
|
455
|
+
millify=False,
|
456
|
+
netuid=None,
|
457
|
+
):
|
458
|
+
"""Format liquidity cell with combined changes"""
|
459
|
+
|
460
|
+
tao_str = (
|
461
|
+
f"τ {millify_tao(tao_val)}"
|
462
|
+
if millify
|
463
|
+
else f"τ {tao_val:,.{precision}f}"
|
464
|
+
)
|
465
|
+
_alpha_str = f"{millify_tao(alpha_val) if millify else f'{alpha_val:,.{precision}f}'}"
|
466
|
+
alpha_str = (
|
467
|
+
f"{_alpha_str} {symbol}" if netuid != 0 else f"{symbol} {_alpha_str}"
|
468
|
+
)
|
469
|
+
|
470
|
+
# Show delta
|
471
|
+
if prev_tao is not None and prev_alpha is not None:
|
472
|
+
tao_change = tao_val - prev_tao
|
473
|
+
alpha_change = alpha_val - prev_alpha
|
474
|
+
|
475
|
+
# Show changes if either value changed
|
476
|
+
if abs(tao_change) > 10 ** (-precision) or abs(alpha_change) > 10 ** (
|
477
|
+
-precision
|
478
|
+
):
|
479
|
+
if millify:
|
480
|
+
tao_change_str = (
|
481
|
+
f"+{millify_tao(tao_change)}"
|
482
|
+
if tao_change > 0
|
483
|
+
else f"{millify_tao(tao_change)}"
|
484
|
+
)
|
485
|
+
alpha_change_str = (
|
486
|
+
f"+{millify_tao(alpha_change)}"
|
487
|
+
if alpha_change > 0
|
488
|
+
else f"{millify_tao(alpha_change)}"
|
489
|
+
)
|
490
|
+
else:
|
491
|
+
tao_change_str = (
|
492
|
+
f"+{tao_change:.{precision}f}"
|
493
|
+
if tao_change > 0
|
494
|
+
else f"{tao_change:.{precision}f}"
|
495
|
+
)
|
496
|
+
alpha_change_str = (
|
497
|
+
f"+{alpha_change:.{precision}f}"
|
498
|
+
if alpha_change > 0
|
499
|
+
else f"{alpha_change:.{precision}f}"
|
500
|
+
)
|
501
|
+
|
502
|
+
changes_str = (
|
503
|
+
f" [pale_green3]({tao_change_str}[/pale_green3]"
|
504
|
+
if tao_change > 0
|
505
|
+
else f" [hot_pink3]({tao_change_str}[/hot_pink3]"
|
506
|
+
if tao_change < 0
|
507
|
+
else f" [white]({tao_change_str}[/white]"
|
508
|
+
)
|
509
|
+
changes_str += (
|
510
|
+
f"[pale_green3],{alpha_change_str})[/pale_green3]"
|
511
|
+
if alpha_change > 0
|
512
|
+
else f"[hot_pink3],{alpha_change_str})[/hot_pink3]"
|
513
|
+
if alpha_change < 0
|
514
|
+
else f"[white],{alpha_change_str})[/white]"
|
515
|
+
)
|
516
|
+
return f"{tao_str}, {alpha_str}{changes_str}"
|
517
|
+
|
518
|
+
return f"{tao_str}, {alpha_str}"
|
519
|
+
|
520
|
+
rows = []
|
521
|
+
current_data = {} # To store current values for comparison in the next update
|
522
|
+
_, percentage_string = calculate_emission_stats(subnets, block_number)
|
523
|
+
|
524
|
+
for subnet in subnets:
|
525
|
+
netuid = subnet.netuid
|
526
|
+
symbol = f"{subnet.symbol}\u200e"
|
527
|
+
|
528
|
+
if netuid == 0:
|
529
|
+
emission_tao = 0.0
|
530
|
+
else:
|
531
|
+
emission_tao = subnet.tao_in_emission.tao
|
532
|
+
|
533
|
+
market_cap = (subnet.alpha_in.tao + subnet.alpha_out.tao) * subnet.price.tao
|
534
|
+
supply = subnet.alpha_in.tao + subnet.alpha_out.tao
|
535
|
+
|
536
|
+
# Store current values for comparison
|
537
|
+
current_data[netuid] = {
|
538
|
+
"market_cap": market_cap,
|
539
|
+
"emission_tao": emission_tao,
|
540
|
+
"alpha_out": subnet.alpha_out.tao,
|
541
|
+
"tao_in": subnet.tao_in.tao,
|
542
|
+
"alpha_in": subnet.alpha_in.tao,
|
543
|
+
"price": subnet.price.tao,
|
544
|
+
"supply": supply,
|
545
|
+
"blocks_since_last_step": subnet.blocks_since_last_step,
|
546
|
+
}
|
547
|
+
prev = previous_data.get(netuid, {}) if previous_data else {}
|
548
|
+
|
549
|
+
# Prepare cells
|
550
|
+
if netuid == 0:
|
551
|
+
unit_first = True
|
552
|
+
else:
|
553
|
+
unit_first = False
|
554
|
+
|
555
|
+
netuid_cell = str(netuid)
|
556
|
+
subnet_name_cell = (
|
557
|
+
f"[{COLOR_PALETTE['GENERAL']['SYMBOL']}]{subnet.symbol if netuid != 0 else 'τ'}[/{COLOR_PALETTE['GENERAL']['SYMBOL']}]"
|
558
|
+
f" {get_subnet_name(subnet)}"
|
559
|
+
)
|
560
|
+
emission_cell = format_cell(
|
561
|
+
emission_tao,
|
562
|
+
prev.get("emission_tao"),
|
563
|
+
unit="τ",
|
564
|
+
unit_first=True,
|
565
|
+
precision=4,
|
566
|
+
)
|
567
|
+
price_cell = format_cell(
|
568
|
+
subnet.price.tao,
|
569
|
+
prev.get("price"),
|
570
|
+
unit=f"τ/{symbol}",
|
571
|
+
precision=4,
|
572
|
+
millify=False,
|
573
|
+
)
|
574
|
+
|
575
|
+
alpha_out_cell = format_cell(
|
576
|
+
subnet.alpha_out.tao,
|
577
|
+
prev.get("alpha_out"),
|
578
|
+
unit=f"{symbol}",
|
579
|
+
unit_first=unit_first,
|
580
|
+
precision=5,
|
581
|
+
millify=True if not verbose else False,
|
582
|
+
)
|
583
|
+
liquidity_cell = (
|
584
|
+
format_liquidity_cell(
|
585
|
+
subnet.tao_in.tao,
|
586
|
+
subnet.alpha_in.tao,
|
587
|
+
prev.get("tao_in"),
|
588
|
+
prev.get("alpha_in"),
|
589
|
+
symbol,
|
590
|
+
precision=4,
|
591
|
+
millify=not verbose,
|
592
|
+
netuid=netuid,
|
593
|
+
)
|
594
|
+
if netuid != 0
|
595
|
+
else "-, -"
|
596
|
+
)
|
597
|
+
|
598
|
+
market_cap_cell = format_cell(
|
599
|
+
market_cap,
|
600
|
+
prev.get("market_cap"),
|
601
|
+
unit="τ",
|
602
|
+
unit_first=True,
|
603
|
+
precision=4,
|
604
|
+
millify=True if not verbose else False,
|
605
|
+
)
|
606
|
+
|
607
|
+
# Supply cell
|
608
|
+
supply_cell = format_cell(
|
609
|
+
supply,
|
610
|
+
prev.get("supply"),
|
611
|
+
unit=f"{symbol} [#806DAF]/21M",
|
612
|
+
unit_first=False,
|
613
|
+
precision=2,
|
614
|
+
millify=True if not verbose else False,
|
615
|
+
)
|
616
|
+
|
617
|
+
# Tempo cell
|
618
|
+
prev_blocks_since_last_step = prev.get("blocks_since_last_step")
|
619
|
+
if prev_blocks_since_last_step is not None:
|
620
|
+
if subnet.blocks_since_last_step >= prev_blocks_since_last_step:
|
621
|
+
block_change = (
|
622
|
+
subnet.blocks_since_last_step - prev_blocks_since_last_step
|
623
|
+
)
|
624
|
+
else:
|
625
|
+
# Tempo restarted
|
626
|
+
block_change = (
|
627
|
+
subnet.blocks_since_last_step + subnet.tempo + 1
|
628
|
+
) - prev_blocks_since_last_step
|
629
|
+
if block_change > 0:
|
630
|
+
block_change_text = f" [pale_green3](+{block_change})[/pale_green3]"
|
631
|
+
elif block_change < 0:
|
632
|
+
block_change_text = f" [hot_pink3]({block_change})[/hot_pink3]"
|
633
|
+
else:
|
634
|
+
block_change_text = ""
|
635
|
+
else:
|
636
|
+
block_change_text = ""
|
637
|
+
tempo_cell = (
|
638
|
+
(f"{subnet.blocks_since_last_step}/{subnet.tempo}{block_change_text}")
|
639
|
+
if netuid != 0
|
640
|
+
else "-/-"
|
641
|
+
)
|
642
|
+
|
643
|
+
rows.append(
|
644
|
+
(
|
645
|
+
netuid_cell, # Netuid
|
646
|
+
subnet_name_cell, # Name
|
647
|
+
price_cell, # Rate τ_in/α_in
|
648
|
+
market_cap_cell, # Market Cap
|
649
|
+
emission_cell, # Emission (τ)
|
650
|
+
liquidity_cell, # Liquidity (t_in, a_in)
|
651
|
+
alpha_out_cell, # Stake α_out
|
652
|
+
supply_cell, # Supply
|
653
|
+
tempo_cell, # Tempo k/n
|
654
|
+
)
|
655
|
+
)
|
656
|
+
|
657
|
+
# Calculate totals
|
658
|
+
total_netuids = len(subnets)
|
659
|
+
_total_emissions = sum(
|
660
|
+
subnet.tao_in_emission.tao for subnet in subnets if subnet.netuid != 0
|
661
|
+
)
|
662
|
+
total_emissions = (
|
663
|
+
f"{millify_tao(_total_emissions)}"
|
664
|
+
if not verbose
|
665
|
+
else f"{_total_emissions:,.2f}"
|
666
|
+
)
|
667
|
+
|
668
|
+
total_rate = sum(subnet.price.tao for subnet in subnets if subnet.netuid != 0)
|
669
|
+
total_rate = (
|
670
|
+
f"{millify_tao(total_rate)}" if not verbose else f"{total_rate:,.2f}"
|
671
|
+
)
|
672
|
+
table = define_table(
|
673
|
+
total_emissions, total_rate, total_netuids, percentage_string
|
674
|
+
)
|
675
|
+
|
676
|
+
for row in rows:
|
677
|
+
table.add_row(*row)
|
678
|
+
return table, current_data
|
679
|
+
|
680
|
+
# Live mode
|
681
|
+
if live:
|
682
|
+
refresh_interval = 10 # seconds
|
683
|
+
|
684
|
+
progress = Progress(
|
685
|
+
TextColumn("[progress.description]{task.description}"),
|
686
|
+
BarColumn(bar_width=20, style="green", complete_style="green"),
|
687
|
+
TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
|
688
|
+
console=console,
|
689
|
+
auto_refresh=True,
|
690
|
+
)
|
691
|
+
progress_task = progress.add_task("Updating:", total=refresh_interval)
|
692
|
+
|
693
|
+
previous_block = None
|
694
|
+
current_block = None
|
695
|
+
previous_data = None
|
696
|
+
|
697
|
+
with Live(console=console, screen=True, auto_refresh=True) as live:
|
698
|
+
try:
|
699
|
+
while True:
|
700
|
+
subnets, block_number = await fetch_subnet_data()
|
701
|
+
|
702
|
+
# Update block numbers
|
703
|
+
previous_block = current_block
|
704
|
+
current_block = block_number
|
705
|
+
new_blocks = (
|
706
|
+
"N/A"
|
707
|
+
if previous_block is None
|
708
|
+
else str(current_block - previous_block)
|
709
|
+
)
|
710
|
+
|
711
|
+
table, current_data = create_table_live(
|
712
|
+
subnets, previous_data, block_number
|
713
|
+
)
|
714
|
+
previous_data = current_data
|
715
|
+
progress.reset(progress_task)
|
716
|
+
start_time = asyncio.get_event_loop().time()
|
717
|
+
|
718
|
+
block_info = (
|
719
|
+
f"Previous: [dark_sea_green]{previous_block if previous_block else 'N/A'}[/dark_sea_green] "
|
720
|
+
f"Current: [dark_sea_green]{current_block}[/dark_sea_green] "
|
721
|
+
f"Diff: [dark_sea_green]{new_blocks}[/dark_sea_green] "
|
722
|
+
)
|
723
|
+
|
724
|
+
message = f"Live view active. Press [bold red]Ctrl + C[/bold red] to exit\n{block_info}"
|
725
|
+
|
726
|
+
live_render = Group(message, progress, table)
|
727
|
+
live.update(live_render)
|
728
|
+
|
729
|
+
while not progress.finished:
|
730
|
+
await asyncio.sleep(0.1)
|
731
|
+
elapsed = asyncio.get_event_loop().time() - start_time
|
732
|
+
progress.update(progress_task, completed=elapsed)
|
733
|
+
|
734
|
+
except KeyboardInterrupt:
|
735
|
+
pass # Ctrl + C
|
736
|
+
else:
|
737
|
+
# Non-live mode
|
738
|
+
subnets, block_number = await fetch_subnet_data()
|
739
|
+
table = create_table(subnets, block_number)
|
740
|
+
console.print(table)
|
741
|
+
|
742
|
+
return
|
743
|
+
# TODO: Temporarily returning till we update docs
|
744
|
+
display_table = Prompt.ask(
|
745
|
+
"\nPress Enter to view column descriptions or type 'q' to skip:",
|
746
|
+
choices=["", "q"],
|
747
|
+
default="",
|
748
|
+
).lower()
|
749
|
+
|
750
|
+
if display_table == "q":
|
751
|
+
console.print(
|
752
|
+
f"[{COLOR_PALETTE['GENERAL']['SUBHEADING_EXTRA_1']}]Column descriptions skipped."
|
753
|
+
)
|
754
|
+
else:
|
755
|
+
header = """
|
756
|
+
[bold white]Description[/bold white]: The table displays information about each subnet. The columns are as follows:
|
757
|
+
"""
|
758
|
+
console.print(header)
|
759
|
+
description_table = Table(
|
760
|
+
show_header=False, box=box.SIMPLE, show_edge=False, show_lines=True
|
761
|
+
)
|
762
|
+
|
763
|
+
fields = [
|
764
|
+
("[bold tan]Netuid[/bold tan]", "The netuid of the subnet."),
|
765
|
+
(
|
766
|
+
"[bold tan]Symbol[/bold tan]",
|
767
|
+
"The symbol for the subnet's dynamic TAO token.",
|
768
|
+
),
|
769
|
+
(
|
770
|
+
"[bold tan]Emission (τ)[/bold tan]",
|
771
|
+
"Shows how the one τ per block emission is distributed among all the subnet pools. For each subnet, this fraction is first calculated by dividing the subnet's alpha token price by the sum of all alpha prices across all the subnets. This fraction of TAO is then added to the TAO Pool (τ_in) of the subnet. This can change every block. \nFor more, see [blue]https://docs.bittensor.com/dynamic-tao/dtao-guide#emissions[/blue].",
|
772
|
+
),
|
773
|
+
(
|
774
|
+
"[bold tan]TAO Pool (τ_in)[/bold tan]",
|
775
|
+
'Number of TAO in the TAO reserves of the pool for this subnet. Attached to every subnet is a subnet pool, containing a TAO reserve and the alpha reserve. See also "Alpha Pool (α_in)" description. This can change every block. \nFor more, see [blue]https://docs.bittensor.com/dynamic-tao/dtao-guide#subnet-pool[/blue].',
|
776
|
+
),
|
777
|
+
(
|
778
|
+
"[bold tan]Alpha Pool (α_in)[/bold tan]",
|
779
|
+
"Number of subnet alpha tokens in the alpha reserves of the pool for this subnet. This reserve, together with 'TAO Pool (τ_in)', form the subnet pool for every subnet. This can change every block. \nFor more, see [blue]https://docs.bittensor.com/dynamic-tao/dtao-guide#subnet-pool[/blue].",
|
780
|
+
),
|
781
|
+
(
|
782
|
+
"[bold tan]STAKE (α_out)[/bold tan]",
|
783
|
+
"Total stake in the subnet, expressed in the subnet's alpha token currency. This is the sum of all the stakes present in all the hotkeys in this subnet. This can change every block. \nFor more, see [blue]https://docs.bittensor.com/dynamic-tao/dtao-guide#stake-%CE%B1_out-or-alpha-out-%CE%B1_out[/blue].",
|
784
|
+
),
|
785
|
+
(
|
786
|
+
"[bold tan]RATE (τ_in/α_in)[/bold tan]",
|
787
|
+
"Exchange rate between TAO and subnet dTAO token. Calculated as the reserve ratio: (TAO Pool (τ_in) / Alpha Pool (α_in)). Note that the terms relative price, alpha token price, alpha price are the same as exchange rate. This rate can change every block. \nFor more, see [blue]https://docs.bittensor.com/dynamic-tao/dtao-guide#rate-%CF%84_in%CE%B1_in[/blue].",
|
788
|
+
),
|
789
|
+
(
|
790
|
+
"[bold tan]Tempo (k/n)[/bold tan]",
|
791
|
+
'The tempo status of the subnet. Represented as (k/n) where "k" is the number of blocks elapsed since the last tempo and "n" is the total number of blocks in the tempo. The number "n" is a subnet hyperparameter and does not change every block. \nFor more, see [blue]https://docs.bittensor.com/dynamic-tao/dtao-guide#tempo-kn[/blue].',
|
792
|
+
),
|
793
|
+
]
|
794
|
+
|
795
|
+
description_table.add_column("Field", no_wrap=True, style="bold tan")
|
796
|
+
description_table.add_column("Description", overflow="fold")
|
797
|
+
for field_name, description in fields:
|
798
|
+
description_table.add_row(field_name, description)
|
799
|
+
console.print(description_table)
|
800
|
+
|
801
|
+
|
802
|
+
async def show(
|
803
|
+
subtensor: "SubtensorInterface",
|
804
|
+
netuid: int,
|
805
|
+
sort: bool = False,
|
806
|
+
max_rows: Optional[int] = None,
|
807
|
+
delegate_selection: bool = False,
|
808
|
+
verbose: bool = False,
|
809
|
+
prompt: bool = True,
|
810
|
+
) -> Optional[str]:
|
811
|
+
async def show_root():
|
812
|
+
block_hash = await subtensor.substrate.get_chain_head()
|
813
|
+
all_subnets = await subtensor.all_subnets(block_hash=block_hash)
|
814
|
+
root_info = next((s for s in all_subnets if s.netuid == 0), None)
|
815
|
+
if root_info is None:
|
816
|
+
print_error("The root subnet does not exist")
|
817
|
+
raise typer.Exit()
|
818
|
+
|
819
|
+
root_state, identities, old_identities = await asyncio.gather(
|
820
|
+
subtensor.get_subnet_state(netuid=0, block_hash=block_hash),
|
821
|
+
subtensor.query_all_identities(block_hash=block_hash),
|
822
|
+
subtensor.get_delegate_identities(block_hash=block_hash),
|
823
|
+
)
|
824
|
+
|
825
|
+
if root_state is None:
|
826
|
+
err_console.print("The root subnet does not exist")
|
827
|
+
return
|
828
|
+
|
829
|
+
if len(root_state.hotkeys) == 0:
|
830
|
+
err_console.print(
|
831
|
+
"The root-subnet is currently empty with 0 UIDs registered."
|
832
|
+
)
|
833
|
+
return
|
834
|
+
|
835
|
+
tao_sum = sum(
|
836
|
+
[root_state.tao_stake[idx].tao for idx in range(len(root_state.tao_stake))]
|
837
|
+
)
|
838
|
+
|
839
|
+
table = Table(
|
840
|
+
title=f"[{COLOR_PALETTE['GENERAL']['HEADER']}]Root Network\n[{COLOR_PALETTE['GENERAL']['SUBHEADING']}]Network: {subtensor.network}[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}]\n",
|
841
|
+
show_footer=True,
|
842
|
+
show_edge=False,
|
843
|
+
header_style="bold white",
|
844
|
+
border_style="bright_black",
|
845
|
+
style="bold",
|
846
|
+
title_justify="center",
|
847
|
+
show_lines=False,
|
848
|
+
pad_edge=True,
|
849
|
+
)
|
850
|
+
|
851
|
+
table.add_column("[bold white]Position", style="white", justify="center")
|
852
|
+
table.add_column(
|
853
|
+
"Tao (τ)",
|
854
|
+
style=COLOR_PALETTE["POOLS"]["EXTRA_2"],
|
855
|
+
no_wrap=True,
|
856
|
+
justify="right",
|
857
|
+
footer=f"{tao_sum:.4f} τ" if verbose else f"{millify_tao(tao_sum)} τ",
|
858
|
+
)
|
859
|
+
table.add_column(
|
860
|
+
f"[bold white]Emission ({Balance.get_unit(0)}/block)",
|
861
|
+
style=COLOR_PALETTE["POOLS"]["EMISSION"],
|
862
|
+
justify="center",
|
863
|
+
)
|
864
|
+
table.add_column(
|
865
|
+
"[bold white]Hotkey",
|
866
|
+
style=COLOR_PALETTE["GENERAL"]["HOTKEY"],
|
867
|
+
justify="center",
|
868
|
+
)
|
869
|
+
table.add_column(
|
870
|
+
"[bold white]Coldkey",
|
871
|
+
style=COLOR_PALETTE["GENERAL"]["COLDKEY"],
|
872
|
+
justify="center",
|
873
|
+
)
|
874
|
+
table.add_column(
|
875
|
+
"[bold white]Identity",
|
876
|
+
style=COLOR_PALETTE["GENERAL"]["SYMBOL"],
|
877
|
+
justify="left",
|
878
|
+
)
|
879
|
+
|
880
|
+
sorted_hotkeys = sorted(
|
881
|
+
enumerate(root_state.hotkeys),
|
882
|
+
key=lambda x: root_state.tao_stake[x[0]],
|
883
|
+
reverse=True,
|
884
|
+
)
|
885
|
+
sorted_rows = []
|
886
|
+
sorted_hks_delegation = []
|
887
|
+
for pos, (idx, hk) in enumerate(sorted_hotkeys):
|
888
|
+
total_emission_per_block = 0
|
889
|
+
for netuid_ in range(len(all_subnets)):
|
890
|
+
subnet = all_subnets[netuid_]
|
891
|
+
emission_on_subnet = (
|
892
|
+
root_state.emission_history[netuid_][idx] / subnet.tempo
|
893
|
+
)
|
894
|
+
total_emission_per_block += subnet.alpha_to_tao(
|
895
|
+
Balance.from_rao(emission_on_subnet)
|
896
|
+
)
|
897
|
+
|
898
|
+
# Get identity for this validator
|
899
|
+
coldkey_identity = identities.get(root_state.coldkeys[idx], {}).get(
|
900
|
+
"name", ""
|
901
|
+
)
|
902
|
+
hotkey_identity = old_identities.get(root_state.hotkeys[idx])
|
903
|
+
validator_identity = (
|
904
|
+
coldkey_identity
|
905
|
+
if coldkey_identity
|
906
|
+
else (hotkey_identity.display if hotkey_identity else "")
|
907
|
+
)
|
908
|
+
|
909
|
+
sorted_rows.append(
|
910
|
+
(
|
911
|
+
str((pos + 1)), # Position
|
912
|
+
# f"τ {millify_tao(root_state.total_stake[idx].tao)}"
|
913
|
+
# if not verbose
|
914
|
+
# else f"{root_state.total_stake[idx]}", # Total Stake
|
915
|
+
# f"τ {root_state.alpha_stake[idx].tao:.4f}"
|
916
|
+
# if verbose
|
917
|
+
# else f"τ {millify_tao(root_state.alpha_stake[idx])}", # Alpha Stake
|
918
|
+
f"τ {root_state.tao_stake[idx].tao:.4f}"
|
919
|
+
if verbose
|
920
|
+
else f"τ {millify_tao(root_state.tao_stake[idx])}", # Tao Stake
|
921
|
+
f"{total_emission_per_block}", # Emission
|
922
|
+
f"{root_state.hotkeys[idx][:6]}"
|
923
|
+
if not verbose
|
924
|
+
else f"{root_state.hotkeys[idx]}", # Hotkey
|
925
|
+
f"{root_state.coldkeys[idx][:6]}"
|
926
|
+
if not verbose
|
927
|
+
else f"{root_state.coldkeys[idx]}", # Coldkey
|
928
|
+
validator_identity, # Identity
|
929
|
+
)
|
930
|
+
)
|
931
|
+
sorted_hks_delegation.append(root_state.hotkeys[idx])
|
932
|
+
|
933
|
+
for pos, row in enumerate(sorted_rows, 1):
|
934
|
+
table_row = []
|
935
|
+
# if delegate_selection:
|
936
|
+
# table_row.append(str(pos))
|
937
|
+
table_row.extend(row)
|
938
|
+
table.add_row(*table_row)
|
939
|
+
if delegate_selection and pos == max_rows:
|
940
|
+
break
|
941
|
+
# Print the table
|
942
|
+
console.print(table)
|
943
|
+
console.print("\n")
|
944
|
+
|
945
|
+
if not delegate_selection:
|
946
|
+
tao_pool = (
|
947
|
+
f"{millify_tao(root_info.tao_in.tao)}"
|
948
|
+
if not verbose
|
949
|
+
else f"{root_info.tao_in.tao:,.4f}"
|
950
|
+
)
|
951
|
+
stake = (
|
952
|
+
f"{millify_tao(root_info.alpha_out.tao)}"
|
953
|
+
if not verbose
|
954
|
+
else f"{root_info.alpha_out.tao:,.5f}"
|
955
|
+
)
|
956
|
+
rate = (
|
957
|
+
f"{millify_tao(root_info.price.tao)}"
|
958
|
+
if not verbose
|
959
|
+
else f"{root_info.price.tao:,.4f}"
|
960
|
+
)
|
961
|
+
console.print(
|
962
|
+
f"[{COLOR_PALETTE['GENERAL']['SUBHEADING']}]Root Network (Subnet 0)[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}]"
|
963
|
+
f"\n Rate: [{COLOR_PALETTE['GENERAL']['HOTKEY']}]{rate} τ/τ[/{COLOR_PALETTE['GENERAL']['HOTKEY']}]"
|
964
|
+
f"\n Emission: [{COLOR_PALETTE['GENERAL']['HOTKEY']}]τ 0[/{COLOR_PALETTE['GENERAL']['HOTKEY']}]"
|
965
|
+
f"\n TAO Pool: [{COLOR_PALETTE['POOLS']['ALPHA_IN']}]τ {tao_pool}[/{COLOR_PALETTE['POOLS']['ALPHA_IN']}]"
|
966
|
+
f"\n Stake: [{COLOR_PALETTE['STAKE']['STAKE_ALPHA']}]τ {stake}[/{COLOR_PALETTE['STAKE']['STAKE_ALPHA']}]"
|
967
|
+
f"\n Tempo: [{COLOR_PALETTE['STAKE']['STAKE_ALPHA']}]{root_info.blocks_since_last_step}/{root_info.tempo}[/{COLOR_PALETTE['STAKE']['STAKE_ALPHA']}]"
|
968
|
+
)
|
969
|
+
console.print(
|
970
|
+
"""
|
971
|
+
Description:
|
972
|
+
The table displays the root subnet participants and their metrics.
|
973
|
+
The columns are as follows:
|
974
|
+
- Position: The sorted position of the hotkey by total TAO.
|
975
|
+
- TAO: The sum of all TAO balances for this hotkey accross all subnets.
|
976
|
+
- Stake: The stake balance of this hotkey on root (measured in TAO).
|
977
|
+
- Emission: The emission accrued to this hotkey across all subnets every block measured in TAO.
|
978
|
+
- Hotkey: The hotkey ss58 address.
|
979
|
+
- Coldkey: The coldkey ss58 address.
|
980
|
+
"""
|
981
|
+
)
|
982
|
+
if delegate_selection:
|
983
|
+
valid_uids = [str(row[0]) for row in sorted_rows[:max_rows]]
|
984
|
+
while True:
|
985
|
+
selection = Prompt.ask(
|
986
|
+
"\nEnter the Position of the delegate you want to stake to [dim](or press Enter to cancel)[/dim]",
|
987
|
+
default="",
|
988
|
+
choices=[""] + valid_uids,
|
989
|
+
show_choices=False,
|
990
|
+
show_default=False,
|
991
|
+
)
|
992
|
+
|
993
|
+
if selection == "":
|
994
|
+
return None
|
995
|
+
|
996
|
+
position = int(selection)
|
997
|
+
idx = position - 1
|
998
|
+
original_idx = sorted_hotkeys[idx][0]
|
999
|
+
selected_hotkey = root_state.hotkeys[original_idx]
|
1000
|
+
|
1001
|
+
coldkey_identity = identities.get(
|
1002
|
+
root_state.coldkeys[original_idx], {}
|
1003
|
+
).get("name", "")
|
1004
|
+
hotkey_identity = old_identities.get(selected_hotkey)
|
1005
|
+
validator_identity = (
|
1006
|
+
coldkey_identity
|
1007
|
+
if coldkey_identity
|
1008
|
+
else (hotkey_identity.display if hotkey_identity else "")
|
1009
|
+
)
|
1010
|
+
identity_str = f" ({validator_identity})" if validator_identity else ""
|
1011
|
+
|
1012
|
+
console.print(
|
1013
|
+
f"\nSelected delegate: [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{selected_hotkey}{identity_str}"
|
1014
|
+
)
|
1015
|
+
return selected_hotkey
|
1016
|
+
|
1017
|
+
async def show_subnet(netuid_: int):
|
1018
|
+
if not await subtensor.subnet_exists(netuid=netuid):
|
1019
|
+
err_console.print(f"[red]Subnet {netuid} does not exist[/red]")
|
1020
|
+
raise typer.Exit()
|
1021
|
+
block_hash = await subtensor.substrate.get_chain_head()
|
1022
|
+
(
|
1023
|
+
subnet_info,
|
1024
|
+
subnet_state,
|
1025
|
+
identities,
|
1026
|
+
old_identities,
|
1027
|
+
current_burn_cost,
|
1028
|
+
) = await asyncio.gather(
|
1029
|
+
subtensor.subnet(netuid=netuid_, block_hash=block_hash),
|
1030
|
+
subtensor.get_subnet_state(netuid=netuid_, block_hash=block_hash),
|
1031
|
+
subtensor.query_all_identities(block_hash=block_hash),
|
1032
|
+
subtensor.get_delegate_identities(block_hash=block_hash),
|
1033
|
+
subtensor.get_hyperparameter(
|
1034
|
+
param_name="Burn", netuid=netuid_, block_hash=block_hash
|
1035
|
+
),
|
1036
|
+
)
|
1037
|
+
if subnet_state is None:
|
1038
|
+
print_error(f"Subnet {netuid_} does not exist")
|
1039
|
+
raise typer.Exit()
|
1040
|
+
|
1041
|
+
if subnet_info is None:
|
1042
|
+
print_error(f"Subnet {netuid_} does not exist")
|
1043
|
+
raise typer.Exit()
|
1044
|
+
|
1045
|
+
if len(subnet_state.hotkeys) == 0:
|
1046
|
+
print_error(f"Subnet {netuid_} is currently empty with 0 UIDs registered.")
|
1047
|
+
raise typer.Exit()
|
1048
|
+
|
1049
|
+
# Define table properties
|
1050
|
+
table = Table(
|
1051
|
+
title=f"[{COLOR_PALETTE['GENERAL']['HEADER']}]Subnet [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{netuid_}"
|
1052
|
+
f"{': ' + get_subnet_name(subnet_info)}"
|
1053
|
+
f"\nNetwork: [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{subtensor.network}[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}]\n",
|
1054
|
+
show_footer=True,
|
1055
|
+
show_edge=False,
|
1056
|
+
header_style="bold white",
|
1057
|
+
border_style="bright_black",
|
1058
|
+
style="bold",
|
1059
|
+
title_justify="center",
|
1060
|
+
show_lines=False,
|
1061
|
+
pad_edge=True,
|
1062
|
+
)
|
1063
|
+
|
1064
|
+
# For table footers
|
1065
|
+
alpha_sum = sum(
|
1066
|
+
[
|
1067
|
+
subnet_state.alpha_stake[idx].tao
|
1068
|
+
for idx in range(len(subnet_state.alpha_stake))
|
1069
|
+
]
|
1070
|
+
)
|
1071
|
+
stake_sum = sum(
|
1072
|
+
[
|
1073
|
+
subnet_state.total_stake[idx].tao
|
1074
|
+
for idx in range(len(subnet_state.total_stake))
|
1075
|
+
]
|
1076
|
+
)
|
1077
|
+
tao_sum = sum(
|
1078
|
+
[
|
1079
|
+
subnet_state.tao_stake[idx].tao * TAO_WEIGHT
|
1080
|
+
for idx in range(len(subnet_state.tao_stake))
|
1081
|
+
]
|
1082
|
+
)
|
1083
|
+
dividends_sum = sum(
|
1084
|
+
subnet_state.dividends[idx] for idx in range(len(subnet_state.dividends))
|
1085
|
+
)
|
1086
|
+
emission_sum = sum(
|
1087
|
+
[
|
1088
|
+
subnet_state.emission[idx].tao
|
1089
|
+
for idx in range(len(subnet_state.emission))
|
1090
|
+
]
|
1091
|
+
)
|
1092
|
+
|
1093
|
+
owner_hotkeys = await subtensor.get_owned_hotkeys(subnet_info.owner_coldkey)
|
1094
|
+
if subnet_info.owner_hotkey not in owner_hotkeys:
|
1095
|
+
owner_hotkeys.append(subnet_info.owner_hotkey)
|
1096
|
+
|
1097
|
+
owner_identity = identities.get(subnet_info.owner_coldkey, {}).get("name", "")
|
1098
|
+
if not owner_identity:
|
1099
|
+
# If no coldkey identity found, try each owner hotkey
|
1100
|
+
for hotkey in owner_hotkeys:
|
1101
|
+
if hotkey_identity := old_identities.get(hotkey):
|
1102
|
+
owner_identity = hotkey_identity.display
|
1103
|
+
break
|
1104
|
+
|
1105
|
+
sorted_indices = sorted(
|
1106
|
+
range(len(subnet_state.hotkeys)),
|
1107
|
+
key=lambda i: (
|
1108
|
+
# If sort is True, sort only by UIDs
|
1109
|
+
i
|
1110
|
+
if sort
|
1111
|
+
else (
|
1112
|
+
# Otherwise
|
1113
|
+
# Sort by owner status first
|
1114
|
+
not (
|
1115
|
+
subnet_state.coldkeys[i] == subnet_info.owner_coldkey
|
1116
|
+
or subnet_state.hotkeys[i] in owner_hotkeys
|
1117
|
+
),
|
1118
|
+
# Then sort by stake amount (higher stakes first)
|
1119
|
+
-subnet_state.total_stake[i].tao,
|
1120
|
+
)
|
1121
|
+
),
|
1122
|
+
)
|
1123
|
+
|
1124
|
+
rows = []
|
1125
|
+
for idx in sorted_indices:
|
1126
|
+
# Get identity for this uid
|
1127
|
+
coldkey_identity = identities.get(subnet_state.coldkeys[idx], {}).get(
|
1128
|
+
"name", ""
|
1129
|
+
)
|
1130
|
+
hotkey_identity = old_identities.get(subnet_state.hotkeys[idx])
|
1131
|
+
uid_identity = (
|
1132
|
+
coldkey_identity
|
1133
|
+
if coldkey_identity
|
1134
|
+
else (hotkey_identity.display if hotkey_identity else "~")
|
1135
|
+
)
|
1136
|
+
|
1137
|
+
if (
|
1138
|
+
subnet_state.coldkeys[idx] == subnet_info.owner_coldkey
|
1139
|
+
or subnet_state.hotkeys[idx] in owner_hotkeys
|
1140
|
+
):
|
1141
|
+
if uid_identity == "~":
|
1142
|
+
uid_identity = (
|
1143
|
+
"[dark_sea_green3](*Owner controlled)[/dark_sea_green3]"
|
1144
|
+
)
|
1145
|
+
else:
|
1146
|
+
uid_identity = (
|
1147
|
+
f"[dark_sea_green3]{uid_identity} (*Owner)[/dark_sea_green3]"
|
1148
|
+
)
|
1149
|
+
|
1150
|
+
# Modify tao stake with TAO_WEIGHT
|
1151
|
+
tao_stake = subnet_state.tao_stake[idx] * TAO_WEIGHT
|
1152
|
+
rows.append(
|
1153
|
+
(
|
1154
|
+
str(idx), # UID
|
1155
|
+
f"{subnet_state.total_stake[idx].tao:.4f} {subnet_info.symbol}"
|
1156
|
+
if verbose
|
1157
|
+
else f"{millify_tao(subnet_state.total_stake[idx])} {subnet_info.symbol}", # Stake
|
1158
|
+
f"{subnet_state.alpha_stake[idx].tao:.4f} {subnet_info.symbol}"
|
1159
|
+
if verbose
|
1160
|
+
else f"{millify_tao(subnet_state.alpha_stake[idx])} {subnet_info.symbol}", # Alpha Stake
|
1161
|
+
f"τ {tao_stake.tao:.4f}"
|
1162
|
+
if verbose
|
1163
|
+
else f"τ {millify_tao(tao_stake)}", # Tao Stake
|
1164
|
+
f"{subnet_state.dividends[idx]:.6f}", # Dividends
|
1165
|
+
f"{subnet_state.incentives[idx]:.6f}", # Incentive
|
1166
|
+
f"{Balance.from_tao(subnet_state.emission[idx].tao).set_unit(netuid_).tao:.6f} {subnet_info.symbol}", # Emissions
|
1167
|
+
f"{subnet_state.hotkeys[idx][:6]}"
|
1168
|
+
if not verbose
|
1169
|
+
else f"{subnet_state.hotkeys[idx]}", # Hotkey
|
1170
|
+
f"{subnet_state.coldkeys[idx][:6]}"
|
1171
|
+
if not verbose
|
1172
|
+
else f"{subnet_state.coldkeys[idx]}", # Coldkey
|
1173
|
+
uid_identity, # Identity
|
1174
|
+
)
|
1175
|
+
)
|
1176
|
+
|
1177
|
+
# Add columns to the table
|
1178
|
+
table.add_column("UID", style="grey89", no_wrap=True, justify="center")
|
1179
|
+
table.add_column(
|
1180
|
+
f"Stake ({Balance.get_unit(netuid_)})",
|
1181
|
+
style=COLOR_PALETTE["POOLS"]["ALPHA_IN"],
|
1182
|
+
no_wrap=True,
|
1183
|
+
justify="right",
|
1184
|
+
footer=f"{stake_sum:.4f} {subnet_info.symbol}"
|
1185
|
+
if verbose
|
1186
|
+
else f"{millify_tao(stake_sum)} {subnet_info.symbol}",
|
1187
|
+
)
|
1188
|
+
table.add_column(
|
1189
|
+
f"Alpha ({Balance.get_unit(netuid_)})",
|
1190
|
+
style=COLOR_PALETTE["POOLS"]["EXTRA_2"],
|
1191
|
+
no_wrap=True,
|
1192
|
+
justify="right",
|
1193
|
+
footer=f"{alpha_sum:.4f} {subnet_info.symbol}"
|
1194
|
+
if verbose
|
1195
|
+
else f"{millify_tao(alpha_sum)} {subnet_info.symbol}",
|
1196
|
+
)
|
1197
|
+
table.add_column(
|
1198
|
+
"Tao (τ)",
|
1199
|
+
style=COLOR_PALETTE["POOLS"]["EXTRA_2"],
|
1200
|
+
no_wrap=True,
|
1201
|
+
justify="right",
|
1202
|
+
footer=f"{tao_sum:.4f} {subnet_info.symbol}"
|
1203
|
+
if verbose
|
1204
|
+
else f"{millify_tao(tao_sum)} {subnet_info.symbol}",
|
1205
|
+
)
|
1206
|
+
table.add_column(
|
1207
|
+
"Dividends",
|
1208
|
+
style=COLOR_PALETTE["POOLS"]["EMISSION"],
|
1209
|
+
no_wrap=True,
|
1210
|
+
justify="center",
|
1211
|
+
footer=f"{dividends_sum:.3f}",
|
1212
|
+
)
|
1213
|
+
table.add_column("Incentive", style="#5fd7ff", no_wrap=True, justify="center")
|
1214
|
+
table.add_column(
|
1215
|
+
f"Emissions ({Balance.get_unit(netuid_)})",
|
1216
|
+
style=COLOR_PALETTE["POOLS"]["EMISSION"],
|
1217
|
+
no_wrap=True,
|
1218
|
+
justify="center",
|
1219
|
+
footer=str(Balance.from_tao(emission_sum).set_unit(subnet_info.netuid)),
|
1220
|
+
)
|
1221
|
+
table.add_column(
|
1222
|
+
"Hotkey",
|
1223
|
+
style=COLOR_PALETTE["GENERAL"]["HOTKEY"],
|
1224
|
+
no_wrap=True,
|
1225
|
+
justify="center",
|
1226
|
+
)
|
1227
|
+
table.add_column(
|
1228
|
+
"Coldkey",
|
1229
|
+
style=COLOR_PALETTE["GENERAL"]["COLDKEY"],
|
1230
|
+
no_wrap=True,
|
1231
|
+
justify="center",
|
1232
|
+
)
|
1233
|
+
table.add_column(
|
1234
|
+
"Identity",
|
1235
|
+
style=COLOR_PALETTE["GENERAL"]["SYMBOL"],
|
1236
|
+
no_wrap=True,
|
1237
|
+
justify="left",
|
1238
|
+
)
|
1239
|
+
for pos, row in enumerate(rows, 1):
|
1240
|
+
table_row = []
|
1241
|
+
table_row.extend(row)
|
1242
|
+
table.add_row(*table_row)
|
1243
|
+
if delegate_selection and pos == max_rows:
|
1244
|
+
break
|
1245
|
+
|
1246
|
+
# Print the table
|
1247
|
+
console.print("\n\n")
|
1248
|
+
console.print(table)
|
1249
|
+
console.print("\n")
|
1250
|
+
|
1251
|
+
if not delegate_selection:
|
1252
|
+
subnet_name_display = f": {get_subnet_name(subnet_info)}"
|
1253
|
+
tao_pool = (
|
1254
|
+
f"{millify_tao(subnet_info.tao_in.tao)}"
|
1255
|
+
if not verbose
|
1256
|
+
else f"{subnet_info.tao_in.tao:,.4f}"
|
1257
|
+
)
|
1258
|
+
alpha_pool = (
|
1259
|
+
f"{millify_tao(subnet_info.alpha_in.tao)}"
|
1260
|
+
if not verbose
|
1261
|
+
else f"{subnet_info.alpha_in.tao:,.4f}"
|
1262
|
+
)
|
1263
|
+
current_registration_burn = (
|
1264
|
+
Balance.from_rao(int(current_burn_cost))
|
1265
|
+
if current_burn_cost
|
1266
|
+
else Balance(0)
|
1267
|
+
)
|
1268
|
+
|
1269
|
+
console.print(
|
1270
|
+
f"[{COLOR_PALETTE['GENERAL']['SUBHEADING']}]Subnet {netuid_}{subnet_name_display}[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}]"
|
1271
|
+
f"\n Owner: [{COLOR_PALETTE['GENERAL']['COLDKEY']}]{subnet_info.owner_coldkey}{' (' + owner_identity + ')' if owner_identity else ''}[/{COLOR_PALETTE['GENERAL']['COLDKEY']}]"
|
1272
|
+
f"\n Rate: [{COLOR_PALETTE['GENERAL']['HOTKEY']}]{subnet_info.price.tao:.4f} τ/{subnet_info.symbol}[/{COLOR_PALETTE['GENERAL']['HOTKEY']}]"
|
1273
|
+
f"\n Emission: [{COLOR_PALETTE['GENERAL']['HOTKEY']}]τ {subnet_info.emission.tao:,.4f}[/{COLOR_PALETTE['GENERAL']['HOTKEY']}]"
|
1274
|
+
f"\n TAO Pool: [{COLOR_PALETTE['POOLS']['ALPHA_IN']}]τ {tao_pool}[/{COLOR_PALETTE['POOLS']['ALPHA_IN']}]"
|
1275
|
+
f"\n Alpha Pool: [{COLOR_PALETTE['POOLS']['ALPHA_IN']}]{alpha_pool} {subnet_info.symbol}[/{COLOR_PALETTE['POOLS']['ALPHA_IN']}]"
|
1276
|
+
# f"\n Stake: [{COLOR_PALETTE['STAKE']['STAKE_ALPHA']}]{subnet_info.alpha_out.tao:,.5f} {subnet_info.symbol}[/{COLOR_PALETTE['STAKE']['STAKE_ALPHA']}]"
|
1277
|
+
f"\n Tempo: [{COLOR_PALETTE['STAKE']['STAKE_ALPHA']}]{subnet_info.blocks_since_last_step}/{subnet_info.tempo}[/{COLOR_PALETTE['STAKE']['STAKE_ALPHA']}]"
|
1278
|
+
f"\n Registration cost (recycled): [{COLOR_PALETTE['STAKE']['STAKE_ALPHA']}]τ {current_registration_burn.tao:.4f}[/{COLOR_PALETTE['STAKE']['STAKE_ALPHA']}]"
|
1279
|
+
)
|
1280
|
+
# console.print(
|
1281
|
+
# """
|
1282
|
+
# Description:
|
1283
|
+
# The table displays the subnet participants and their metrics.
|
1284
|
+
# The columns are as follows:
|
1285
|
+
# - UID: The hotkey index in the subnet.
|
1286
|
+
# - TAO: The sum of all TAO balances for this hotkey accross all subnets.
|
1287
|
+
# - Stake: The stake balance of this hotkey on this subnet.
|
1288
|
+
# - Weight: The stake-weight of this hotkey on this subnet. Computed as an average of the normalized TAO and Stake columns of this subnet.
|
1289
|
+
# - Dividends: Validating dividends earned by the hotkey.
|
1290
|
+
# - Incentives: Mining incentives earned by the hotkey (always zero in the RAO demo.)
|
1291
|
+
# - Emission: The emission accrued to this hokey on this subnet every block (in staking units).
|
1292
|
+
# - Hotkey: The hotkey ss58 address.
|
1293
|
+
# - Coldkey: The coldkey ss58 address.
|
1294
|
+
# """
|
1295
|
+
# )
|
1296
|
+
|
1297
|
+
if delegate_selection:
|
1298
|
+
while True:
|
1299
|
+
valid_uids = [str(row[0]) for row in rows[:max_rows]]
|
1300
|
+
selection = Prompt.ask(
|
1301
|
+
"\nEnter the UID of the delegate you want to stake to [dim](or press Enter to cancel)[/dim]",
|
1302
|
+
default="",
|
1303
|
+
choices=[""] + valid_uids,
|
1304
|
+
show_choices=False,
|
1305
|
+
show_default=False,
|
1306
|
+
)
|
1307
|
+
|
1308
|
+
if selection == "":
|
1309
|
+
return None
|
1310
|
+
|
1311
|
+
try:
|
1312
|
+
uid = int(selection)
|
1313
|
+
# Check if the UID exists in the subnet
|
1314
|
+
if uid in [int(row[0]) for row in rows]:
|
1315
|
+
row_data = next(row for row in rows if int(row[0]) == uid)
|
1316
|
+
hotkey = subnet_state.hotkeys[uid]
|
1317
|
+
identity = "" if row_data[9] == "~" else row_data[9]
|
1318
|
+
identity_str = f" ({identity})" if identity else ""
|
1319
|
+
console.print(
|
1320
|
+
f"\nSelected delegate: [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{hotkey}{identity_str}"
|
1321
|
+
)
|
1322
|
+
return hotkey
|
1323
|
+
else:
|
1324
|
+
console.print(
|
1325
|
+
"[red]Invalid UID. Please enter a valid UID from the table above[/red]"
|
1326
|
+
)
|
1327
|
+
except ValueError:
|
1328
|
+
console.print("[red]Please enter a valid number[/red]")
|
1329
|
+
|
1330
|
+
return None
|
1331
|
+
|
1332
|
+
if netuid == 0:
|
1333
|
+
result = await show_root()
|
1334
|
+
return result
|
1335
|
+
else:
|
1336
|
+
result = await show_subnet(netuid)
|
1337
|
+
return result
|
1338
|
+
|
1339
|
+
|
1340
|
+
async def burn_cost(subtensor: "SubtensorInterface") -> Optional[Balance]:
|
1341
|
+
"""View locking cost of creating a new subnetwork"""
|
1342
|
+
with console.status(
|
1343
|
+
f":satellite:Retrieving lock cost from {subtensor.network}...",
|
1344
|
+
spinner="aesthetic",
|
1345
|
+
):
|
1346
|
+
burn_cost = await subtensor.burn_cost()
|
1347
|
+
if burn_cost:
|
1348
|
+
console.print(
|
1349
|
+
f"Subnet burn cost: [{COLOR_PALETTE['STAKE']['STAKE_AMOUNT']}]{burn_cost}"
|
1350
|
+
)
|
1351
|
+
return burn_cost
|
1352
|
+
else:
|
1353
|
+
err_console.print(
|
1354
|
+
"Subnet burn cost: [red]Failed to get subnet burn cost[/red]"
|
1355
|
+
)
|
1356
|
+
return None
|
1357
|
+
|
1358
|
+
|
1359
|
+
async def create(
|
1360
|
+
wallet: Wallet, subtensor: "SubtensorInterface", subnet_identity: dict, prompt: bool
|
1361
|
+
):
|
1362
|
+
"""Register a subnetwork"""
|
1363
|
+
|
1364
|
+
# Call register command.
|
1365
|
+
success = await register_subnetwork_extrinsic(
|
1366
|
+
subtensor, wallet, subnet_identity, prompt=prompt
|
1367
|
+
)
|
1368
|
+
if success and prompt:
|
1369
|
+
# Prompt for user to set identity.
|
1370
|
+
do_set_identity = Confirm.ask(
|
1371
|
+
"Would you like to set your own [blue]identity?[/blue]"
|
1372
|
+
)
|
1373
|
+
|
1374
|
+
if do_set_identity:
|
1375
|
+
current_identity = await get_id(
|
1376
|
+
subtensor, wallet.coldkeypub.ss58_address, "Current on-chain identity"
|
1377
|
+
)
|
1378
|
+
if prompt:
|
1379
|
+
if not Confirm.ask(
|
1380
|
+
"\nCost to register an [blue]Identity[/blue] is [blue]0.1 TAO[/blue],"
|
1381
|
+
" are you sure you wish to continue?"
|
1382
|
+
):
|
1383
|
+
console.print(":cross_mark: Aborted!")
|
1384
|
+
raise typer.Exit()
|
1385
|
+
|
1386
|
+
identity = prompt_for_identity(
|
1387
|
+
current_identity=current_identity,
|
1388
|
+
name=None,
|
1389
|
+
web_url=None,
|
1390
|
+
image_url=None,
|
1391
|
+
discord=None,
|
1392
|
+
description=None,
|
1393
|
+
additional=None,
|
1394
|
+
github_repo=None,
|
1395
|
+
)
|
1396
|
+
|
1397
|
+
await set_id(
|
1398
|
+
wallet,
|
1399
|
+
subtensor,
|
1400
|
+
identity["name"],
|
1401
|
+
identity["url"],
|
1402
|
+
identity["image"],
|
1403
|
+
identity["discord"],
|
1404
|
+
identity["description"],
|
1405
|
+
identity["additional"],
|
1406
|
+
identity["github_repo"],
|
1407
|
+
prompt,
|
1408
|
+
)
|
1409
|
+
|
1410
|
+
|
1411
|
+
async def pow_register(
|
1412
|
+
wallet: Wallet,
|
1413
|
+
subtensor: "SubtensorInterface",
|
1414
|
+
netuid,
|
1415
|
+
processors,
|
1416
|
+
update_interval,
|
1417
|
+
output_in_place,
|
1418
|
+
verbose,
|
1419
|
+
use_cuda,
|
1420
|
+
dev_id,
|
1421
|
+
threads_per_block,
|
1422
|
+
):
|
1423
|
+
"""Register neuron."""
|
1424
|
+
|
1425
|
+
await register_extrinsic(
|
1426
|
+
subtensor,
|
1427
|
+
wallet=wallet,
|
1428
|
+
netuid=netuid,
|
1429
|
+
prompt=True,
|
1430
|
+
tpb=threads_per_block,
|
1431
|
+
update_interval=update_interval,
|
1432
|
+
num_processes=processors,
|
1433
|
+
cuda=use_cuda,
|
1434
|
+
dev_id=dev_id,
|
1435
|
+
output_in_place=output_in_place,
|
1436
|
+
log_verbose=verbose,
|
1437
|
+
)
|
1438
|
+
|
1439
|
+
|
1440
|
+
async def register(
|
1441
|
+
wallet: Wallet, subtensor: "SubtensorInterface", netuid: int, prompt: bool
|
1442
|
+
):
|
1443
|
+
"""Register neuron by recycling some TAO."""
|
1444
|
+
|
1445
|
+
# Verify subnet exists
|
1446
|
+
print_verbose("Checking subnet status")
|
1447
|
+
block_hash = await subtensor.substrate.get_chain_head()
|
1448
|
+
if not await subtensor.subnet_exists(netuid=netuid, block_hash=block_hash):
|
1449
|
+
err_console.print(f"[red]Subnet {netuid} does not exist[/red]")
|
1450
|
+
return
|
1451
|
+
|
1452
|
+
# Check current recycle amount
|
1453
|
+
print_verbose("Fetching recycle amount")
|
1454
|
+
current_recycle_, balance = await asyncio.gather(
|
1455
|
+
subtensor.get_hyperparameter(
|
1456
|
+
param_name="Burn", netuid=netuid, block_hash=block_hash
|
1457
|
+
),
|
1458
|
+
subtensor.get_balance(wallet.coldkeypub.ss58_address, block_hash=block_hash),
|
1459
|
+
)
|
1460
|
+
current_recycle = (
|
1461
|
+
Balance.from_rao(int(current_recycle_)) if current_recycle_ else Balance(0)
|
1462
|
+
)
|
1463
|
+
|
1464
|
+
# Check balance is sufficient
|
1465
|
+
if balance < current_recycle:
|
1466
|
+
err_console.print(
|
1467
|
+
f"[red]Insufficient balance {balance} to register neuron. Current recycle is {current_recycle} TAO[/red]"
|
1468
|
+
)
|
1469
|
+
return
|
1470
|
+
|
1471
|
+
if prompt:
|
1472
|
+
# TODO make this a reusable function, also used in subnets list
|
1473
|
+
# Show creation table.
|
1474
|
+
table = Table(
|
1475
|
+
title=f"\n[{COLOR_PALETTE['GENERAL']['HEADER']}]Register to [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]netuid: {netuid}[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}]"
|
1476
|
+
f"\nNetwork: [{COLOR_PALETTE['GENERAL']['SUBHEADING']}]{subtensor.network}[/{COLOR_PALETTE['GENERAL']['SUBHEADING']}]\n",
|
1477
|
+
show_footer=True,
|
1478
|
+
show_edge=False,
|
1479
|
+
header_style="bold white",
|
1480
|
+
border_style="bright_black",
|
1481
|
+
style="bold",
|
1482
|
+
title_justify="center",
|
1483
|
+
show_lines=False,
|
1484
|
+
pad_edge=True,
|
1485
|
+
)
|
1486
|
+
table.add_column(
|
1487
|
+
"Netuid", style="rgb(253,246,227)", no_wrap=True, justify="center"
|
1488
|
+
)
|
1489
|
+
table.add_column(
|
1490
|
+
"Symbol",
|
1491
|
+
style=COLOR_PALETTE["GENERAL"]["SYMBOL"],
|
1492
|
+
no_wrap=True,
|
1493
|
+
justify="center",
|
1494
|
+
)
|
1495
|
+
table.add_column(
|
1496
|
+
f"Cost ({Balance.get_unit(0)})",
|
1497
|
+
style=COLOR_PALETTE["POOLS"]["TAO"],
|
1498
|
+
no_wrap=True,
|
1499
|
+
justify="center",
|
1500
|
+
)
|
1501
|
+
table.add_column(
|
1502
|
+
"Hotkey",
|
1503
|
+
style=COLOR_PALETTE["GENERAL"]["HOTKEY"],
|
1504
|
+
no_wrap=True,
|
1505
|
+
justify="center",
|
1506
|
+
)
|
1507
|
+
table.add_column(
|
1508
|
+
"Coldkey",
|
1509
|
+
style=COLOR_PALETTE["GENERAL"]["COLDKEY"],
|
1510
|
+
no_wrap=True,
|
1511
|
+
justify="center",
|
1512
|
+
)
|
1513
|
+
table.add_row(
|
1514
|
+
str(netuid),
|
1515
|
+
f"{Balance.get_unit(netuid)}",
|
1516
|
+
f"τ {current_recycle.tao:.4f}",
|
1517
|
+
f"{wallet.hotkey.ss58_address}",
|
1518
|
+
f"{wallet.coldkeypub.ss58_address}",
|
1519
|
+
)
|
1520
|
+
console.print(table)
|
1521
|
+
if not (
|
1522
|
+
Confirm.ask(
|
1523
|
+
f"Your balance is: [{COLOR_PALETTE['GENERAL']['BALANCE']}]{balance}[/{COLOR_PALETTE['GENERAL']['BALANCE']}]\nThe cost to register by recycle is "
|
1524
|
+
f"[{COLOR_PALETTE['GENERAL']['COST']}]{current_recycle}[/{COLOR_PALETTE['GENERAL']['COST']}]\nDo you want to continue?",
|
1525
|
+
default=False,
|
1526
|
+
)
|
1527
|
+
):
|
1528
|
+
return
|
1529
|
+
|
1530
|
+
if netuid == 0:
|
1531
|
+
await root_register_extrinsic(subtensor, wallet=wallet)
|
1532
|
+
else:
|
1533
|
+
await burned_register_extrinsic(
|
1534
|
+
subtensor,
|
1535
|
+
wallet=wallet,
|
1536
|
+
netuid=netuid,
|
1537
|
+
prompt=False,
|
1538
|
+
old_balance=balance,
|
1539
|
+
)
|
1540
|
+
|
1541
|
+
|
1542
|
+
# TODO: Confirm emissions, incentive, Dividends are to be fetched from subnet_state or keep NeuronInfo
|
1543
|
+
async def metagraph_cmd(
|
1544
|
+
subtensor: Optional["SubtensorInterface"],
|
1545
|
+
netuid: Optional[int],
|
1546
|
+
reuse_last: bool,
|
1547
|
+
html_output: bool,
|
1548
|
+
no_cache: bool,
|
1549
|
+
display_cols: dict,
|
1550
|
+
):
|
1551
|
+
"""Prints an entire metagraph."""
|
1552
|
+
# TODO allow config to set certain columns
|
1553
|
+
if not reuse_last:
|
1554
|
+
cast("SubtensorInterface", subtensor)
|
1555
|
+
cast(int, netuid)
|
1556
|
+
with console.status(
|
1557
|
+
f":satellite: Syncing with chain: [white]{subtensor.network}[/white] ...",
|
1558
|
+
spinner="aesthetic",
|
1559
|
+
) as status:
|
1560
|
+
block_hash = await subtensor.substrate.get_chain_head()
|
1561
|
+
|
1562
|
+
if not await subtensor.subnet_exists(netuid, block_hash):
|
1563
|
+
print_error(f"Subnet with netuid: {netuid} does not exist", status)
|
1564
|
+
return False
|
1565
|
+
|
1566
|
+
(
|
1567
|
+
neurons,
|
1568
|
+
difficulty_,
|
1569
|
+
total_issuance_,
|
1570
|
+
block,
|
1571
|
+
subnet_state,
|
1572
|
+
) = await asyncio.gather(
|
1573
|
+
subtensor.neurons(netuid, block_hash=block_hash),
|
1574
|
+
subtensor.get_hyperparameter(
|
1575
|
+
param_name="Difficulty", netuid=netuid, block_hash=block_hash
|
1576
|
+
),
|
1577
|
+
subtensor.query(
|
1578
|
+
module="SubtensorModule",
|
1579
|
+
storage_function="TotalIssuance",
|
1580
|
+
params=[],
|
1581
|
+
block_hash=block_hash,
|
1582
|
+
),
|
1583
|
+
subtensor.substrate.get_block_number(block_hash=block_hash),
|
1584
|
+
subtensor.get_subnet_state(netuid=netuid),
|
1585
|
+
)
|
1586
|
+
|
1587
|
+
difficulty = int(difficulty_)
|
1588
|
+
total_issuance = Balance.from_rao(total_issuance_)
|
1589
|
+
metagraph = MiniGraph(
|
1590
|
+
netuid=netuid,
|
1591
|
+
neurons=neurons,
|
1592
|
+
subtensor=subtensor,
|
1593
|
+
subnet_state=subnet_state,
|
1594
|
+
block=block,
|
1595
|
+
)
|
1596
|
+
table_data = []
|
1597
|
+
db_table = []
|
1598
|
+
total_global_stake = 0.0
|
1599
|
+
total_local_stake = 0.0
|
1600
|
+
total_rank = 0.0
|
1601
|
+
total_validator_trust = 0.0
|
1602
|
+
total_trust = 0.0
|
1603
|
+
total_consensus = 0.0
|
1604
|
+
total_incentive = 0.0
|
1605
|
+
total_dividends = 0.0
|
1606
|
+
total_emission = 0
|
1607
|
+
for uid in metagraph.uids:
|
1608
|
+
neuron = metagraph.neurons[uid]
|
1609
|
+
ep = metagraph.axons[uid]
|
1610
|
+
row = [
|
1611
|
+
str(neuron.uid),
|
1612
|
+
"{:.4f}".format(metagraph.global_stake[uid]),
|
1613
|
+
"{:.4f}".format(metagraph.local_stake[uid]),
|
1614
|
+
"{:.4f}".format(metagraph.stake_weights[uid]),
|
1615
|
+
"{:.5f}".format(metagraph.ranks[uid]),
|
1616
|
+
"{:.5f}".format(metagraph.trust[uid]),
|
1617
|
+
"{:.5f}".format(metagraph.consensus[uid]),
|
1618
|
+
"{:.5f}".format(metagraph.incentive[uid]),
|
1619
|
+
"{:.5f}".format(metagraph.dividends[uid]),
|
1620
|
+
"{}".format(int(metagraph.emission[uid] * 1000000000)),
|
1621
|
+
"{:.5f}".format(metagraph.validator_trust[uid]),
|
1622
|
+
"*" if metagraph.validator_permit[uid] else "",
|
1623
|
+
str(metagraph.block.item() - metagraph.last_update[uid].item()),
|
1624
|
+
str(metagraph.active[uid].item()),
|
1625
|
+
(
|
1626
|
+
ep.ip + ":" + str(ep.port)
|
1627
|
+
if ep.is_serving
|
1628
|
+
else "[light_goldenrod2]none[/light_goldenrod2]"
|
1629
|
+
),
|
1630
|
+
ep.hotkey[:10],
|
1631
|
+
ep.coldkey[:10],
|
1632
|
+
]
|
1633
|
+
db_row = [
|
1634
|
+
neuron.uid,
|
1635
|
+
float(metagraph.global_stake[uid]),
|
1636
|
+
float(metagraph.local_stake[uid]),
|
1637
|
+
float(metagraph.stake_weights[uid]),
|
1638
|
+
float(metagraph.ranks[uid]),
|
1639
|
+
float(metagraph.trust[uid]),
|
1640
|
+
float(metagraph.consensus[uid]),
|
1641
|
+
float(metagraph.incentive[uid]),
|
1642
|
+
float(metagraph.dividends[uid]),
|
1643
|
+
int(metagraph.emission[uid] * 1000000000),
|
1644
|
+
float(metagraph.validator_trust[uid]),
|
1645
|
+
bool(metagraph.validator_permit[uid]),
|
1646
|
+
metagraph.block.item() - metagraph.last_update[uid].item(),
|
1647
|
+
metagraph.active[uid].item(),
|
1648
|
+
(ep.ip + ":" + str(ep.port) if ep.is_serving else "ERROR"),
|
1649
|
+
ep.hotkey[:10],
|
1650
|
+
ep.coldkey[:10],
|
1651
|
+
]
|
1652
|
+
db_table.append(db_row)
|
1653
|
+
total_global_stake += metagraph.global_stake[uid]
|
1654
|
+
total_local_stake += metagraph.local_stake[uid]
|
1655
|
+
total_rank += metagraph.ranks[uid]
|
1656
|
+
total_validator_trust += metagraph.validator_trust[uid]
|
1657
|
+
total_trust += metagraph.trust[uid]
|
1658
|
+
total_consensus += metagraph.consensus[uid]
|
1659
|
+
total_incentive += metagraph.incentive[uid]
|
1660
|
+
total_dividends += metagraph.dividends[uid]
|
1661
|
+
total_emission += int(metagraph.emission[uid] * 1000000000)
|
1662
|
+
table_data.append(row)
|
1663
|
+
metadata_info = {
|
1664
|
+
"total_global_stake": "\u03c4 {:.5f}".format(total_global_stake),
|
1665
|
+
"total_local_stake": f"{Balance.get_unit(netuid)} "
|
1666
|
+
+ "{:.5f}".format(total_local_stake),
|
1667
|
+
"rank": "{:.5f}".format(total_rank),
|
1668
|
+
"validator_trust": "{:.5f}".format(total_validator_trust),
|
1669
|
+
"trust": "{:.5f}".format(total_trust),
|
1670
|
+
"consensus": "{:.5f}".format(total_consensus),
|
1671
|
+
"incentive": "{:.5f}".format(total_incentive),
|
1672
|
+
"dividends": "{:.5f}".format(total_dividends),
|
1673
|
+
"emission": "\u03c1{}".format(int(total_emission)),
|
1674
|
+
"net": f"{subtensor.network}:{metagraph.netuid}",
|
1675
|
+
"block": str(metagraph.block.item()),
|
1676
|
+
"N": f"{sum(metagraph.active.tolist())}/{metagraph.n.item()}",
|
1677
|
+
"N0": str(sum(metagraph.active.tolist())),
|
1678
|
+
"N1": str(metagraph.n.item()),
|
1679
|
+
"issuance": str(total_issuance),
|
1680
|
+
"difficulty": str(difficulty),
|
1681
|
+
"total_neurons": str(len(metagraph.uids)),
|
1682
|
+
"table_data": json.dumps(table_data),
|
1683
|
+
}
|
1684
|
+
if not no_cache:
|
1685
|
+
update_metadata_table("metagraph", metadata_info)
|
1686
|
+
create_table(
|
1687
|
+
"metagraph",
|
1688
|
+
columns=[
|
1689
|
+
("UID", "INTEGER"),
|
1690
|
+
("GLOBAL_STAKE", "REAL"),
|
1691
|
+
("LOCAL_STAKE", "REAL"),
|
1692
|
+
("STAKE_WEIGHT", "REAL"),
|
1693
|
+
("RANK", "REAL"),
|
1694
|
+
("TRUST", "REAL"),
|
1695
|
+
("CONSENSUS", "REAL"),
|
1696
|
+
("INCENTIVE", "REAL"),
|
1697
|
+
("DIVIDENDS", "REAL"),
|
1698
|
+
("EMISSION", "INTEGER"),
|
1699
|
+
("VTRUST", "REAL"),
|
1700
|
+
("VAL", "INTEGER"),
|
1701
|
+
("UPDATED", "INTEGER"),
|
1702
|
+
("ACTIVE", "INTEGER"),
|
1703
|
+
("AXON", "TEXT"),
|
1704
|
+
("HOTKEY", "TEXT"),
|
1705
|
+
("COLDKEY", "TEXT"),
|
1706
|
+
],
|
1707
|
+
rows=db_table,
|
1708
|
+
)
|
1709
|
+
else:
|
1710
|
+
try:
|
1711
|
+
metadata_info = get_metadata_table("metagraph")
|
1712
|
+
table_data = json.loads(metadata_info["table_data"])
|
1713
|
+
except sqlite3.OperationalError:
|
1714
|
+
err_console.print(
|
1715
|
+
"[red]Error[/red] Unable to retrieve table data. This is usually caused by attempting to use "
|
1716
|
+
"`--reuse-last` before running the command a first time. In rare cases, this could also be due to "
|
1717
|
+
"a corrupted database. Re-run the command (do not use `--reuse-last`) and see if that resolves your "
|
1718
|
+
"issue."
|
1719
|
+
)
|
1720
|
+
return
|
1721
|
+
|
1722
|
+
if html_output:
|
1723
|
+
try:
|
1724
|
+
render_table(
|
1725
|
+
table_name="metagraph",
|
1726
|
+
table_info=f"Metagraph | "
|
1727
|
+
f"net: {metadata_info['net']}, "
|
1728
|
+
f"block: {metadata_info['block']}, "
|
1729
|
+
f"N: {metadata_info['N']}, "
|
1730
|
+
f"stake: {metadata_info['stake']}, "
|
1731
|
+
f"issuance: {metadata_info['issuance']}, "
|
1732
|
+
f"difficulty: {metadata_info['difficulty']}",
|
1733
|
+
columns=[
|
1734
|
+
{"title": "UID", "field": "UID"},
|
1735
|
+
{
|
1736
|
+
"title": "Global Stake",
|
1737
|
+
"field": "GLOBAL_STAKE",
|
1738
|
+
"formatter": "money",
|
1739
|
+
"formatterParams": {"symbol": "τ", "precision": 5},
|
1740
|
+
},
|
1741
|
+
{
|
1742
|
+
"title": "Local Stake",
|
1743
|
+
"field": "LOCAL_STAKE",
|
1744
|
+
"formatter": "money",
|
1745
|
+
"formatterParams": {
|
1746
|
+
"symbol": f"{Balance.get_unit(netuid)}",
|
1747
|
+
"precision": 5,
|
1748
|
+
},
|
1749
|
+
},
|
1750
|
+
{
|
1751
|
+
"title": "Stake Weight",
|
1752
|
+
"field": "STAKE_WEIGHT",
|
1753
|
+
"formatter": "money",
|
1754
|
+
"formatterParams": {"precision": 5},
|
1755
|
+
},
|
1756
|
+
{
|
1757
|
+
"title": "Rank",
|
1758
|
+
"field": "RANK",
|
1759
|
+
"formatter": "money",
|
1760
|
+
"formatterParams": {"precision": 5},
|
1761
|
+
},
|
1762
|
+
{
|
1763
|
+
"title": "Trust",
|
1764
|
+
"field": "TRUST",
|
1765
|
+
"formatter": "money",
|
1766
|
+
"formatterParams": {"precision": 5},
|
1767
|
+
},
|
1768
|
+
{
|
1769
|
+
"title": "Consensus",
|
1770
|
+
"field": "CONSENSUS",
|
1771
|
+
"formatter": "money",
|
1772
|
+
"formatterParams": {"precision": 5},
|
1773
|
+
},
|
1774
|
+
{
|
1775
|
+
"title": "Incentive",
|
1776
|
+
"field": "INCENTIVE",
|
1777
|
+
"formatter": "money",
|
1778
|
+
"formatterParams": {"precision": 5},
|
1779
|
+
},
|
1780
|
+
{
|
1781
|
+
"title": "Dividends",
|
1782
|
+
"field": "DIVIDENDS",
|
1783
|
+
"formatter": "money",
|
1784
|
+
"formatterParams": {"precision": 5},
|
1785
|
+
},
|
1786
|
+
{"title": "Emission", "field": "EMISSION"},
|
1787
|
+
{
|
1788
|
+
"title": "VTrust",
|
1789
|
+
"field": "VTRUST",
|
1790
|
+
"formatter": "money",
|
1791
|
+
"formatterParams": {"precision": 5},
|
1792
|
+
},
|
1793
|
+
{"title": "Validated", "field": "VAL"},
|
1794
|
+
{"title": "Updated", "field": "UPDATED"},
|
1795
|
+
{"title": "Active", "field": "ACTIVE"},
|
1796
|
+
{"title": "Axon", "field": "AXON"},
|
1797
|
+
{"title": "Hotkey", "field": "HOTKEY"},
|
1798
|
+
{"title": "Coldkey", "field": "COLDKEY"},
|
1799
|
+
],
|
1800
|
+
)
|
1801
|
+
except sqlite3.OperationalError:
|
1802
|
+
err_console.print(
|
1803
|
+
"[red]Error[/red] Unable to retrieve table data. This may indicate that your database is corrupted, "
|
1804
|
+
"or was not able to load with the most recent data."
|
1805
|
+
)
|
1806
|
+
return
|
1807
|
+
else:
|
1808
|
+
cols: dict[str, tuple[int, Column]] = {
|
1809
|
+
"UID": (
|
1810
|
+
0,
|
1811
|
+
Column(
|
1812
|
+
"[bold white]UID",
|
1813
|
+
footer=f"[white]{metadata_info['total_neurons']}[/white]",
|
1814
|
+
style="white",
|
1815
|
+
justify="right",
|
1816
|
+
ratio=0.75,
|
1817
|
+
),
|
1818
|
+
),
|
1819
|
+
"GLOBAL_STAKE": (
|
1820
|
+
1,
|
1821
|
+
Column(
|
1822
|
+
"[bold white]GLOBAL STAKE(\u03c4)",
|
1823
|
+
footer=metadata_info["total_global_stake"],
|
1824
|
+
style="bright_cyan",
|
1825
|
+
justify="right",
|
1826
|
+
no_wrap=True,
|
1827
|
+
ratio=1.6,
|
1828
|
+
),
|
1829
|
+
),
|
1830
|
+
"LOCAL_STAKE": (
|
1831
|
+
2,
|
1832
|
+
Column(
|
1833
|
+
f"[bold white]LOCAL STAKE({Balance.get_unit(netuid)})",
|
1834
|
+
footer=metadata_info["total_local_stake"],
|
1835
|
+
style="bright_green",
|
1836
|
+
justify="right",
|
1837
|
+
no_wrap=True,
|
1838
|
+
ratio=1.5,
|
1839
|
+
),
|
1840
|
+
),
|
1841
|
+
"STAKE_WEIGHT": (
|
1842
|
+
3,
|
1843
|
+
Column(
|
1844
|
+
f"[bold white]WEIGHT (\u03c4x{Balance.get_unit(netuid)})",
|
1845
|
+
style="purple",
|
1846
|
+
justify="right",
|
1847
|
+
no_wrap=True,
|
1848
|
+
ratio=1.3,
|
1849
|
+
),
|
1850
|
+
),
|
1851
|
+
"RANK": (
|
1852
|
+
4,
|
1853
|
+
Column(
|
1854
|
+
"[bold white]RANK",
|
1855
|
+
footer=metadata_info["rank"],
|
1856
|
+
style="medium_purple",
|
1857
|
+
justify="right",
|
1858
|
+
no_wrap=True,
|
1859
|
+
ratio=1,
|
1860
|
+
),
|
1861
|
+
),
|
1862
|
+
"TRUST": (
|
1863
|
+
5,
|
1864
|
+
Column(
|
1865
|
+
"[bold white]TRUST",
|
1866
|
+
footer=metadata_info["trust"],
|
1867
|
+
style="dark_sea_green",
|
1868
|
+
justify="right",
|
1869
|
+
no_wrap=True,
|
1870
|
+
ratio=1,
|
1871
|
+
),
|
1872
|
+
),
|
1873
|
+
"CONSENSUS": (
|
1874
|
+
6,
|
1875
|
+
Column(
|
1876
|
+
"[bold white]CONSENSUS",
|
1877
|
+
footer=metadata_info["consensus"],
|
1878
|
+
style="rgb(42,161,152)",
|
1879
|
+
justify="right",
|
1880
|
+
no_wrap=True,
|
1881
|
+
ratio=1,
|
1882
|
+
),
|
1883
|
+
),
|
1884
|
+
"INCENTIVE": (
|
1885
|
+
7,
|
1886
|
+
Column(
|
1887
|
+
"[bold white]INCENTIVE",
|
1888
|
+
footer=metadata_info["incentive"],
|
1889
|
+
style="#5fd7ff",
|
1890
|
+
justify="right",
|
1891
|
+
no_wrap=True,
|
1892
|
+
ratio=1,
|
1893
|
+
),
|
1894
|
+
),
|
1895
|
+
"DIVIDENDS": (
|
1896
|
+
8,
|
1897
|
+
Column(
|
1898
|
+
"[bold white]DIVIDENDS",
|
1899
|
+
footer=metadata_info["dividends"],
|
1900
|
+
style="#8787d7",
|
1901
|
+
justify="right",
|
1902
|
+
no_wrap=True,
|
1903
|
+
ratio=1,
|
1904
|
+
),
|
1905
|
+
),
|
1906
|
+
"EMISSION": (
|
1907
|
+
9,
|
1908
|
+
Column(
|
1909
|
+
"[bold white]EMISSION(\u03c1)",
|
1910
|
+
footer=metadata_info["emission"],
|
1911
|
+
style="#d7d7ff",
|
1912
|
+
justify="right",
|
1913
|
+
no_wrap=True,
|
1914
|
+
ratio=1.5,
|
1915
|
+
),
|
1916
|
+
),
|
1917
|
+
"VTRUST": (
|
1918
|
+
10,
|
1919
|
+
Column(
|
1920
|
+
"[bold white]VTRUST",
|
1921
|
+
footer=metadata_info["validator_trust"],
|
1922
|
+
style="magenta",
|
1923
|
+
justify="right",
|
1924
|
+
no_wrap=True,
|
1925
|
+
ratio=1,
|
1926
|
+
),
|
1927
|
+
),
|
1928
|
+
"VAL": (
|
1929
|
+
11,
|
1930
|
+
Column(
|
1931
|
+
"[bold white]VAL",
|
1932
|
+
justify="center",
|
1933
|
+
style="bright_white",
|
1934
|
+
no_wrap=True,
|
1935
|
+
ratio=0.7,
|
1936
|
+
),
|
1937
|
+
),
|
1938
|
+
"UPDATED": (
|
1939
|
+
12,
|
1940
|
+
Column("[bold white]UPDATED", justify="right", no_wrap=True, ratio=1),
|
1941
|
+
),
|
1942
|
+
"ACTIVE": (
|
1943
|
+
13,
|
1944
|
+
Column(
|
1945
|
+
"[bold white]ACTIVE",
|
1946
|
+
justify="center",
|
1947
|
+
style="#8787ff",
|
1948
|
+
no_wrap=True,
|
1949
|
+
ratio=1,
|
1950
|
+
),
|
1951
|
+
),
|
1952
|
+
"AXON": (
|
1953
|
+
14,
|
1954
|
+
Column(
|
1955
|
+
"[bold white]AXON",
|
1956
|
+
justify="left",
|
1957
|
+
style="dark_orange",
|
1958
|
+
overflow="fold",
|
1959
|
+
ratio=2,
|
1960
|
+
),
|
1961
|
+
),
|
1962
|
+
"HOTKEY": (
|
1963
|
+
15,
|
1964
|
+
Column(
|
1965
|
+
"[bold white]HOTKEY",
|
1966
|
+
justify="center",
|
1967
|
+
style="bright_magenta",
|
1968
|
+
overflow="fold",
|
1969
|
+
ratio=1.5,
|
1970
|
+
),
|
1971
|
+
),
|
1972
|
+
"COLDKEY": (
|
1973
|
+
16,
|
1974
|
+
Column(
|
1975
|
+
"[bold white]COLDKEY",
|
1976
|
+
justify="center",
|
1977
|
+
style="bright_magenta",
|
1978
|
+
overflow="fold",
|
1979
|
+
ratio=1.5,
|
1980
|
+
),
|
1981
|
+
),
|
1982
|
+
}
|
1983
|
+
table_cols: list[Column] = []
|
1984
|
+
table_cols_indices: list[int] = []
|
1985
|
+
for k, (idx, v) in cols.items():
|
1986
|
+
if display_cols[k] is True:
|
1987
|
+
table_cols_indices.append(idx)
|
1988
|
+
table_cols.append(v)
|
1989
|
+
|
1990
|
+
table = Table(
|
1991
|
+
*table_cols,
|
1992
|
+
show_footer=True,
|
1993
|
+
show_edge=False,
|
1994
|
+
header_style="bold white",
|
1995
|
+
border_style="bright_black",
|
1996
|
+
style="bold",
|
1997
|
+
title_style="bold white",
|
1998
|
+
title_justify="center",
|
1999
|
+
show_lines=False,
|
2000
|
+
expand=True,
|
2001
|
+
title=(
|
2002
|
+
f"[underline dark_orange]Metagraph[/underline dark_orange]\n\n"
|
2003
|
+
f"Net: [bright_cyan]{metadata_info['net']}[/bright_cyan], "
|
2004
|
+
f"Block: [bright_cyan]{metadata_info['block']}[/bright_cyan], "
|
2005
|
+
f"N: [bright_green]{metadata_info['N0']}[/bright_green]/[bright_red]{metadata_info['N1']}[/bright_red], "
|
2006
|
+
f"Total Local Stake: [dark_orange]{metadata_info['total_local_stake']}[/dark_orange], "
|
2007
|
+
f"Issuance: [bright_blue]{metadata_info['issuance']}[/bright_blue], "
|
2008
|
+
f"Difficulty: [bright_cyan]{metadata_info['difficulty']}[/bright_cyan]\n"
|
2009
|
+
),
|
2010
|
+
pad_edge=True,
|
2011
|
+
)
|
2012
|
+
|
2013
|
+
if all(x is False for x in display_cols.values()):
|
2014
|
+
console.print("You have selected no columns to display in your config.")
|
2015
|
+
table.add_row(" " * 256) # allows title to be printed
|
2016
|
+
elif any(x is False for x in display_cols.values()):
|
2017
|
+
console.print(
|
2018
|
+
"Limiting column display output based on your config settings. Hiding columns "
|
2019
|
+
f"{', '.join([k for (k, v) in display_cols.items() if v is False])}"
|
2020
|
+
)
|
2021
|
+
for row in table_data:
|
2022
|
+
new_row = [row[idx] for idx in table_cols_indices]
|
2023
|
+
table.add_row(*new_row)
|
2024
|
+
else:
|
2025
|
+
for row in table_data:
|
2026
|
+
table.add_row(*row)
|
2027
|
+
|
2028
|
+
console.print(table)
|