cartha-cli 1.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.
- cartha_cli/__init__.py +34 -0
- cartha_cli/bt.py +206 -0
- cartha_cli/commands/__init__.py +25 -0
- cartha_cli/commands/common.py +76 -0
- cartha_cli/commands/config.py +294 -0
- cartha_cli/commands/health.py +463 -0
- cartha_cli/commands/help.py +49 -0
- cartha_cli/commands/miner_password.py +283 -0
- cartha_cli/commands/miner_status.py +524 -0
- cartha_cli/commands/pair_status.py +484 -0
- cartha_cli/commands/pools.py +121 -0
- cartha_cli/commands/prove_lock.py +1260 -0
- cartha_cli/commands/register.py +274 -0
- cartha_cli/commands/shared_options.py +235 -0
- cartha_cli/commands/version.py +15 -0
- cartha_cli/config.py +75 -0
- cartha_cli/display.py +62 -0
- cartha_cli/eth712.py +7 -0
- cartha_cli/main.py +237 -0
- cartha_cli/pair.py +201 -0
- cartha_cli/utils.py +274 -0
- cartha_cli/verifier.py +342 -0
- cartha_cli/wallet.py +59 -0
- cartha_cli-1.0.0.dist-info/METADATA +180 -0
- cartha_cli-1.0.0.dist-info/RECORD +28 -0
- cartha_cli-1.0.0.dist-info/WHEEL +4 -0
- cartha_cli-1.0.0.dist-info/entry_points.txt +2 -0
- cartha_cli-1.0.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
"""Miner password command - shows password with authentication."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import bittensor as bt
|
|
8
|
+
import typer
|
|
9
|
+
from rich.json import JSON
|
|
10
|
+
|
|
11
|
+
from ..config import settings
|
|
12
|
+
from ..pair import (
|
|
13
|
+
build_pair_auth_payload,
|
|
14
|
+
get_uid_from_hotkey,
|
|
15
|
+
)
|
|
16
|
+
from ..utils import format_timestamp
|
|
17
|
+
from ..verifier import VerifierError, fetch_pair_status
|
|
18
|
+
from ..wallet import load_wallet
|
|
19
|
+
from .common import (
|
|
20
|
+
console,
|
|
21
|
+
handle_unexpected_exception,
|
|
22
|
+
handle_wallet_exception,
|
|
23
|
+
)
|
|
24
|
+
from .shared_options import (
|
|
25
|
+
wallet_name_option,
|
|
26
|
+
wallet_hotkey_option,
|
|
27
|
+
slot_option,
|
|
28
|
+
auto_fetch_uid_option,
|
|
29
|
+
network_option,
|
|
30
|
+
netuid_option,
|
|
31
|
+
json_output_option,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def miner_password(
|
|
36
|
+
wallet_name: str = wallet_name_option(required=True),
|
|
37
|
+
wallet_hotkey: str = wallet_hotkey_option(required=True),
|
|
38
|
+
slot: int | None = slot_option(),
|
|
39
|
+
auto_fetch_uid: bool = auto_fetch_uid_option(),
|
|
40
|
+
network: str = network_option(),
|
|
41
|
+
netuid: int = netuid_option(),
|
|
42
|
+
json_output: bool = json_output_option(),
|
|
43
|
+
) -> None:
|
|
44
|
+
"""DEPRECATED: View your existing miner password (requires authentication).
|
|
45
|
+
|
|
46
|
+
All arguments are optional - the CLI will prompt for wallet name and hotkey if not provided.
|
|
47
|
+
Multiple aliases available: use --wallet-name or --coldkey, --wallet-hotkey or --hotkey, -w, -wh, etc.
|
|
48
|
+
|
|
49
|
+
⚠️ This command is deprecated. The new lock flow uses session tokens instead of passwords.
|
|
50
|
+
Passwords were only used in the old LockProof flow, which has been replaced.
|
|
51
|
+
|
|
52
|
+
This command allows you to VIEW existing passwords only. Password generation is no longer supported.
|
|
53
|
+
Use 'cartha vault lock' to create new lock positions with the new flow.
|
|
54
|
+
"""
|
|
55
|
+
console.print(
|
|
56
|
+
"[bold yellow]⚠️ DEPRECATED:[/] The miner password command is deprecated. "
|
|
57
|
+
"The new lock flow uses session tokens instead of passwords."
|
|
58
|
+
)
|
|
59
|
+
console.print()
|
|
60
|
+
console.print(
|
|
61
|
+
"[dim]This command allows you to VIEW existing passwords only. "
|
|
62
|
+
"Password generation is no longer supported.[/]"
|
|
63
|
+
)
|
|
64
|
+
console.print()
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
# Auto-map netuid and verifier URL based on network
|
|
68
|
+
if network == "test":
|
|
69
|
+
netuid = 78
|
|
70
|
+
elif network == "finney":
|
|
71
|
+
netuid = 35
|
|
72
|
+
# Warn that mainnet is not live yet
|
|
73
|
+
console.print()
|
|
74
|
+
console.print("[bold yellow]⚠️ MAINNET NOT AVAILABLE YET[/]")
|
|
75
|
+
console.print("[yellow]Cartha subnet is currently in testnet phase (subnet 78).[/]")
|
|
76
|
+
console.print("[yellow]Mainnet (subnet 35) has not been announced yet.[/]")
|
|
77
|
+
console.print("[dim]Use --network test to access testnet.[/]")
|
|
78
|
+
console.print()
|
|
79
|
+
# Note: netuid parameter is kept for backwards compatibility / explicit override
|
|
80
|
+
|
|
81
|
+
from ..config import get_verifier_url_for_network
|
|
82
|
+
expected_verifier_url = get_verifier_url_for_network(network)
|
|
83
|
+
if settings.verifier_url != expected_verifier_url:
|
|
84
|
+
settings.verifier_url = expected_verifier_url
|
|
85
|
+
|
|
86
|
+
console.print("[bold cyan]Loading wallet...[/]")
|
|
87
|
+
wallet = load_wallet(wallet_name, wallet_hotkey, None)
|
|
88
|
+
hotkey = wallet.hotkey.ss58_address
|
|
89
|
+
|
|
90
|
+
# Fetch UID automatically by default, prompt if disabled
|
|
91
|
+
if slot is None:
|
|
92
|
+
if auto_fetch_uid:
|
|
93
|
+
console.print("[bold cyan]Fetching UID from subnet...[/]")
|
|
94
|
+
try:
|
|
95
|
+
slot = get_uid_from_hotkey(
|
|
96
|
+
network=network, netuid=netuid, hotkey=hotkey
|
|
97
|
+
)
|
|
98
|
+
if slot is None:
|
|
99
|
+
console.print(
|
|
100
|
+
"[bold yellow]Hotkey is not registered or has been deregistered[/] "
|
|
101
|
+
f"on netuid {netuid} ({network} network)."
|
|
102
|
+
)
|
|
103
|
+
console.print(
|
|
104
|
+
"[yellow]You do not belong to any UID at the moment.[/] "
|
|
105
|
+
"Please register your hotkey first using 'cartha miner register'."
|
|
106
|
+
)
|
|
107
|
+
raise typer.Exit(code=0)
|
|
108
|
+
console.print(f"[bold green]Found UID: {slot}[/]")
|
|
109
|
+
except typer.Exit:
|
|
110
|
+
raise
|
|
111
|
+
except Exception as exc:
|
|
112
|
+
console.print(
|
|
113
|
+
"[bold red]Failed to fetch UID automatically[/]: This may be due to Bittensor network issues."
|
|
114
|
+
)
|
|
115
|
+
console.print("[yellow]Falling back to manual input...[/]")
|
|
116
|
+
try:
|
|
117
|
+
slot_input = typer.prompt("Enter your slot UID", type=int)
|
|
118
|
+
slot = slot_input
|
|
119
|
+
console.print(f"[bold green]Using UID: {slot}[/]")
|
|
120
|
+
except (ValueError, KeyboardInterrupt):
|
|
121
|
+
console.print("[bold red]Invalid UID or cancelled.[/]")
|
|
122
|
+
raise typer.Exit(code=1) from exc
|
|
123
|
+
else:
|
|
124
|
+
console.print(
|
|
125
|
+
"[bold cyan]UID not provided.[/] "
|
|
126
|
+
"[yellow]Auto-fetch disabled. Enter UID manually.[/]"
|
|
127
|
+
)
|
|
128
|
+
try:
|
|
129
|
+
slot_input = typer.prompt(
|
|
130
|
+
"Enter your slot UID (from 'cartha miner register' output)",
|
|
131
|
+
type=int,
|
|
132
|
+
)
|
|
133
|
+
slot = slot_input
|
|
134
|
+
console.print(f"[bold green]Using UID: {slot}[/]")
|
|
135
|
+
except (ValueError, KeyboardInterrupt):
|
|
136
|
+
console.print("[bold red]Invalid UID or cancelled.[/]")
|
|
137
|
+
raise typer.Exit(code=1)
|
|
138
|
+
|
|
139
|
+
slot_id = str(slot)
|
|
140
|
+
|
|
141
|
+
console.print("[bold cyan]Signing hotkey ownership challenge...[/]")
|
|
142
|
+
auth_payload = build_pair_auth_payload(
|
|
143
|
+
network=network,
|
|
144
|
+
netuid=netuid,
|
|
145
|
+
slot=slot_id,
|
|
146
|
+
hotkey=hotkey,
|
|
147
|
+
wallet_name=wallet_name,
|
|
148
|
+
wallet_hotkey=wallet_hotkey,
|
|
149
|
+
)
|
|
150
|
+
with console.status(
|
|
151
|
+
"[bold cyan]Verifying ownership with Cartha verifier...[/]",
|
|
152
|
+
spinner="dots",
|
|
153
|
+
):
|
|
154
|
+
status = fetch_pair_status(
|
|
155
|
+
hotkey=hotkey,
|
|
156
|
+
slot=slot_id,
|
|
157
|
+
network=network,
|
|
158
|
+
netuid=netuid,
|
|
159
|
+
message=auth_payload["message"],
|
|
160
|
+
signature=auth_payload["signature"],
|
|
161
|
+
)
|
|
162
|
+
except bt.KeyFileError as exc:
|
|
163
|
+
handle_wallet_exception(
|
|
164
|
+
wallet_name=wallet_name, wallet_hotkey=wallet_hotkey, exc=exc
|
|
165
|
+
)
|
|
166
|
+
except typer.Exit:
|
|
167
|
+
raise
|
|
168
|
+
except VerifierError as exc:
|
|
169
|
+
error_msg = str(exc)
|
|
170
|
+
if "timed out" in error_msg.lower() or "timeout" in error_msg.lower():
|
|
171
|
+
console.print(f"[bold red]Request timed out[/]")
|
|
172
|
+
console.print(f"[yellow]{error_msg}[/]")
|
|
173
|
+
else:
|
|
174
|
+
console.print(f"[bold red]Verifier request failed[/]: {exc}")
|
|
175
|
+
raise typer.Exit(code=1) from exc
|
|
176
|
+
except Exception as exc:
|
|
177
|
+
error_msg = str(exc)
|
|
178
|
+
error_type = type(exc).__name__
|
|
179
|
+
|
|
180
|
+
is_timeout = (
|
|
181
|
+
"timed out" in error_msg.lower()
|
|
182
|
+
or "timeout" in error_msg.lower()
|
|
183
|
+
or error_type == "Timeout"
|
|
184
|
+
or (
|
|
185
|
+
hasattr(exc, "__cause__")
|
|
186
|
+
and exc.__cause__ is not None
|
|
187
|
+
and (
|
|
188
|
+
"timeout" in str(exc.__cause__).lower()
|
|
189
|
+
or "Timeout" in type(exc.__cause__).__name__
|
|
190
|
+
)
|
|
191
|
+
)
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
if is_timeout:
|
|
195
|
+
console.print(f"[bold red]Request timed out[/]")
|
|
196
|
+
console.print(
|
|
197
|
+
f"[yellow]CLI failed to reach Cartha verifier\n"
|
|
198
|
+
f"Possible causes: Network latency or the verifier is receiving too many requests\n"
|
|
199
|
+
f"Tip: Try again in a moment\n"
|
|
200
|
+
f"Error details: {error_msg}[/]"
|
|
201
|
+
)
|
|
202
|
+
raise typer.Exit(code=1) from exc
|
|
203
|
+
|
|
204
|
+
handle_unexpected_exception("Unable to fetch password", exc)
|
|
205
|
+
|
|
206
|
+
initial_status = dict(status)
|
|
207
|
+
existing_pwd = initial_status.get("pwd")
|
|
208
|
+
state = initial_status.get("state") or "unknown"
|
|
209
|
+
has_pwd_flag = initial_status.get("has_pwd") or bool(existing_pwd)
|
|
210
|
+
|
|
211
|
+
# Password generation is deprecated - only allow viewing existing passwords
|
|
212
|
+
if not has_pwd_flag and not json_output:
|
|
213
|
+
console.print()
|
|
214
|
+
console.print(
|
|
215
|
+
"[bold yellow]⚠️ No password found for this miner.[/]"
|
|
216
|
+
)
|
|
217
|
+
console.print()
|
|
218
|
+
console.print(
|
|
219
|
+
"[dim]Password generation is no longer supported. "
|
|
220
|
+
"The new lock flow uses session tokens instead of passwords.[/]"
|
|
221
|
+
)
|
|
222
|
+
console.print()
|
|
223
|
+
console.print(
|
|
224
|
+
"[bold cyan]To create a lock position, use the new lock flow:[/]"
|
|
225
|
+
)
|
|
226
|
+
console.print(" [green]cartha vault lock[/] --coldkey <name> --hotkey <name> --pool-id <pool> --amount <amount> --lock-days <days> --owner-evm <address> --chain-id <chain> --vault-address <vault>")
|
|
227
|
+
console.print()
|
|
228
|
+
raise typer.Exit(code=0)
|
|
229
|
+
|
|
230
|
+
sanitized = dict(status)
|
|
231
|
+
sanitized.setdefault("state", "unknown")
|
|
232
|
+
password = sanitized.get("pwd")
|
|
233
|
+
issued_at = sanitized.get("issued_at")
|
|
234
|
+
|
|
235
|
+
if json_output:
|
|
236
|
+
console.print(JSON.from_data(sanitized))
|
|
237
|
+
if password:
|
|
238
|
+
console.print(
|
|
239
|
+
"[bold yellow]Keep it safe[/] — for your eyes only. Exposure might allow others to steal your locked USDC rewards."
|
|
240
|
+
)
|
|
241
|
+
return
|
|
242
|
+
|
|
243
|
+
# Display password information
|
|
244
|
+
from rich.table import Table
|
|
245
|
+
from datetime import datetime
|
|
246
|
+
|
|
247
|
+
table = Table(title="Miner Password", show_header=False)
|
|
248
|
+
table.add_row("Hotkey", hotkey)
|
|
249
|
+
table.add_row("Slot UID", slot_id)
|
|
250
|
+
table.add_row("Password issued", "yes" if sanitized.get("has_pwd") else "no")
|
|
251
|
+
|
|
252
|
+
if issued_at:
|
|
253
|
+
try:
|
|
254
|
+
if isinstance(issued_at, (int, float)) or (
|
|
255
|
+
isinstance(issued_at, str) and issued_at.isdigit()
|
|
256
|
+
):
|
|
257
|
+
formatted_time = format_timestamp(issued_at)
|
|
258
|
+
elif isinstance(issued_at, str):
|
|
259
|
+
try:
|
|
260
|
+
dt = datetime.fromisoformat(issued_at.replace("Z", "+00:00"))
|
|
261
|
+
timestamp = dt.timestamp()
|
|
262
|
+
formatted_time = format_timestamp(timestamp)
|
|
263
|
+
except (ValueError, AttributeError):
|
|
264
|
+
formatted_time = issued_at
|
|
265
|
+
else:
|
|
266
|
+
formatted_time = str(issued_at)
|
|
267
|
+
table.add_row("Password issued at", formatted_time)
|
|
268
|
+
except Exception:
|
|
269
|
+
table.add_row("Password issued at", str(issued_at))
|
|
270
|
+
|
|
271
|
+
if password:
|
|
272
|
+
table.add_row("Pair password", password)
|
|
273
|
+
|
|
274
|
+
console.print(table)
|
|
275
|
+
|
|
276
|
+
# Show password warning
|
|
277
|
+
if password:
|
|
278
|
+
console.print()
|
|
279
|
+
console.print(
|
|
280
|
+
"[bold yellow]🔐 Keep your password safe[/] — Exposure might allow others to steal your locked USDC rewards."
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
return
|