htcli 1.1.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.
- htcli-1.1.0.dist-info/METADATA +509 -0
- htcli-1.1.0.dist-info/RECORD +140 -0
- htcli-1.1.0.dist-info/WHEEL +4 -0
- htcli-1.1.0.dist-info/entry_points.txt +2 -0
- htcli-1.1.0.dist-info/licenses/LICENSE +21 -0
- src/__init__.py +0 -0
- src/htcli/__init__.py +5 -0
- src/htcli/client/__init__.py +338 -0
- src/htcli/client/extrinsics/__init__.py +26 -0
- src/htcli/client/extrinsics/base.py +487 -0
- src/htcli/client/extrinsics/consensus.py +79 -0
- src/htcli/client/extrinsics/governance.py +714 -0
- src/htcli/client/extrinsics/identity.py +490 -0
- src/htcli/client/extrinsics/node.py +1054 -0
- src/htcli/client/extrinsics/overwatch.py +401 -0
- src/htcli/client/extrinsics/staking.py +1504 -0
- src/htcli/client/extrinsics/subnet.py +2218 -0
- src/htcli/client/extrinsics/validator.py +203 -0
- src/htcli/client/extrinsics/wallet.py +323 -0
- src/htcli/client/offchain/__init__.py +10 -0
- src/htcli/client/offchain/backup.py +385 -0
- src/htcli/client/offchain/config.py +541 -0
- src/htcli/client/offchain/wallet.py +839 -0
- src/htcli/client/rpc/__init__.py +20 -0
- src/htcli/client/rpc/chain.py +568 -0
- src/htcli/client/rpc/node.py +783 -0
- src/htcli/client/rpc/overwatch.py +680 -0
- src/htcli/client/rpc/staking.py +216 -0
- src/htcli/client/rpc/subnet.py +2104 -0
- src/htcli/client/rpc/wallet.py +912 -0
- src/htcli/commands/__init__.py +31 -0
- src/htcli/commands/chain/__init__.py +66 -0
- src/htcli/commands/chain/display.py +204 -0
- src/htcli/commands/chain/handlers.py +260 -0
- src/htcli/commands/config/__init__.py +158 -0
- src/htcli/commands/config/display.py +353 -0
- src/htcli/commands/config/handlers.py +347 -0
- src/htcli/commands/config/prompts.py +357 -0
- src/htcli/commands/consensus/__init__.py +61 -0
- src/htcli/commands/consensus/handlers.py +100 -0
- src/htcli/commands/governance/__init__.py +49 -0
- src/htcli/commands/governance/handlers.py +81 -0
- src/htcli/commands/node/__init__.py +304 -0
- src/htcli/commands/node/display.py +749 -0
- src/htcli/commands/node/error_handling.py +470 -0
- src/htcli/commands/node/handlers.py +844 -0
- src/htcli/commands/node/prompts.py +346 -0
- src/htcli/commands/overwatch/__init__.py +219 -0
- src/htcli/commands/overwatch/display.py +396 -0
- src/htcli/commands/overwatch/error_handling.py +276 -0
- src/htcli/commands/overwatch/handlers.py +443 -0
- src/htcli/commands/overwatch/prompts.py +359 -0
- src/htcli/commands/stake/__init__.py +736 -0
- src/htcli/commands/stake/display.py +1103 -0
- src/htcli/commands/stake/error_handling.py +425 -0
- src/htcli/commands/stake/handlers.py +1902 -0
- src/htcli/commands/stake/prompts.py +1080 -0
- src/htcli/commands/subnet/__init__.py +639 -0
- src/htcli/commands/subnet/display.py +801 -0
- src/htcli/commands/subnet/error_handling.py +524 -0
- src/htcli/commands/subnet/handlers.py +2855 -0
- src/htcli/commands/subnet/prompts.py +1225 -0
- src/htcli/commands/validator/__init__.py +192 -0
- src/htcli/commands/validator/display.py +54 -0
- src/htcli/commands/validator/handlers.py +340 -0
- src/htcli/commands/wallet/__init__.py +546 -0
- src/htcli/commands/wallet/display.py +806 -0
- src/htcli/commands/wallet/error_handling.py +210 -0
- src/htcli/commands/wallet/handlers.py +3040 -0
- src/htcli/commands/wallet/prompts.py +1518 -0
- src/htcli/config.py +184 -0
- src/htcli/dependencies.py +186 -0
- src/htcli/errors/__init__.py +63 -0
- src/htcli/errors/base.py +141 -0
- src/htcli/errors/display.py +20 -0
- src/htcli/errors/handlers.py +710 -0
- src/htcli/main.py +343 -0
- src/htcli/models/__init__.py +21 -0
- src/htcli/models/enums/enum_types.py +35 -0
- src/htcli/models/errors.py +103 -0
- src/htcli/models/requests/__init__.py +197 -0
- src/htcli/models/requests/config.py +70 -0
- src/htcli/models/requests/consensus.py +19 -0
- src/htcli/models/requests/governance.py +38 -0
- src/htcli/models/requests/identity.py +51 -0
- src/htcli/models/requests/key.py +22 -0
- src/htcli/models/requests/node.py +91 -0
- src/htcli/models/requests/overwatch.py +64 -0
- src/htcli/models/requests/staking.py +580 -0
- src/htcli/models/requests/subnet.py +195 -0
- src/htcli/models/requests/validator.py +139 -0
- src/htcli/models/requests/wallet.py +118 -0
- src/htcli/models/responses/__init__.py +147 -0
- src/htcli/models/responses/base.py +18 -0
- src/htcli/models/responses/chain.py +39 -0
- src/htcli/models/responses/config.py +58 -0
- src/htcli/models/responses/identity.py +102 -0
- src/htcli/models/responses/overwatch.py +51 -0
- src/htcli/models/responses/staking.py +502 -0
- src/htcli/models/responses/subnet.py +856 -0
- src/htcli/models/responses/wallet.py +185 -0
- src/htcli/ui/__init__.py +87 -0
- src/htcli/ui/colors.py +309 -0
- src/htcli/ui/components/__init__.py +60 -0
- src/htcli/ui/components/panels.py +174 -0
- src/htcli/ui/components/progress.py +166 -0
- src/htcli/ui/components/spinners.py +92 -0
- src/htcli/ui/components/tables.py +809 -0
- src/htcli/ui/components/trees.py +721 -0
- src/htcli/ui/display.py +336 -0
- src/htcli/ui/prompts.py +870 -0
- src/htcli/utils/__init__.py +76 -0
- src/htcli/utils/blockchain/__init__.py +75 -0
- src/htcli/utils/blockchain/formatting.py +368 -0
- src/htcli/utils/blockchain/patches.py +286 -0
- src/htcli/utils/blockchain/peer_id.py +186 -0
- src/htcli/utils/blockchain/staking.py +448 -0
- src/htcli/utils/blockchain/type_registry.py +1373 -0
- src/htcli/utils/blockchain/validation.py +179 -0
- src/htcli/utils/cache.py +613 -0
- src/htcli/utils/constants.py +38 -0
- src/htcli/utils/legacy/__init__.py +12 -0
- src/htcli/utils/legacy/colors.py +311 -0
- src/htcli/utils/legacy/crypto.py +1176 -0
- src/htcli/utils/legacy/formatting.py +452 -0
- src/htcli/utils/legacy/interactive.py +306 -0
- src/htcli/utils/legacy/subnet_manifest.py +265 -0
- src/htcli/utils/legacy/validation.py +488 -0
- src/htcli/utils/logging.py +183 -0
- src/htcli/utils/network/__init__.py +20 -0
- src/htcli/utils/network/subnet.py +344 -0
- src/htcli/utils/prompts.py +27 -0
- src/htcli/utils/scale_codec.py +155 -0
- src/htcli/utils/validation/__init__.py +57 -0
- src/htcli/utils/validation/prompt_validators.py +267 -0
- src/htcli/utils/wallet/__init__.py +65 -0
- src/htcli/utils/wallet/auth.py +151 -0
- src/htcli/utils/wallet/core.py +1069 -0
- src/htcli/utils/wallet/crypto.py +1615 -0
- src/htcli/utils/wallet/migration.py +159 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
from textwrap import dedent
|
|
3
|
+
|
|
4
|
+
import typer
|
|
5
|
+
|
|
6
|
+
from .handlers import propose_attestation_handler, attest_handler
|
|
7
|
+
|
|
8
|
+
app = typer.Typer(name="consensus", help="Consensus operations")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
PROPOSE_HELP = dedent(
|
|
12
|
+
"""\
|
|
13
|
+
Propose an attestation on a subnet.
|
|
14
|
+
|
|
15
|
+
Validators use this command to submit a proposal (arbitrary data) for consensus.
|
|
16
|
+
Requires a registered hotkey.
|
|
17
|
+
|
|
18
|
+
\b
|
|
19
|
+
Example:
|
|
20
|
+
htcli consensus propose --wallet my-hotkey --subnet 1 --data "0x1234..."
|
|
21
|
+
"""
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
ATTEST_HELP = dedent(
|
|
25
|
+
"""\
|
|
26
|
+
Attest to an existing proposal.
|
|
27
|
+
|
|
28
|
+
Validators use this command to vote for a proposal by its hash.
|
|
29
|
+
Requires a registered hotkey.
|
|
30
|
+
|
|
31
|
+
\b
|
|
32
|
+
Example:
|
|
33
|
+
htcli consensus attest --wallet my-hotkey --subnet 1 --hash "0xabcd..."
|
|
34
|
+
"""
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@app.command("propose", help=PROPOSE_HELP)
|
|
39
|
+
def propose(
|
|
40
|
+
wallet: str = typer.Option(..., "--wallet", "-w", help="Wallet name (hotkey)"),
|
|
41
|
+
subnet_id: int = typer.Option(..., "--subnet", "-s", help="Subnet ID"),
|
|
42
|
+
data: str = typer.Option(..., "--data", "-d", help="Data to propose"),
|
|
43
|
+
password: Optional[str] = typer.Option(
|
|
44
|
+
None, "--password", "-p", help="Wallet password"
|
|
45
|
+
),
|
|
46
|
+
):
|
|
47
|
+
"""Propose an attestation on a subnet."""
|
|
48
|
+
propose_attestation_handler(wallet, subnet_id, data, password)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@app.command("attest", help=ATTEST_HELP)
|
|
52
|
+
def attest(
|
|
53
|
+
wallet: str = typer.Option(..., "--wallet", "-w", help="Wallet name (hotkey)"),
|
|
54
|
+
subnet_id: int = typer.Option(..., "--subnet", "-s", help="Subnet ID"),
|
|
55
|
+
proposal_hash: str = typer.Option(..., "--hash", "-h", help="Proposal hash"),
|
|
56
|
+
password: Optional[str] = typer.Option(
|
|
57
|
+
None, "--password", "-p", help="Wallet password"
|
|
58
|
+
),
|
|
59
|
+
):
|
|
60
|
+
"""Attest to an existing proposal."""
|
|
61
|
+
attest_handler(wallet, subnet_id, proposal_hash, password)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Consensus command handlers.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
|
|
9
|
+
from ...dependencies import get_client
|
|
10
|
+
from ...models.requests.consensus import AttestRequest, ProposeAttestationRequest
|
|
11
|
+
from ...ui.components.spinners import HTCLISpinner
|
|
12
|
+
from ...ui.display import print_error, print_info, print_success
|
|
13
|
+
from ...ui.prompts import confirm_prompt
|
|
14
|
+
from ...utils.wallet.core import _get_keypair_with_password_retry
|
|
15
|
+
|
|
16
|
+
console = Console()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def propose_attestation_handler(
|
|
20
|
+
wallet_name: str,
|
|
21
|
+
subnet_id: int,
|
|
22
|
+
data: str,
|
|
23
|
+
password: Optional[str] = None,
|
|
24
|
+
):
|
|
25
|
+
"""Handle propose attestation command."""
|
|
26
|
+
try:
|
|
27
|
+
client = get_client()
|
|
28
|
+
if not client.connect():
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
# Get keypair
|
|
32
|
+
print_info(f"🔐 Unlocking wallet '{wallet_name}'...", emoji=False)
|
|
33
|
+
wallet_manager = client.offchain.wallet
|
|
34
|
+
# Assuming validators sign with hotkeys for consensus
|
|
35
|
+
wallet_info = wallet_manager.get_wallet_info(wallet_name, is_hotkey=True)
|
|
36
|
+
_, keypair = _get_keypair_with_password_retry(
|
|
37
|
+
client, wallet_name, wallet_info["data"], 3, password
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# Confirm
|
|
41
|
+
if not confirm_prompt(
|
|
42
|
+
f"Propose attestation for subnet {subnet_id}?", default=True
|
|
43
|
+
):
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
# Submit
|
|
47
|
+
with HTCLISpinner("Submitting proposal..."):
|
|
48
|
+
request = ProposeAttestationRequest(subnet_id=subnet_id, data=data)
|
|
49
|
+
response = client.extrinsics.consensus.propose_attestation(request, keypair)
|
|
50
|
+
|
|
51
|
+
if response["success"]:
|
|
52
|
+
print_success("✅ Proposal submitted successfully!")
|
|
53
|
+
console.print(f" • Block Hash: {response.get('block_hash')}")
|
|
54
|
+
else:
|
|
55
|
+
print_error(f"Proposal failed: {response.get('error')}")
|
|
56
|
+
|
|
57
|
+
except Exception as e:
|
|
58
|
+
print_error(f"Error: {str(e)}")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def attest_handler(
|
|
62
|
+
wallet_name: str,
|
|
63
|
+
subnet_id: int,
|
|
64
|
+
proposal_hash: str,
|
|
65
|
+
password: Optional[str] = None,
|
|
66
|
+
):
|
|
67
|
+
"""Handle attest command."""
|
|
68
|
+
try:
|
|
69
|
+
client = get_client()
|
|
70
|
+
if not client.connect():
|
|
71
|
+
return
|
|
72
|
+
|
|
73
|
+
# Get keypair
|
|
74
|
+
print_info(f"🔐 Unlocking wallet '{wallet_name}'...", emoji=False)
|
|
75
|
+
wallet_manager = client.offchain.wallet
|
|
76
|
+
# Assuming validators sign with hotkeys for consensus
|
|
77
|
+
wallet_info = wallet_manager.get_wallet_info(wallet_name, is_hotkey=True)
|
|
78
|
+
_, keypair = _get_keypair_with_password_retry(
|
|
79
|
+
client, wallet_name, wallet_info["data"], 3, password
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# Confirm
|
|
83
|
+
if not confirm_prompt(
|
|
84
|
+
f"Attest to proposal {proposal_hash} on subnet {subnet_id}?", default=True
|
|
85
|
+
):
|
|
86
|
+
return
|
|
87
|
+
|
|
88
|
+
# Submit
|
|
89
|
+
with HTCLISpinner("Submitting attestation..."):
|
|
90
|
+
request = AttestRequest(subnet_id=subnet_id, proposal_hash=proposal_hash)
|
|
91
|
+
response = client.extrinsics.consensus.attest(request, keypair)
|
|
92
|
+
|
|
93
|
+
if response["success"]:
|
|
94
|
+
print_success("✅ Attestation submitted successfully!")
|
|
95
|
+
console.print(f" • Block Hash: {response.get('block_hash')}")
|
|
96
|
+
else:
|
|
97
|
+
print_error(f"Attestation failed: {response.get('error')}")
|
|
98
|
+
|
|
99
|
+
except Exception as e:
|
|
100
|
+
print_error(f"Error: {str(e)}")
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
from textwrap import dedent
|
|
3
|
+
|
|
4
|
+
import typer
|
|
5
|
+
|
|
6
|
+
from .handlers import set_parameter_handler
|
|
7
|
+
|
|
8
|
+
app = typer.Typer(name="governance", help="Governance operations")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
SET_PARAM_HELP = dedent(
|
|
12
|
+
"""\
|
|
13
|
+
Update a network governance parameter.
|
|
14
|
+
|
|
15
|
+
Requires administrative privileges (sudo/root key).
|
|
16
|
+
|
|
17
|
+
\b
|
|
18
|
+
Available Parameters:
|
|
19
|
+
- min_registration_cost
|
|
20
|
+
- target_registrations_per_interval
|
|
21
|
+
- max_registrations_per_interval
|
|
22
|
+
- adjustment_alpha
|
|
23
|
+
- target_max_subnet_nodes
|
|
24
|
+
- tx_rate_limit
|
|
25
|
+
- min_delegate_stake_percentage
|
|
26
|
+
- max_delegate_stake_percentage
|
|
27
|
+
- min_max_registered_nodes
|
|
28
|
+
- max_max_registered_nodes
|
|
29
|
+
- network_min_stake_balance
|
|
30
|
+
- network_max_stake_balance
|
|
31
|
+
|
|
32
|
+
\b
|
|
33
|
+
Example:
|
|
34
|
+
htcli governance set-param --wallet root --param min_registration_cost --value 1000
|
|
35
|
+
"""
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@app.command("set-param", help=SET_PARAM_HELP)
|
|
40
|
+
def set_param(
|
|
41
|
+
wallet: str = typer.Option(..., "--wallet", "-w", help="Governance wallet name"),
|
|
42
|
+
parameter: str = typer.Option(..., "--param", "-p", help="Parameter name"),
|
|
43
|
+
value: int = typer.Option(..., "--value", "-v", help="New value"),
|
|
44
|
+
password: Optional[str] = typer.Option(
|
|
45
|
+
None, "--password", "-pw", help="Wallet password"
|
|
46
|
+
),
|
|
47
|
+
):
|
|
48
|
+
"""Update a network governance parameter."""
|
|
49
|
+
set_parameter_handler(wallet, parameter, value, password)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Governance command handlers.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
|
|
9
|
+
from ...dependencies import get_client
|
|
10
|
+
from ...models.requests.governance import GovernanceParameterUpdateRequest
|
|
11
|
+
from ...ui.components.spinners import HTCLISpinner
|
|
12
|
+
from ...ui.display import print_error, print_info, print_success
|
|
13
|
+
from ...ui.prompts import confirm_prompt
|
|
14
|
+
from ...utils.wallet.core import _get_keypair_with_password_retry
|
|
15
|
+
|
|
16
|
+
console = Console()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def set_parameter_handler(
|
|
20
|
+
wallet_name: str,
|
|
21
|
+
parameter: str,
|
|
22
|
+
value: int,
|
|
23
|
+
password: Optional[str] = None,
|
|
24
|
+
):
|
|
25
|
+
"""Handle parameter setting command."""
|
|
26
|
+
try:
|
|
27
|
+
# Map parameter names to client method names before attempting wallet unlock
|
|
28
|
+
method_name_map = {
|
|
29
|
+
"min_registration_cost": "set_min_registration_cost",
|
|
30
|
+
"target_registrations_per_interval": "set_target_registrations_per_interval",
|
|
31
|
+
"max_registrations_per_interval": "set_max_registrations_per_interval",
|
|
32
|
+
"adjustment_alpha": "set_adjustment_alpha",
|
|
33
|
+
"target_max_subnet_nodes": "set_target_max_subnet_nodes",
|
|
34
|
+
"tx_rate_limit": "set_tx_rate_limit",
|
|
35
|
+
"min_delegate_stake_percentage": "set_min_delegate_stake_percentage",
|
|
36
|
+
"max_delegate_stake_percentage": "set_max_delegate_stake_percentage",
|
|
37
|
+
"min_max_registered_nodes": "set_min_max_registered_nodes",
|
|
38
|
+
"max_max_registered_nodes": "set_max_max_registered_nodes",
|
|
39
|
+
"network_min_stake_balance": "set_network_min_stake_balance",
|
|
40
|
+
"network_max_stake_balance": "set_network_max_stake_balance",
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if parameter not in method_name_map:
|
|
44
|
+
print_error(f"Unknown parameter: {parameter}")
|
|
45
|
+
console.print("Available parameters:")
|
|
46
|
+
for p in method_name_map.keys():
|
|
47
|
+
console.print(f" • {p}")
|
|
48
|
+
return
|
|
49
|
+
|
|
50
|
+
client = get_client()
|
|
51
|
+
if not client.connect():
|
|
52
|
+
return
|
|
53
|
+
|
|
54
|
+
# Get keypair (must be governance)
|
|
55
|
+
print_info(f"🔐 Unlocking governance wallet '{wallet_name}'...", emoji=False)
|
|
56
|
+
wallet_manager = client.offchain.wallet
|
|
57
|
+
# Assuming governance keys are coldkeys
|
|
58
|
+
wallet_info = wallet_manager.get_wallet_info(wallet_name, is_hotkey=False)
|
|
59
|
+
_, keypair = _get_keypair_with_password_retry(
|
|
60
|
+
client, wallet_name, wallet_info["data"], 3, password
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
method = getattr(client.extrinsics.governance, method_name_map[parameter])
|
|
64
|
+
|
|
65
|
+
# Confirm
|
|
66
|
+
if not confirm_prompt(f"Set {parameter} to {value}?", default=False):
|
|
67
|
+
return
|
|
68
|
+
|
|
69
|
+
# Submit
|
|
70
|
+
with HTCLISpinner(f"Setting {parameter}..."):
|
|
71
|
+
request = GovernanceParameterUpdateRequest(value=value)
|
|
72
|
+
response = method(request, keypair)
|
|
73
|
+
|
|
74
|
+
if response["success"]:
|
|
75
|
+
print_success(f"✅ {parameter} set successfully!")
|
|
76
|
+
console.print(f" • Block Hash: {response.get('block_hash')}")
|
|
77
|
+
else:
|
|
78
|
+
print_error(f"Failed to set parameter: {response.get('error')}")
|
|
79
|
+
|
|
80
|
+
except Exception as e:
|
|
81
|
+
print_error(f"Error: {str(e)}")
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Node command module - placeholder implementation.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from textwrap import dedent
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
|
|
10
|
+
from ..subnet import handlers as subnet_handlers
|
|
11
|
+
from . import handlers as node_handlers
|
|
12
|
+
|
|
13
|
+
app = typer.Typer(name="node", help="Node operations")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
UPDATE_NODE_HELP = dedent(
|
|
17
|
+
"""\
|
|
18
|
+
Update node configuration.
|
|
19
|
+
|
|
20
|
+
This command allows updating various properties of a registered node.
|
|
21
|
+
You can update multiple fields in a single call. Any provided field will be
|
|
22
|
+
updated sequentially and a consolidated summary will be displayed.
|
|
23
|
+
|
|
24
|
+
\b
|
|
25
|
+
Examples:
|
|
26
|
+
htcli node update --subnet-id 1 --node-id 5 --delegate-rate 10
|
|
27
|
+
htcli node update --subnet-id 1 --node-id 5 --peer-id "new-peer-id"
|
|
28
|
+
"""
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@app.command("register")
|
|
33
|
+
def register_node(
|
|
34
|
+
subnet_id: Optional[int] = typer.Option(
|
|
35
|
+
None, "--subnet-id", help="Subnet ID to register on"
|
|
36
|
+
),
|
|
37
|
+
validator_id: Optional[int] = typer.Option(
|
|
38
|
+
None, "--validator-id", help="Validator ID that owns the node"
|
|
39
|
+
),
|
|
40
|
+
hotkey: Optional[str] = typer.Option(
|
|
41
|
+
None, "--hotkey", help="Hotkey address for the node"
|
|
42
|
+
),
|
|
43
|
+
stake: Optional[float] = typer.Option(
|
|
44
|
+
None, "--stake", help="Initial stake amount (TENSOR)"
|
|
45
|
+
),
|
|
46
|
+
peer_id: Optional[str] = typer.Option(
|
|
47
|
+
None, "--peer-id", help="Peer ID (auto-generated if not provided)"
|
|
48
|
+
),
|
|
49
|
+
coldkey: Optional[str] = typer.Option(
|
|
50
|
+
None,
|
|
51
|
+
"--coldkey",
|
|
52
|
+
help="Coldkey wallet name or address to sign the registration extrinsic",
|
|
53
|
+
),
|
|
54
|
+
):
|
|
55
|
+
"""Register a new node on a subnet."""
|
|
56
|
+
node_handlers.register_node_handler(
|
|
57
|
+
subnet_id=subnet_id,
|
|
58
|
+
validator_id=validator_id,
|
|
59
|
+
hotkey=hotkey,
|
|
60
|
+
stake_amount=stake,
|
|
61
|
+
peer_id=peer_id,
|
|
62
|
+
coldkey=coldkey,
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@app.command("list")
|
|
67
|
+
def list_nodes(
|
|
68
|
+
subnet_id: Optional[int] = typer.Option(
|
|
69
|
+
None, "--subnet-id", "--subnetid", help="The unique ID (UID) of the subnet."
|
|
70
|
+
),
|
|
71
|
+
live: bool = typer.Option(
|
|
72
|
+
False,
|
|
73
|
+
"--live",
|
|
74
|
+
help="Enable live updates when supported.",
|
|
75
|
+
),
|
|
76
|
+
coldkey: Optional[str] = typer.Option(
|
|
77
|
+
None, "--coldkey", help="Coldkey wallet name or address to list nodes for"
|
|
78
|
+
),
|
|
79
|
+
):
|
|
80
|
+
"""List all nodes registered to a specific subnet using RPC. Use --coldkey to filter by coldkey."""
|
|
81
|
+
_ = live
|
|
82
|
+
subnet_handlers.get_subnet_nodes_handler(subnet_id, coldkey)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@app.command("all")
|
|
86
|
+
def get_all_nodes(
|
|
87
|
+
live: bool = typer.Option(
|
|
88
|
+
False,
|
|
89
|
+
"--live",
|
|
90
|
+
help="Enable live updates when supported.",
|
|
91
|
+
),
|
|
92
|
+
):
|
|
93
|
+
"""Get all nodes across all subnets using RPC."""
|
|
94
|
+
_ = live
|
|
95
|
+
node_handlers.get_all_nodes_handler()
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@app.command("status")
|
|
99
|
+
def get_node_status(
|
|
100
|
+
subnet_id: Optional[int] = typer.Argument(
|
|
101
|
+
None,
|
|
102
|
+
help="The subnet ID",
|
|
103
|
+
),
|
|
104
|
+
node_id: Optional[int] = typer.Argument(
|
|
105
|
+
None,
|
|
106
|
+
help="The node ID within the subnet",
|
|
107
|
+
),
|
|
108
|
+
):
|
|
109
|
+
"""Get the status for a specific node."""
|
|
110
|
+
subnet_handlers.get_node_status_handler(subnet_id, node_id)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@app.command("info")
|
|
114
|
+
def get_node_info(
|
|
115
|
+
subnet_id: Optional[int] = typer.Option(
|
|
116
|
+
None, "--subnet-id", "--subnetid", help="The subnet ID"
|
|
117
|
+
),
|
|
118
|
+
node_id: Optional[int] = typer.Option(
|
|
119
|
+
None, "--node-id", "--nodeid", help="The node ID"
|
|
120
|
+
),
|
|
121
|
+
):
|
|
122
|
+
"""Get detailed information about a specific node using RPC."""
|
|
123
|
+
node_handlers.get_node_info_handler(subnet_id, node_id)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@app.command("overwatch-commits", context_settings={"allow_extra_args": True})
|
|
127
|
+
def get_overwatch_commits(
|
|
128
|
+
ctx: typer.Context,
|
|
129
|
+
epoch: Optional[int] = typer.Option(None, "--epoch", "-e", help="The epoch number"),
|
|
130
|
+
overwatch_node_id: Optional[int] = typer.Option(
|
|
131
|
+
None, "--node-id", "-n", help="The overwatch node ID"
|
|
132
|
+
),
|
|
133
|
+
):
|
|
134
|
+
"""Get overwatch commits for a specific node and epoch using RPC."""
|
|
135
|
+
if epoch is None and len(ctx.args) > 0:
|
|
136
|
+
try:
|
|
137
|
+
epoch = int(ctx.args[0])
|
|
138
|
+
except ValueError:
|
|
139
|
+
pass
|
|
140
|
+
if overwatch_node_id is None and len(ctx.args) > 1:
|
|
141
|
+
try:
|
|
142
|
+
overwatch_node_id = int(ctx.args[1])
|
|
143
|
+
except ValueError:
|
|
144
|
+
pass
|
|
145
|
+
node_handlers.get_overwatch_commits_handler(epoch, overwatch_node_id)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@app.command("overwatch-reveals", context_settings={"allow_extra_args": True})
|
|
149
|
+
def get_overwatch_reveals(
|
|
150
|
+
ctx: typer.Context,
|
|
151
|
+
epoch: Optional[int] = typer.Option(None, "--epoch", "-e", help="The epoch number"),
|
|
152
|
+
overwatch_node_id: Optional[int] = typer.Option(
|
|
153
|
+
None, "--node-id", "-n", help="The overwatch node ID"
|
|
154
|
+
),
|
|
155
|
+
):
|
|
156
|
+
"""Get overwatch reveals for a specific node and epoch using RPC."""
|
|
157
|
+
if epoch is None and len(ctx.args) > 0:
|
|
158
|
+
try:
|
|
159
|
+
epoch = int(ctx.args[0])
|
|
160
|
+
except ValueError:
|
|
161
|
+
pass
|
|
162
|
+
if overwatch_node_id is None and len(ctx.args) > 1:
|
|
163
|
+
try:
|
|
164
|
+
overwatch_node_id = int(ctx.args[1])
|
|
165
|
+
except ValueError:
|
|
166
|
+
pass
|
|
167
|
+
node_handlers.get_overwatch_reveals_handler(epoch, overwatch_node_id)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
@app.command("remove")
|
|
171
|
+
def remove_node(
|
|
172
|
+
subnet_id: Optional[int] = typer.Option(
|
|
173
|
+
None,
|
|
174
|
+
"--subnet-id",
|
|
175
|
+
help="Subnet ID of the node to remove",
|
|
176
|
+
),
|
|
177
|
+
node_id: Optional[int] = typer.Option(
|
|
178
|
+
None,
|
|
179
|
+
"--node-id",
|
|
180
|
+
help="Node ID to remove",
|
|
181
|
+
),
|
|
182
|
+
coldkey: Optional[str] = typer.Option(
|
|
183
|
+
None,
|
|
184
|
+
"--coldkey",
|
|
185
|
+
help="Coldkey wallet name or address to sign the removal extrinsic",
|
|
186
|
+
),
|
|
187
|
+
):
|
|
188
|
+
"""Remove a node from a subnet."""
|
|
189
|
+
node_handlers.remove_node_handler(
|
|
190
|
+
subnet_id=subnet_id, node_id=node_id, coldkey=coldkey
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@app.command("activate")
|
|
195
|
+
def activate_node(
|
|
196
|
+
subnet_id: Optional[int] = typer.Option(
|
|
197
|
+
None,
|
|
198
|
+
"--subnet-id",
|
|
199
|
+
help="Subnet ID of the node to activate",
|
|
200
|
+
),
|
|
201
|
+
node_id: Optional[int] = typer.Option(
|
|
202
|
+
None,
|
|
203
|
+
"--node-id",
|
|
204
|
+
help="Node ID to activate",
|
|
205
|
+
),
|
|
206
|
+
coldkey: Optional[str] = typer.Option(
|
|
207
|
+
None,
|
|
208
|
+
"--coldkey",
|
|
209
|
+
help="Coldkey wallet name or address to sign the activation extrinsic",
|
|
210
|
+
),
|
|
211
|
+
):
|
|
212
|
+
"""Activate a registered node on a subnet."""
|
|
213
|
+
node_handlers.activate_node_handler(
|
|
214
|
+
subnet_id=subnet_id, node_id=node_id, coldkey=coldkey
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
@app.command("deactivate")
|
|
219
|
+
def deactivate_node(
|
|
220
|
+
subnet_id: Optional[int] = typer.Option(
|
|
221
|
+
None,
|
|
222
|
+
"--subnet-id",
|
|
223
|
+
help="Subnet ID of the node to deactivate",
|
|
224
|
+
),
|
|
225
|
+
node_id: Optional[int] = typer.Option(
|
|
226
|
+
None,
|
|
227
|
+
"--node-id",
|
|
228
|
+
help="Node ID to deactivate",
|
|
229
|
+
),
|
|
230
|
+
coldkey: Optional[str] = typer.Option(
|
|
231
|
+
None,
|
|
232
|
+
"--coldkey",
|
|
233
|
+
help="Coldkey wallet name or address to sign the deactivation extrinsic",
|
|
234
|
+
),
|
|
235
|
+
):
|
|
236
|
+
"""Deactivate a node on a subnet."""
|
|
237
|
+
node_handlers.deactivate_node_handler(
|
|
238
|
+
subnet_id=subnet_id, node_id=node_id, coldkey=coldkey
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
@app.command("update", help=UPDATE_NODE_HELP)
|
|
243
|
+
def update_node(
|
|
244
|
+
subnet_id: Optional[int] = typer.Option(
|
|
245
|
+
None, "--subnet-id", help="Subnet ID of the node"
|
|
246
|
+
),
|
|
247
|
+
node_id: Optional[int] = typer.Option(None, "--node-id", help="Node ID to update"),
|
|
248
|
+
peer_id: Optional[str] = typer.Option(
|
|
249
|
+
None,
|
|
250
|
+
"--peer-id",
|
|
251
|
+
help="New primary peer ID for the node",
|
|
252
|
+
),
|
|
253
|
+
bootnode: Optional[str] = typer.Option(
|
|
254
|
+
None,
|
|
255
|
+
"--bootnode",
|
|
256
|
+
help="New bootnode multiaddress for the node (empty string to clear)",
|
|
257
|
+
),
|
|
258
|
+
bootnode_peer_id: Optional[str] = typer.Option(
|
|
259
|
+
None,
|
|
260
|
+
"--bootnode-peer-id",
|
|
261
|
+
help="New bootnode peer ID",
|
|
262
|
+
),
|
|
263
|
+
client_peer_id: Optional[str] = typer.Option(
|
|
264
|
+
None,
|
|
265
|
+
"--client-peer-id",
|
|
266
|
+
help="New client peer ID",
|
|
267
|
+
),
|
|
268
|
+
delegate_rate: Optional[int] = typer.Option(
|
|
269
|
+
None,
|
|
270
|
+
"--delegate-rate",
|
|
271
|
+
help="New delegate reward rate (0-100 as percent, or 1e18-format value)",
|
|
272
|
+
),
|
|
273
|
+
unique: Optional[str] = typer.Option(
|
|
274
|
+
None,
|
|
275
|
+
"--unique",
|
|
276
|
+
help="New unique metadata value (empty string to clear)",
|
|
277
|
+
),
|
|
278
|
+
non_unique: Optional[str] = typer.Option(
|
|
279
|
+
None,
|
|
280
|
+
"--non-unique",
|
|
281
|
+
help="New non-unique metadata value (empty string to clear)",
|
|
282
|
+
),
|
|
283
|
+
coldkey: Optional[str] = typer.Option(
|
|
284
|
+
None,
|
|
285
|
+
"--coldkey",
|
|
286
|
+
help="Coldkey wallet name or address to sign the update transaction",
|
|
287
|
+
),
|
|
288
|
+
):
|
|
289
|
+
"""Update node configuration."""
|
|
290
|
+
node_handlers.update_node_handler(
|
|
291
|
+
subnet_id=subnet_id,
|
|
292
|
+
node_id=node_id,
|
|
293
|
+
peer_id=peer_id,
|
|
294
|
+
bootnode=bootnode,
|
|
295
|
+
bootnode_peer_id=bootnode_peer_id,
|
|
296
|
+
client_peer_id=client_peer_id,
|
|
297
|
+
delegate_reward_rate=delegate_rate,
|
|
298
|
+
unique=unique,
|
|
299
|
+
non_unique=non_unique,
|
|
300
|
+
coldkey=coldkey,
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
__all__ = ["app"]
|