|
16 | 16 | from bittensor.core.chain_data import NeuronInfo, NeuronInfoLite |
17 | 17 | from bittensor.utils import determine_chain_endpoint_and_network |
18 | 18 |
|
19 | | -SubstrateClass = Type[Union[SubstrateInterface, AsyncSubstrateInterface]] |
20 | | - |
21 | | - |
22 | | -class RetrySubstrate: |
23 | | - def __init__( |
24 | | - self, |
25 | | - substrate: SubstrateClass, |
26 | | - main_url: str, |
27 | | - ss58_format: int, |
28 | | - type_registry: dict, |
29 | | - use_remote_preset: bool, |
30 | | - chain_name: str, |
31 | | - _mock: bool, |
32 | | - fallback_chains: Optional[list[str]] = None, |
33 | | - retry_forever: bool = False, |
34 | | - ): |
35 | | - fallback_chains = fallback_chains or [] |
36 | | - self._substrate_class: SubstrateClass = substrate |
37 | | - self.ss58_format: int = ss58_format |
38 | | - self.type_registry: dict = type_registry |
39 | | - self.use_remote_preset: bool = use_remote_preset |
40 | | - self.chain_name: str = chain_name |
41 | | - self._mock = _mock |
42 | | - self.fallback_chains = ( |
43 | | - iter(fallback_chains) |
44 | | - if not retry_forever |
45 | | - else cycle(fallback_chains + [main_url]) |
46 | | - ) |
47 | | - initialized = False |
48 | | - for chain_url in [main_url] + fallback_chains: |
49 | | - try: |
50 | | - self._substrate = self._substrate_class( |
51 | | - url=chain_url, |
52 | | - ss58_format=ss58_format, |
53 | | - type_registry=type_registry, |
54 | | - use_remote_preset=use_remote_preset, |
55 | | - chain_name=chain_name, |
56 | | - _mock=_mock, |
57 | | - ) |
58 | | - initialized = True |
59 | | - break |
60 | | - except ConnectionError: |
61 | | - logging.warning(f"Unable to connect to {chain_url}") |
62 | | - if not initialized: |
63 | | - raise ConnectionError( |
64 | | - f"Unable to connect at any chains specified: {[main_url]+fallback_chains}" |
65 | | - ) |
66 | | - |
67 | | - # retries |
68 | | - |
69 | | - # TODO: properties that need retry logic |
70 | | - # properties |
71 | | - # version |
72 | | - # token_decimals |
73 | | - # token_symbol |
74 | | - # name |
75 | | - |
76 | | - retry = ( |
77 | | - self._async_retry |
78 | | - if self._substrate_class == AsyncSubstrateInterface |
79 | | - else self._retry |
80 | | - ) |
81 | | - |
82 | | - self._get_block_handler = partial(retry, "_get_block_handler") |
83 | | - self.apply_type_registry_presets = partial(retry, "apply_type_registry_presets") |
84 | | - self.close = partial(retry, "close") |
85 | | - self.compose_call = partial(retry, "compose_call") |
86 | | - self.connect = partial(retry, "connect") |
87 | | - self.create_scale_object = partial(retry, "create_scale_object") |
88 | | - self.create_signed_extrinsic = partial(retry, "create_signed_extrinsic") |
89 | | - self.create_storage_key = partial(retry, "create_storage_key") |
90 | | - self.decode_scale = partial(retry, "decode_scale") |
91 | | - self.encode_scale = partial(retry, "encode_scale") |
92 | | - self.extension_call = partial(retry, "extension_call") |
93 | | - self.filter_events = partial(retry, "filter_events") |
94 | | - self.filter_extrinsics = partial(retry, "filter_extrinsics") |
95 | | - self.generate_signature_payload = partial(retry, "generate_signature_payload") |
96 | | - self.get_account_next_index = partial(retry, "get_account_next_index") |
97 | | - self.get_account_nonce = partial(retry, "get_account_nonce") |
98 | | - self.get_block = partial(retry, "get_block") |
99 | | - self.get_block_hash = partial(retry, "get_block_hash") |
100 | | - self.get_block_header = partial(retry, "get_block_header") |
101 | | - self.get_block_metadata = partial(retry, "get_block_metadata") |
102 | | - self.get_block_number = partial(retry, "get_block_number") |
103 | | - self.get_block_runtime_info = partial(retry, "get_block_runtime_info") |
104 | | - self.get_block_runtime_version_for = partial( |
105 | | - retry, "get_block_runtime_version_for" |
106 | | - ) |
107 | | - self.get_block_timestamp = partial(retry, "get_block_timestamp") |
108 | | - self.get_chain_finalised_head = partial(retry, "get_chain_finalised_head") |
109 | | - self.get_chain_head = partial(retry, "get_chain_head") |
110 | | - self.get_constant = partial(retry, "get_constant") |
111 | | - self.get_events = partial(retry, "get_events") |
112 | | - self.get_extrinsics = partial(retry, "get_extrinsics") |
113 | | - self.get_metadata_call_function = partial(retry, "get_metadata_call_function") |
114 | | - self.get_metadata_constant = partial(retry, "get_metadata_constant") |
115 | | - self.get_metadata_error = partial(retry, "get_metadata_error") |
116 | | - self.get_metadata_errors = partial(retry, "get_metadata_errors") |
117 | | - self.get_metadata_module = partial(retry, "get_metadata_module") |
118 | | - self.get_metadata_modules = partial(retry, "get_metadata_modules") |
119 | | - self.get_metadata_runtime_call_function = partial( |
120 | | - retry, "get_metadata_runtime_call_function" |
121 | | - ) |
122 | | - self.get_metadata_runtime_call_functions = partial( |
123 | | - retry, "get_metadata_runtime_call_functions" |
124 | | - ) |
125 | | - self.get_metadata_storage_function = partial( |
126 | | - retry, "get_metadata_storage_function" |
127 | | - ) |
128 | | - self.get_metadata_storage_functions = partial( |
129 | | - retry, "get_metadata_storage_functions" |
130 | | - ) |
131 | | - self.get_parent_block_hash = partial(retry, "get_parent_block_hash") |
132 | | - self.get_payment_info = partial(retry, "get_payment_info") |
133 | | - self.get_storage_item = partial(retry, "get_storage_item") |
134 | | - self.get_type_definition = partial(retry, "get_type_definition") |
135 | | - self.get_type_registry = partial(retry, "get_type_registry") |
136 | | - self.init_runtime = partial(retry, "init_runtime") |
137 | | - self.initialize = partial(retry, "initialize") |
138 | | - self.is_valid_ss58_address = partial(retry, "is_valid_ss58_address") |
139 | | - self.load_runtime = partial(retry, "load_runtime") |
140 | | - self.make_payload = partial(retry, "make_payload") |
141 | | - self.query = partial(retry, "query") |
142 | | - self.query_map = partial(retry, "query_map") |
143 | | - self.query_multi = partial(retry, "query_multi") |
144 | | - self.query_multiple = partial(retry, "query_multiple") |
145 | | - self.reload_type_registry = partial(retry, "reload_type_registry") |
146 | | - self.retrieve_extrinsic_by_hash = partial(retry, "retrieve_extrinsic_by_hash") |
147 | | - self.retrieve_extrinsic_by_identifier = partial( |
148 | | - retry, "retrieve_extrinsic_by_identifier" |
149 | | - ) |
150 | | - self.rpc_request = partial(retry, "rpc_request") |
151 | | - self.runtime_call = partial(retry, "runtime_call") |
152 | | - self.search_block_number = partial(retry, "search_block_number") |
153 | | - self.serialize_constant = partial(retry, "serialize_constant") |
154 | | - self.serialize_module_call = partial(retry, "serialize_module_call") |
155 | | - self.serialize_module_error = partial(retry, "serialize_module_error") |
156 | | - self.serialize_module_event = partial(retry, "serialize_module_event") |
157 | | - self.serialize_storage_item = partial(retry, "serialize_storage_item") |
158 | | - self.ss58_decode = partial(retry, "ss58_decode") |
159 | | - self.ss58_encode = partial(retry, "ss58_encode") |
160 | | - self.submit_extrinsic = partial(retry, "submit_extrinsic") |
161 | | - self.subscribe_block_headers = partial(retry, "subscribe_block_headers") |
162 | | - self.supports_rpc_method = partial(retry, "supports_rpc_method") |
163 | | - self.ws = self._substrate.ws |
164 | | - |
165 | | - def _retry(self, method, *args, **kwargs): |
166 | | - try: |
167 | | - method_ = getattr(self._substrate, method) |
168 | | - return method_(*args, **kwargs) |
169 | | - except (MaxRetriesExceeded, ConnectionError, ConnectionRefusedError) as e: |
170 | | - try: |
171 | | - self._reinstantiate_substrate() |
172 | | - method_ = getattr(self._substrate, method) |
173 | | - return self._retry(method_(*args, **kwargs)) |
174 | | - except StopIteration: |
175 | | - logging.error( |
176 | | - f"Max retries exceeded with {self._substrate.url}. No more fallback chains." |
177 | | - ) |
178 | | - raise MaxRetriesExceeded |
179 | | - |
180 | | - async def _async_retry(self, method, *args, **kwargs): |
181 | | - try: |
182 | | - method_ = getattr(self._substrate, method) |
183 | | - if asyncio.iscoroutinefunction(method_): |
184 | | - return await method_(*args, **kwargs) |
185 | | - else: |
186 | | - return method_(*args, **kwargs) |
187 | | - except (MaxRetriesExceeded, ConnectionError, ConnectionRefusedError) as e: |
188 | | - try: |
189 | | - self._reinstantiate_substrate(e) |
190 | | - method_ = getattr(self._substrate, method) |
191 | | - if asyncio.iscoroutinefunction(method_): |
192 | | - return await method_(*args, **kwargs) |
193 | | - else: |
194 | | - return method_(*args, **kwargs) |
195 | | - except StopIteration: |
196 | | - logging.error( |
197 | | - f"Max retries exceeded with {self._substrate.url}. No more fallback chains." |
198 | | - ) |
199 | | - raise MaxRetriesExceeded |
200 | | - |
201 | | - def _reinstantiate_substrate(self, e: Optional[Exception] = None) -> None: |
202 | | - next_network = next(self.fallback_chains) |
203 | | - if e.__class__ == MaxRetriesExceeded: |
204 | | - logging.error( |
205 | | - f"Max retries exceeded with {self._substrate.url}. Retrying with {next_network}." |
206 | | - ) |
207 | | - else: |
208 | | - print(f"Connection error. Trying again with {next_network}") |
209 | | - self._substrate = self._substrate_class( |
210 | | - url=next_network, |
211 | | - ss58_format=self.ss58_format, |
212 | | - type_registry=self.type_registry, |
213 | | - use_remote_preset=self.use_remote_preset, |
214 | | - chain_name=self.chain_name, |
215 | | - _mock=self._mock, |
216 | | - ) |
217 | | - |
218 | 19 |
|
219 | 20 | class SubtensorMixin(ABC): |
220 | 21 | network: str |
|
0 commit comments