13
13
from websockets .exceptions import ConnectionClosed
14
14
15
15
from async_substrate_interface .async_substrate import AsyncSubstrateInterface , Websocket
16
- from async_substrate_interface .errors import MaxRetriesExceeded
16
+ from async_substrate_interface .errors import MaxRetriesExceeded , StateDiscardedError
17
17
from async_substrate_interface .sync_substrate import SubstrateInterface
18
18
19
19
logger = logging .getLogger ("async_substrate_interface" )
@@ -117,13 +117,17 @@ def __init__(
117
117
max_retries : int = 5 ,
118
118
retry_timeout : float = 60.0 ,
119
119
_mock : bool = False ,
120
+ archive_nodes : Optional [list [str ]] = None ,
120
121
):
121
122
fallback_chains = fallback_chains or []
122
123
self .fallback_chains = (
123
124
iter (fallback_chains )
124
125
if not retry_forever
125
126
else cycle (fallback_chains + [url ])
126
127
)
128
+ self .archive_nodes = (
129
+ iter (archive_nodes ) if not retry_forever else cycle (archive_nodes )
130
+ )
127
131
self .use_remote_preset = use_remote_preset
128
132
self .chain_name = chain_name
129
133
self ._mock = _mock
@@ -174,20 +178,32 @@ def _retry(self, method, *args, **kwargs):
174
178
EOFError ,
175
179
ConnectionClosed ,
176
180
TimeoutError ,
181
+ socket .gaierror ,
182
+ StateDiscardedError ,
177
183
) as e :
184
+ use_archive = isinstance (e , StateDiscardedError )
178
185
try :
179
- self ._reinstantiate_substrate (e )
186
+ self ._reinstantiate_substrate (e , use_archive = use_archive )
180
187
return method_ (* args , ** kwargs )
181
188
except StopIteration :
182
189
logger .error (
183
190
f"Max retries exceeded with { self .url } . No more fallback chains."
184
191
)
185
192
raise MaxRetriesExceeded
186
193
187
- def _reinstantiate_substrate (self , e : Optional [Exception ] = None ) -> None :
188
- next_network = next (self .fallback_chains )
194
+ def _reinstantiate_substrate (
195
+ self , e : Optional [Exception ] = None , use_archive : bool = False
196
+ ) -> None :
197
+ if use_archive :
198
+ bh = getattr (e , "block_hash" , "Unknown Block Hash" )
199
+ logger .info (
200
+ f"Attempt made to { bh } failed for state discarded. Attempting to switch to archive node."
201
+ )
202
+ next_network = next (self .archive_nodes )
203
+ else :
204
+ next_network = next (self .fallback_chains )
189
205
self .ws .close ()
190
- if e . __class__ == MaxRetriesExceeded :
206
+ if isinstance ( e , MaxRetriesExceeded ) :
191
207
logger .error (
192
208
f"Max retries exceeded with { self .url } . Retrying with { next_network } ."
193
209
)
@@ -243,13 +259,17 @@ def __init__(
243
259
max_retries : int = 5 ,
244
260
retry_timeout : float = 60.0 ,
245
261
_mock : bool = False ,
262
+ archive_nodes : Optional [list [str ]] = None ,
246
263
):
247
264
fallback_chains = fallback_chains or []
248
265
self .fallback_chains = (
249
266
iter (fallback_chains )
250
267
if not retry_forever
251
268
else cycle (fallback_chains + [url ])
252
269
)
270
+ self .archive_nodes = (
271
+ iter (archive_nodes ) if not retry_forever else cycle (archive_nodes )
272
+ )
253
273
self .use_remote_preset = use_remote_preset
254
274
self .chain_name = chain_name
255
275
self ._mock = _mock
@@ -272,9 +292,18 @@ def __init__(
272
292
for method in RETRY_METHODS :
273
293
setattr (self , method , partial (self ._retry , method ))
274
294
275
- async def _reinstantiate_substrate (self , e : Optional [Exception ] = None ) -> None :
276
- next_network = next (self .fallback_chains )
277
- if e .__class__ == MaxRetriesExceeded :
295
+ async def _reinstantiate_substrate (
296
+ self , e : Optional [Exception ] = None , use_archive : bool = False
297
+ ) -> None :
298
+ if use_archive :
299
+ bh = getattr (e , "block_hash" , "Unknown Block Hash" )
300
+ logger .info (
301
+ f"Attempt made to { bh } failed for state discarded. Attempting to switch to archive node."
302
+ )
303
+ next_network = next (self .archive_nodes )
304
+ else :
305
+ next_network = next (self .fallback_chains )
306
+ if isinstance (e , MaxRetriesExceeded ):
278
307
logger .error (
279
308
f"Max retries exceeded with { self .url } . Retrying with { next_network } ."
280
309
)
@@ -314,9 +343,11 @@ async def _retry(self, method, *args, **kwargs):
314
343
ConnectionClosed ,
315
344
EOFError ,
316
345
socket .gaierror ,
346
+ StateDiscardedError ,
317
347
) as e :
348
+ use_archive = isinstance (e , StateDiscardedError )
318
349
try :
319
- await self ._reinstantiate_substrate (e )
350
+ await self ._reinstantiate_substrate (e , use_archive = use_archive )
320
351
return await method_ (* args , ** kwargs )
321
352
except StopAsyncIteration :
322
353
logger .error (
0 commit comments