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
src/htcli/__init__.py
ADDED
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Clean client structure for Hypertensor CLI using 3-layer architecture.
|
|
3
|
+
The client only manages connections and exposes the 3 layers directly.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
from substrateinterface import SubstrateInterface
|
|
10
|
+
|
|
11
|
+
# Import logging
|
|
12
|
+
from ..utils.logging import get_logger
|
|
13
|
+
from .extrinsics import (
|
|
14
|
+
ConsensusExtrinsics,
|
|
15
|
+
GovernanceExtrinsics,
|
|
16
|
+
IdentityExtrinsics,
|
|
17
|
+
NodeExtrinsics,
|
|
18
|
+
OverwatchExtrinsics,
|
|
19
|
+
StakingExtrinsics,
|
|
20
|
+
SubnetExtrinsics,
|
|
21
|
+
ValidatorExtrinsics,
|
|
22
|
+
WalletExtrinsics,
|
|
23
|
+
)
|
|
24
|
+
from .offchain import BackupManager, ConfigManager, WalletManager
|
|
25
|
+
from .rpc import (
|
|
26
|
+
ChainRpcClient,
|
|
27
|
+
OverwatchRpcClient,
|
|
28
|
+
StakingRpcClient,
|
|
29
|
+
SubnetNodeRpcClient,
|
|
30
|
+
SubnetRpcClient,
|
|
31
|
+
WalletRpcClient,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
logger = get_logger(__name__)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class RPCLayer:
|
|
38
|
+
"""Container for RPC (read-only) operations."""
|
|
39
|
+
|
|
40
|
+
def __init__(self, substrate):
|
|
41
|
+
self.chain = ChainRpcClient(substrate)
|
|
42
|
+
self.subnet = SubnetRpcClient(substrate)
|
|
43
|
+
self.wallet = WalletRpcClient(substrate)
|
|
44
|
+
self.node = SubnetNodeRpcClient(substrate)
|
|
45
|
+
self.staking = StakingRpcClient(substrate)
|
|
46
|
+
self.overwatch = OverwatchRpcClient(substrate)
|
|
47
|
+
self.identity = IdentityExtrinsics(substrate)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class ExtrinsicsLayer:
|
|
51
|
+
"""Container for Extrinsics (state-changing) operations."""
|
|
52
|
+
|
|
53
|
+
def __init__(self, substrate):
|
|
54
|
+
self.subnet = SubnetExtrinsics(substrate)
|
|
55
|
+
self.wallet = WalletExtrinsics(substrate)
|
|
56
|
+
self.node = NodeExtrinsics(substrate)
|
|
57
|
+
self.governance = GovernanceExtrinsics(substrate)
|
|
58
|
+
self.identity = IdentityExtrinsics(substrate)
|
|
59
|
+
self.staking = StakingExtrinsics(substrate)
|
|
60
|
+
self.overwatch = OverwatchExtrinsics(substrate)
|
|
61
|
+
self.consensus = ConsensusExtrinsics(substrate)
|
|
62
|
+
self.validator = ValidatorExtrinsics(substrate)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class OffchainLayer:
|
|
66
|
+
"""Container for Off-chain (local) operations."""
|
|
67
|
+
|
|
68
|
+
def __init__(self, config=None):
|
|
69
|
+
# Get wallet path from config if available
|
|
70
|
+
wallet_dir = None
|
|
71
|
+
if config and config.wallet and config.wallet.path:
|
|
72
|
+
wallet_dir = str(Path(config.wallet.path).expanduser())
|
|
73
|
+
self.wallet = WalletManager(wallet_dir=wallet_dir)
|
|
74
|
+
self.config = ConfigManager()
|
|
75
|
+
self.backup = BackupManager()
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class HypertensorClient:
|
|
79
|
+
"""
|
|
80
|
+
Minimal client that manages blockchain connection and exposes 3-layer architecture.
|
|
81
|
+
|
|
82
|
+
Usage:
|
|
83
|
+
client.rpc.chain.get_network_stats()
|
|
84
|
+
client.extrinsics.wallet.add_to_stake(request, keypair)
|
|
85
|
+
client.offchain.keystore.get_or_create_wallet_session(wallet_name)
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
def __init__(self, config):
|
|
89
|
+
self.config = config
|
|
90
|
+
self.substrate = None
|
|
91
|
+
self.ws_connection = None
|
|
92
|
+
|
|
93
|
+
# The 3 layers - initialized only after successful connection
|
|
94
|
+
# Initialize offchain immediately (doesn't need blockchain connection)
|
|
95
|
+
self.offchain = OffchainLayer(config=config)
|
|
96
|
+
self.rpc = None # Will be initialized in connect()
|
|
97
|
+
self.extrinsics = None # Will be initialized in connect()
|
|
98
|
+
|
|
99
|
+
def connect(
|
|
100
|
+
self, rpc_url: Optional[str] = None, force_reconnect: bool = False
|
|
101
|
+
) -> bool:
|
|
102
|
+
"""Connect to the Hypertensor blockchain and initialize the 3 layers."""
|
|
103
|
+
try:
|
|
104
|
+
# Close existing connection if force reconnecting
|
|
105
|
+
if force_reconnect and self.substrate:
|
|
106
|
+
try:
|
|
107
|
+
self.substrate.close()
|
|
108
|
+
except Exception:
|
|
109
|
+
pass # Ignore errors during close
|
|
110
|
+
self.substrate = None
|
|
111
|
+
self.rpc = None
|
|
112
|
+
self.extrinsics = None
|
|
113
|
+
|
|
114
|
+
url = rpc_url or self.config.network.endpoint
|
|
115
|
+
logger.info(f"Attempting to connect to blockchain at {url}")
|
|
116
|
+
|
|
117
|
+
# Create direct blockchain connection
|
|
118
|
+
logger.info("Creating direct blockchain connection")
|
|
119
|
+
# SubstrateInterface handles WebSocket connections internally
|
|
120
|
+
# We'll create it with the URL and let it manage the connection
|
|
121
|
+
try:
|
|
122
|
+
# Load custom type registry for encoding/decoding
|
|
123
|
+
from scalecodec.type_registry import load_type_registry_preset
|
|
124
|
+
|
|
125
|
+
from ..utils.blockchain.type_registry import CUSTOM_RPC_TYPE_REGISTRY
|
|
126
|
+
|
|
127
|
+
# Merge custom types with legacy preset
|
|
128
|
+
type_registry = load_type_registry_preset("legacy")
|
|
129
|
+
type_registry.update(CUSTOM_RPC_TYPE_REGISTRY)
|
|
130
|
+
|
|
131
|
+
# Try with use_remote_preset for faster metadata loading
|
|
132
|
+
self.substrate = SubstrateInterface(
|
|
133
|
+
url=url,
|
|
134
|
+
use_remote_preset=True, # Use remote metadata preset for faster init
|
|
135
|
+
type_registry=type_registry, # Add custom type registry
|
|
136
|
+
)
|
|
137
|
+
except Exception as init_error:
|
|
138
|
+
logger.warning(
|
|
139
|
+
f"Connection with remote preset failed: {init_error}, trying without preset..."
|
|
140
|
+
)
|
|
141
|
+
# Fallback to basic connection without remote preset
|
|
142
|
+
try:
|
|
143
|
+
from scalecodec.type_registry import load_type_registry_preset
|
|
144
|
+
|
|
145
|
+
from ..utils.blockchain.type_registry import (
|
|
146
|
+
CUSTOM_RPC_TYPE_REGISTRY,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
type_registry = load_type_registry_preset("legacy")
|
|
150
|
+
type_registry.update(CUSTOM_RPC_TYPE_REGISTRY)
|
|
151
|
+
|
|
152
|
+
self.substrate = SubstrateInterface(
|
|
153
|
+
url=url,
|
|
154
|
+
type_registry=type_registry, # Add custom type registry
|
|
155
|
+
)
|
|
156
|
+
except Exception as fallback_error:
|
|
157
|
+
logger.error(
|
|
158
|
+
f"Connection failed even without preset: {fallback_error}"
|
|
159
|
+
)
|
|
160
|
+
raise
|
|
161
|
+
|
|
162
|
+
# Initialize runtime metadata (required for queries to work)
|
|
163
|
+
# This must be done before any queries to ensure metadata is loaded
|
|
164
|
+
# Add timeout to prevent hanging indefinitely
|
|
165
|
+
try:
|
|
166
|
+
import signal
|
|
167
|
+
|
|
168
|
+
timeout_seconds = self.config.network.timeout or 30
|
|
169
|
+
|
|
170
|
+
def timeout_handler(signum, frame):
|
|
171
|
+
raise TimeoutError(
|
|
172
|
+
f"Runtime initialization timed out after {timeout_seconds}s"
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# Set timeout (Unix only - Windows will skip this)
|
|
176
|
+
try:
|
|
177
|
+
old_handler = signal.signal(signal.SIGALRM, timeout_handler)
|
|
178
|
+
signal.alarm(timeout_seconds)
|
|
179
|
+
except (AttributeError, ValueError):
|
|
180
|
+
# Windows doesn't support SIGALRM, skip timeout
|
|
181
|
+
old_handler = None
|
|
182
|
+
|
|
183
|
+
try:
|
|
184
|
+
self.substrate.init_runtime()
|
|
185
|
+
logger.debug("Runtime metadata initialized successfully")
|
|
186
|
+
finally:
|
|
187
|
+
# Cancel timeout
|
|
188
|
+
if old_handler is not None:
|
|
189
|
+
try:
|
|
190
|
+
signal.alarm(0)
|
|
191
|
+
signal.signal(signal.SIGALRM, old_handler)
|
|
192
|
+
except (AttributeError, ValueError):
|
|
193
|
+
pass
|
|
194
|
+
except TimeoutError as timeout_error:
|
|
195
|
+
logger.error(f"Runtime initialization timed out: {timeout_error}")
|
|
196
|
+
raise Exception(
|
|
197
|
+
f"Cannot connect: metadata initialization timed out after {timeout_seconds}s. "
|
|
198
|
+
f"This usually means the connection is very slow or the endpoint is unreachable."
|
|
199
|
+
) from timeout_error
|
|
200
|
+
except Exception as meta_error:
|
|
201
|
+
logger.error(f"Failed to initialize runtime metadata: {meta_error}")
|
|
202
|
+
# Don't continue if metadata init fails - queries won't work
|
|
203
|
+
raise Exception(
|
|
204
|
+
f"Cannot connect: metadata initialization failed: {meta_error}"
|
|
205
|
+
) from meta_error
|
|
206
|
+
|
|
207
|
+
# Test the connection with a simple query to verify metadata is loaded
|
|
208
|
+
try:
|
|
209
|
+
# Try a simple query to ensure metadata is working
|
|
210
|
+
_ = self.substrate.query(
|
|
211
|
+
"System", "Account", ["0x0000000000000000000000000000000000000000"]
|
|
212
|
+
)
|
|
213
|
+
chain_properties = self.substrate.properties
|
|
214
|
+
logger.info(f"Connected to blockchain at {url}")
|
|
215
|
+
logger.info(f"Chain: {chain_properties.get('tokenSymbol', 'Unknown')}")
|
|
216
|
+
logger.debug("Connection test query successful - metadata is loaded")
|
|
217
|
+
except Exception as test_error:
|
|
218
|
+
logger.error(f"Connection test failed: {test_error}")
|
|
219
|
+
# If test query fails, connection is not usable
|
|
220
|
+
raise Exception(
|
|
221
|
+
f"Cannot connect: test query failed: {test_error}"
|
|
222
|
+
) from test_error
|
|
223
|
+
|
|
224
|
+
# Initialize the 3 layers only if connection successful
|
|
225
|
+
if self.substrate:
|
|
226
|
+
self.rpc = RPCLayer(self.substrate)
|
|
227
|
+
self.extrinsics = ExtrinsicsLayer(self.substrate)
|
|
228
|
+
self.offchain = OffchainLayer(config=self.config)
|
|
229
|
+
return True
|
|
230
|
+
else:
|
|
231
|
+
logger.error("Substrate connection not established")
|
|
232
|
+
return False
|
|
233
|
+
|
|
234
|
+
except Exception as e:
|
|
235
|
+
logger.error(f"Failed to connect to blockchain: {e}")
|
|
236
|
+
logger.error("Connection details:")
|
|
237
|
+
logger.error(f" URL: {url}")
|
|
238
|
+
logger.error(f" Timeout: {self.config.network.timeout}s")
|
|
239
|
+
logger.error(f" Network type: {self.config.network.network_type}")
|
|
240
|
+
|
|
241
|
+
# Provide helpful error message for network issues
|
|
242
|
+
if "Temporary failure in name resolution" in str(e):
|
|
243
|
+
logger.error("\n💡 Network connection issue detected:")
|
|
244
|
+
logger.error(" The blockchain endpoint is unreachable.")
|
|
245
|
+
logger.error(" This could be due to:")
|
|
246
|
+
logger.error(" • Network connectivity issues")
|
|
247
|
+
logger.error(" • DNS resolution problems")
|
|
248
|
+
logger.error(" • The endpoint being temporarily down")
|
|
249
|
+
logger.error("\n Try:")
|
|
250
|
+
logger.error(" • Check your internet connection")
|
|
251
|
+
logger.error(" • Try a different network")
|
|
252
|
+
logger.error(" • Contact the network administrator")
|
|
253
|
+
|
|
254
|
+
# Don't initialize layers with None - they should be None until connected
|
|
255
|
+
# This prevents trying to use RPC clients without a valid connection
|
|
256
|
+
self.rpc = None
|
|
257
|
+
self.extrinsics = None
|
|
258
|
+
self.offchain = OffchainLayer(
|
|
259
|
+
config=self.config
|
|
260
|
+
) # Offchain doesn't need blockchain
|
|
261
|
+
return False
|
|
262
|
+
|
|
263
|
+
def is_connected(self) -> bool:
|
|
264
|
+
"""
|
|
265
|
+
Lightweight check if client appears connected to blockchain.
|
|
266
|
+
|
|
267
|
+
This does NOT perform expensive queries - it only checks connection state.
|
|
268
|
+
For actual verification, use verify_connection() which does a query.
|
|
269
|
+
"""
|
|
270
|
+
if not self.substrate or not self.rpc or not self.extrinsics:
|
|
271
|
+
return False
|
|
272
|
+
|
|
273
|
+
try:
|
|
274
|
+
# Check WebSocket connection status if available
|
|
275
|
+
# SubstrateInterface uses websockets which can timeout
|
|
276
|
+
if hasattr(self.substrate, "websocket") and self.substrate.websocket:
|
|
277
|
+
if hasattr(self.substrate.websocket, "connected"):
|
|
278
|
+
if not self.substrate.websocket.connected:
|
|
279
|
+
logger.debug(
|
|
280
|
+
"WebSocket connection check failed - not connected"
|
|
281
|
+
)
|
|
282
|
+
return False
|
|
283
|
+
elif hasattr(self.substrate.websocket, "sock"):
|
|
284
|
+
# Alternative check: see if socket exists
|
|
285
|
+
if self.substrate.websocket.sock is None:
|
|
286
|
+
logger.debug("WebSocket socket check failed - no socket")
|
|
287
|
+
return False
|
|
288
|
+
|
|
289
|
+
# Lightweight check: just verify properties exist (no network call)
|
|
290
|
+
# This is much faster than a query
|
|
291
|
+
try:
|
|
292
|
+
_ = self.substrate.properties
|
|
293
|
+
return True
|
|
294
|
+
except Exception:
|
|
295
|
+
return False
|
|
296
|
+
except (AttributeError, Exception) as e:
|
|
297
|
+
# Connection appears dead
|
|
298
|
+
logger.debug(f"Lightweight connection check failed: {e}")
|
|
299
|
+
return False
|
|
300
|
+
|
|
301
|
+
def verify_connection(self) -> bool:
|
|
302
|
+
"""
|
|
303
|
+
Perform an actual query to verify the connection is working.
|
|
304
|
+
This is more expensive but more reliable than is_connected().
|
|
305
|
+
Use this when you need to be certain the connection works.
|
|
306
|
+
"""
|
|
307
|
+
if not self.is_connected():
|
|
308
|
+
return False
|
|
309
|
+
|
|
310
|
+
try:
|
|
311
|
+
# Do a lightweight query to verify connection actually works
|
|
312
|
+
_ = self.substrate.query(
|
|
313
|
+
"System", "Account", ["0x0000000000000000000000000000000000000000"]
|
|
314
|
+
)
|
|
315
|
+
return True
|
|
316
|
+
except Exception as query_error:
|
|
317
|
+
logger.debug(f"Connection verification query failed: {query_error}")
|
|
318
|
+
return False
|
|
319
|
+
|
|
320
|
+
def disconnect(self):
|
|
321
|
+
"""Disconnect from blockchain."""
|
|
322
|
+
if self.substrate:
|
|
323
|
+
try:
|
|
324
|
+
self.substrate.close()
|
|
325
|
+
except Exception:
|
|
326
|
+
pass # Ignore errors during disconnect
|
|
327
|
+
if self.ws_connection:
|
|
328
|
+
try:
|
|
329
|
+
self.ws_connection.close()
|
|
330
|
+
except Exception:
|
|
331
|
+
pass # Ignore errors during disconnect
|
|
332
|
+
# Reset layers
|
|
333
|
+
self.rpc = None
|
|
334
|
+
self.extrinsics = None
|
|
335
|
+
self.substrate = None
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
__all__ = ["HypertensorClient"]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Extrinsics module for blockchain state-changing operations.
|
|
3
|
+
Contains clients for submitting transactions that modify blockchain state.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .consensus import ConsensusExtrinsics
|
|
7
|
+
from .governance import GovernanceExtrinsics
|
|
8
|
+
from .identity import IdentityExtrinsics
|
|
9
|
+
from .node import NodeExtrinsics
|
|
10
|
+
from .overwatch import OverwatchExtrinsics
|
|
11
|
+
from .staking import StakingExtrinsics
|
|
12
|
+
from .subnet import SubnetExtrinsics
|
|
13
|
+
from .validator import ValidatorExtrinsics
|
|
14
|
+
from .wallet import WalletExtrinsics
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"SubnetExtrinsics",
|
|
18
|
+
"WalletExtrinsics",
|
|
19
|
+
"NodeExtrinsics",
|
|
20
|
+
"StakingExtrinsics",
|
|
21
|
+
"IdentityExtrinsics",
|
|
22
|
+
"GovernanceExtrinsics",
|
|
23
|
+
"OverwatchExtrinsics",
|
|
24
|
+
"ConsensusExtrinsics",
|
|
25
|
+
"ValidatorExtrinsics",
|
|
26
|
+
]
|