tonutils 2.0.1b2__py3-none-any.whl → 2.0.1b4__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.
- tonutils/__init__.py +0 -2
- tonutils/__meta__.py +1 -1
- tonutils/cli.py +111 -0
- tonutils/clients/__init__.py +7 -11
- tonutils/clients/adnl/__init__.py +7 -3
- tonutils/clients/adnl/balancer.py +362 -168
- tonutils/clients/adnl/client.py +203 -67
- tonutils/clients/adnl/provider/config.py +24 -25
- tonutils/clients/adnl/provider/models.py +4 -0
- tonutils/clients/adnl/provider/provider.py +203 -160
- tonutils/clients/adnl/provider/transport.py +44 -33
- tonutils/clients/adnl/provider/workers/base.py +0 -2
- tonutils/clients/adnl/provider/workers/pinger.py +1 -1
- tonutils/clients/adnl/provider/workers/reader.py +3 -2
- tonutils/clients/adnl/{provider/builder.py → utils.py} +62 -2
- tonutils/clients/http/__init__.py +11 -8
- tonutils/clients/http/balancer.py +75 -63
- tonutils/clients/http/clients/__init__.py +13 -0
- tonutils/clients/http/clients/chainstack.py +48 -0
- tonutils/clients/http/clients/quicknode.py +47 -0
- tonutils/clients/http/clients/tatum.py +56 -0
- tonutils/clients/http/{tonapi/client.py → clients/tonapi.py} +31 -31
- tonutils/clients/http/{toncenter/client.py → clients/toncenter.py} +59 -48
- tonutils/clients/http/providers/__init__.py +4 -0
- tonutils/clients/http/providers/base.py +201 -0
- tonutils/clients/http/providers/response.py +85 -0
- tonutils/clients/http/providers/tonapi/__init__.py +3 -0
- tonutils/clients/http/{tonapi → providers/tonapi}/models.py +1 -0
- tonutils/clients/http/providers/tonapi/provider.py +125 -0
- tonutils/clients/http/providers/toncenter/__init__.py +3 -0
- tonutils/clients/http/{toncenter → providers/toncenter}/models.py +1 -0
- tonutils/clients/http/providers/toncenter/provider.py +119 -0
- tonutils/clients/http/utils.py +140 -0
- tonutils/clients/limiter.py +115 -0
- tonutils/contracts/__init__.py +4 -0
- tonutils/contracts/base.py +33 -20
- tonutils/contracts/dns/methods.py +2 -2
- tonutils/contracts/jetton/methods.py +2 -2
- tonutils/contracts/nft/methods.py +2 -2
- tonutils/contracts/nft/tlb.py +1 -1
- tonutils/{protocols/contract.py → contracts/protocol.py} +29 -29
- tonutils/contracts/telegram/methods.py +2 -2
- tonutils/contracts/vanity/vanity.py +1 -1
- tonutils/contracts/wallet/__init__.py +2 -0
- tonutils/contracts/wallet/base.py +3 -3
- tonutils/contracts/wallet/messages.py +1 -1
- tonutils/contracts/wallet/methods.py +2 -2
- tonutils/{protocols/wallet.py → contracts/wallet/protocol.py} +35 -35
- tonutils/contracts/wallet/versions/v5.py +3 -3
- tonutils/exceptions.py +146 -228
- tonutils/tonconnect/__init__.py +0 -0
- tonutils/tools/__init__.py +6 -0
- tonutils/tools/block_scanner/__init__.py +26 -0
- tonutils/tools/block_scanner/annotations.py +23 -0
- tonutils/tools/block_scanner/dispatcher.py +141 -0
- tonutils/tools/block_scanner/events.py +31 -0
- tonutils/tools/block_scanner/scanner.py +315 -0
- tonutils/tools/block_scanner/traversal.py +96 -0
- tonutils/tools/block_scanner/where.py +151 -0
- tonutils/tools/status_monitor/__init__.py +3 -0
- tonutils/tools/status_monitor/console.py +157 -0
- tonutils/tools/status_monitor/models.py +27 -0
- tonutils/tools/status_monitor/monitor.py +295 -0
- tonutils/types.py +125 -2
- tonutils/utils.py +3 -3
- {tonutils-2.0.1b2.dist-info → tonutils-2.0.1b4.dist-info}/METADATA +2 -5
- tonutils-2.0.1b4.dist-info/RECORD +108 -0
- tonutils-2.0.1b4.dist-info/entry_points.txt +2 -0
- tonutils/clients/adnl/provider/limiter.py +0 -56
- tonutils/clients/adnl/stack.py +0 -64
- tonutils/clients/http/chainstack/__init__.py +0 -4
- tonutils/clients/http/chainstack/client.py +0 -63
- tonutils/clients/http/chainstack/provider.py +0 -44
- tonutils/clients/http/quicknode/__init__.py +0 -4
- tonutils/clients/http/quicknode/client.py +0 -60
- tonutils/clients/http/quicknode/provider.py +0 -42
- tonutils/clients/http/tatum/__init__.py +0 -4
- tonutils/clients/http/tatum/client.py +0 -66
- tonutils/clients/http/tatum/provider.py +0 -53
- tonutils/clients/http/tonapi/__init__.py +0 -4
- tonutils/clients/http/tonapi/provider.py +0 -150
- tonutils/clients/http/tonapi/stack.py +0 -71
- tonutils/clients/http/toncenter/__init__.py +0 -4
- tonutils/clients/http/toncenter/provider.py +0 -145
- tonutils/clients/http/toncenter/stack.py +0 -73
- tonutils/protocols/__init__.py +0 -9
- tonutils-2.0.1b2.dist-info/RECORD +0 -98
- /tonutils/{protocols/client.py → clients/protocol.py} +0 -0
- {tonutils-2.0.1b2.dist-info → tonutils-2.0.1b4.dist-info}/WHEEL +0 -0
- {tonutils-2.0.1b2.dist-info → tonutils-2.0.1b4.dist-info}/licenses/LICENSE +0 -0
- {tonutils-2.0.1b2.dist-info → tonutils-2.0.1b4.dist-info}/top_level.txt +0 -0
|
@@ -18,12 +18,6 @@ from pytoniq_core import (
|
|
|
18
18
|
from pytoniq_core.crypto.ciphers import get_random
|
|
19
19
|
from pytoniq_core.crypto.crc import crc16
|
|
20
20
|
|
|
21
|
-
from tonutils.clients.adnl.provider.builder import (
|
|
22
|
-
build_contract_state_info,
|
|
23
|
-
build_shard_account,
|
|
24
|
-
build_config_all,
|
|
25
|
-
)
|
|
26
|
-
from tonutils.clients.adnl.provider.limiter import PriorityLimiter
|
|
27
21
|
from tonutils.clients.adnl.provider.models import LiteServer, MasterchainInfo
|
|
28
22
|
from tonutils.clients.adnl.provider.transport import AdnlTcpTransport
|
|
29
23
|
from tonutils.clients.adnl.provider.workers import (
|
|
@@ -31,35 +25,38 @@ from tonutils.clients.adnl.provider.workers import (
|
|
|
31
25
|
ReaderWorker,
|
|
32
26
|
UpdaterWorker,
|
|
33
27
|
)
|
|
28
|
+
from tonutils.clients.adnl.utils import (
|
|
29
|
+
build_contract_state_info,
|
|
30
|
+
build_shard_account,
|
|
31
|
+
build_config_all,
|
|
32
|
+
)
|
|
33
|
+
from tonutils.clients.limiter import RateLimiter
|
|
34
34
|
from tonutils.exceptions import (
|
|
35
|
-
AdnlHandshakeError,
|
|
36
|
-
AdnlProviderConnectError,
|
|
37
|
-
AdnlServerError,
|
|
38
|
-
AdnlProviderMissingBlockError,
|
|
39
|
-
AdnlProviderResponseError,
|
|
40
|
-
AdnlProviderClosedError,
|
|
41
35
|
ClientError,
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
NotConnectedError,
|
|
37
|
+
ProviderError,
|
|
44
38
|
RunGetMethodError,
|
|
39
|
+
ProviderTimeoutError,
|
|
40
|
+
RetryLimitError,
|
|
41
|
+
ProviderResponseError,
|
|
42
|
+
)
|
|
43
|
+
from tonutils.types import (
|
|
44
|
+
ContractStateInfo,
|
|
45
|
+
RetryPolicy,
|
|
46
|
+
WorkchainID,
|
|
45
47
|
)
|
|
46
|
-
from tonutils.types import ContractStateInfo, WorkchainID
|
|
47
48
|
|
|
48
49
|
|
|
49
50
|
class AdnlProvider:
|
|
50
|
-
"""
|
|
51
|
-
ADNL-based provider for TON lite-servers.
|
|
52
|
-
|
|
53
|
-
Handles encrypted TCP transport, ping and masterchain updates, and exposes
|
|
54
|
-
a high-level API for lite-server queries.
|
|
55
|
-
"""
|
|
51
|
+
"""ADNL-based provider for TON lite-servers."""
|
|
56
52
|
|
|
57
53
|
def __init__(
|
|
58
54
|
self,
|
|
59
55
|
node: LiteServer,
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
limiter: t.Optional[
|
|
56
|
+
connect_timeout: float = 2.0,
|
|
57
|
+
request_timeout: float = 10.0,
|
|
58
|
+
limiter: t.Optional[RateLimiter] = None,
|
|
59
|
+
retry_policy: t.Optional[RetryPolicy] = None,
|
|
63
60
|
) -> None:
|
|
64
61
|
"""
|
|
65
62
|
Initialize ADNL provider for a specific lite-server.
|
|
@@ -71,14 +68,15 @@ class AdnlProvider:
|
|
|
71
68
|
- dTON telegram bot: https://t.me/dtontech_bot (https://dton.io/)
|
|
72
69
|
|
|
73
70
|
:param node: LiteServer configuration (host, port, public key)
|
|
74
|
-
:param
|
|
75
|
-
:param
|
|
71
|
+
:param connect_timeout: Timeout in seconds for connect/reconnect
|
|
72
|
+
:param request_timeout: Timeout in seconds for queries
|
|
76
73
|
:param limiter: Optional priority-aware rate limiter
|
|
74
|
+
:param retry_policy: Optional retry policy that defines per-error-code retry rules
|
|
77
75
|
"""
|
|
78
76
|
self.node = node
|
|
79
|
-
self.
|
|
80
|
-
self.
|
|
81
|
-
self.transport = AdnlTcpTransport(self.node, self.
|
|
77
|
+
self.connect_timeout = connect_timeout
|
|
78
|
+
self.request_timeout = request_timeout
|
|
79
|
+
self.transport = AdnlTcpTransport(self.node, self.connect_timeout)
|
|
82
80
|
self.loop: t.Optional[asyncio.AbstractEventLoop] = None
|
|
83
81
|
|
|
84
82
|
self.tl_schemas = TlGenerator.with_default_schemas().generate()
|
|
@@ -92,15 +90,16 @@ class AdnlProvider:
|
|
|
92
90
|
|
|
93
91
|
self.pending: t.Dict[str, asyncio.Future] = {}
|
|
94
92
|
|
|
93
|
+
self._limiter: t.Optional[RateLimiter] = limiter
|
|
94
|
+
self._retry_policy: t.Optional[RetryPolicy] = retry_policy
|
|
95
95
|
self._connect_lock: asyncio.Lock = asyncio.Lock()
|
|
96
|
-
self._limiter: t.Optional[PriorityLimiter] = limiter
|
|
97
96
|
|
|
98
97
|
@property
|
|
99
98
|
def is_connected(self) -> bool:
|
|
100
99
|
"""
|
|
101
|
-
|
|
100
|
+
Whether the underlying transport is currently connected.
|
|
102
101
|
|
|
103
|
-
:return: True if
|
|
102
|
+
:return: True if connected, False otherwise
|
|
104
103
|
"""
|
|
105
104
|
return self.transport.is_connected
|
|
106
105
|
|
|
@@ -134,9 +133,9 @@ class AdnlProvider:
|
|
|
134
133
|
@property
|
|
135
134
|
def last_ping_ms(self) -> t.Optional[int]:
|
|
136
135
|
"""
|
|
137
|
-
Round-trip time of the last ping
|
|
136
|
+
Round-trip time of the last successful ping.
|
|
138
137
|
|
|
139
|
-
:return: Ping RTT in milliseconds or None if unknown
|
|
138
|
+
:return: Ping RTT in milliseconds, or None if unknown
|
|
140
139
|
"""
|
|
141
140
|
if self.last_ping_rtt is None:
|
|
142
141
|
return None
|
|
@@ -170,20 +169,7 @@ class AdnlProvider:
|
|
|
170
169
|
return
|
|
171
170
|
|
|
172
171
|
self.loop = asyncio.get_running_loop()
|
|
173
|
-
|
|
174
|
-
await self.transport.connect()
|
|
175
|
-
except AdnlHandshakeError as exc:
|
|
176
|
-
raise AdnlProviderConnectError(
|
|
177
|
-
host=self.node.host,
|
|
178
|
-
port=self.node.port,
|
|
179
|
-
message=str(exc),
|
|
180
|
-
) from exc
|
|
181
|
-
except OSError as exc:
|
|
182
|
-
raise AdnlProviderConnectError(
|
|
183
|
-
host=self.node.host,
|
|
184
|
-
port=self.node.port,
|
|
185
|
-
message=str(exc),
|
|
186
|
-
) from exc
|
|
172
|
+
await self.transport.connect()
|
|
187
173
|
|
|
188
174
|
tasks = [self.reader.start(), self.pinger.start(), self.updater.start()]
|
|
189
175
|
await asyncio.gather(*tasks, return_exceptions=True)
|
|
@@ -221,124 +207,93 @@ class AdnlProvider:
|
|
|
221
207
|
async with self._connect_lock:
|
|
222
208
|
await self._do_close()
|
|
223
209
|
|
|
224
|
-
async def
|
|
225
|
-
self,
|
|
226
|
-
query: bytes,
|
|
227
|
-
priority: bool = False,
|
|
228
|
-
) -> dict:
|
|
210
|
+
async def _send_once_adnl_query(self, query: bytes, *, priority: bool) -> dict:
|
|
229
211
|
"""
|
|
230
|
-
Send a
|
|
231
|
-
|
|
232
|
-
Retries temporary overload errors (228, 5556) and missing-block errors (651)
|
|
233
|
-
before returning a response or raising an exception.
|
|
212
|
+
Send a single ADNL query.
|
|
234
213
|
|
|
235
214
|
:param query: Encoded ADNL TL-query bytes
|
|
236
215
|
:param priority: Whether to use priority slot in the limiter
|
|
237
216
|
:return: Lite-server response payload as a decoded dictionary
|
|
238
217
|
"""
|
|
239
|
-
|
|
218
|
+
if not self.is_connected or self.loop is None:
|
|
219
|
+
raise NotConnectedError()
|
|
240
220
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
query: bytes,
|
|
244
|
-
priority: bool = False,
|
|
245
|
-
) -> dict:
|
|
246
|
-
"""
|
|
247
|
-
Internal wrapper adding retry handling for missing-block errors (code 651).
|
|
221
|
+
if self._limiter is not None:
|
|
222
|
+
await self._limiter.acquire(priority=priority)
|
|
248
223
|
|
|
249
|
-
|
|
250
|
-
|
|
224
|
+
query_id = get_random(32)
|
|
225
|
+
packet = self.tl_schemas.serialize(
|
|
226
|
+
self.adnl_query_tl_schema,
|
|
227
|
+
{"query_id": query_id, "query": query},
|
|
228
|
+
)
|
|
251
229
|
|
|
252
|
-
|
|
253
|
-
:
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
230
|
+
query_id_key = query_id[::-1].hex()
|
|
231
|
+
fut: asyncio.Future[t.Any] = self.loop.create_future()
|
|
232
|
+
self.pending[query_id_key] = fut
|
|
233
|
+
|
|
234
|
+
try:
|
|
235
|
+
await self.transport.send_adnl_packet(packet)
|
|
258
236
|
|
|
259
|
-
for attempt in range(max_651_retries):
|
|
260
237
|
try:
|
|
261
|
-
|
|
262
|
-
except
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
)
|
|
238
|
+
resp = await asyncio.wait_for(fut, timeout=self.request_timeout)
|
|
239
|
+
except asyncio.TimeoutError as exc:
|
|
240
|
+
raise ProviderTimeoutError(
|
|
241
|
+
timeout=self.request_timeout,
|
|
242
|
+
endpoint=self.node.endpoint,
|
|
243
|
+
operation="request",
|
|
244
|
+
) from exc
|
|
245
|
+
|
|
246
|
+
if not isinstance(resp, dict):
|
|
247
|
+
raise ProviderError(f"invalid response type: {type(resp).__name__}")
|
|
248
|
+
return resp
|
|
249
|
+
|
|
250
|
+
finally:
|
|
251
|
+
if query_id_key in self.pending:
|
|
252
|
+
del self.pending[query_id_key]
|
|
277
253
|
|
|
278
|
-
async def
|
|
254
|
+
async def send_adnl_query(
|
|
279
255
|
self,
|
|
280
256
|
query: bytes,
|
|
281
257
|
priority: bool = False,
|
|
282
258
|
) -> dict:
|
|
283
259
|
"""
|
|
284
|
-
|
|
260
|
+
Send a raw ADNL query with retry handling based on retry policy.
|
|
285
261
|
|
|
286
|
-
|
|
287
|
-
|
|
262
|
+
On server error, retries the request according to the rule associated
|
|
263
|
+
with the received error code. If no rule matches, or retry attempts are
|
|
264
|
+
exhausted, the error is raised.
|
|
288
265
|
|
|
289
266
|
:param query: Encoded ADNL TL-query bytes
|
|
290
267
|
:param priority: Whether to use priority slot in the limiter
|
|
291
|
-
:return: Lite-server response payload as a dictionary
|
|
268
|
+
:return: Lite-server response payload as a decoded dictionary
|
|
292
269
|
"""
|
|
293
|
-
|
|
294
|
-
raise ClientNotConnectedError(self)
|
|
295
|
-
|
|
296
|
-
attempts = max(self.rps_retries or 0, 1)
|
|
297
|
-
for attempt in range(attempts):
|
|
298
|
-
if self._limiter is not None:
|
|
299
|
-
await self._limiter.acquire(priority=priority)
|
|
300
|
-
|
|
301
|
-
query_id = get_random(32)
|
|
302
|
-
packet = self.tl_schemas.serialize(
|
|
303
|
-
self.adnl_query_tl_schema,
|
|
304
|
-
{
|
|
305
|
-
"query_id": query_id,
|
|
306
|
-
"query": query,
|
|
307
|
-
},
|
|
308
|
-
)
|
|
309
|
-
query_id_key = query_id[::-1].hex()
|
|
310
|
-
fut: asyncio.Future = self.loop.create_future()
|
|
311
|
-
self.pending[query_id_key] = fut
|
|
270
|
+
attempts: t.Dict[int, int] = {}
|
|
312
271
|
|
|
272
|
+
while True:
|
|
313
273
|
try:
|
|
314
|
-
await self.
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
274
|
+
return await self._send_once_adnl_query(query, priority=priority)
|
|
275
|
+
|
|
276
|
+
except ProviderResponseError as e:
|
|
277
|
+
policy = self._retry_policy
|
|
278
|
+
if policy is None:
|
|
318
279
|
raise
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
port=self.node.port,
|
|
323
|
-
) from exc
|
|
324
|
-
except AdnlServerError as e:
|
|
325
|
-
if e.code in (228, 5556):
|
|
326
|
-
if attempt < attempts - 1:
|
|
327
|
-
await asyncio.sleep(0.3 * (2**attempt))
|
|
328
|
-
continue
|
|
329
|
-
break
|
|
280
|
+
|
|
281
|
+
rule = policy.rule_for(e.code, e.message)
|
|
282
|
+
if rule is None:
|
|
330
283
|
raise
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
284
|
+
|
|
285
|
+
key = id(rule)
|
|
286
|
+
n = attempts.get(key, 0) + 1
|
|
287
|
+
attempts[key] = n
|
|
288
|
+
|
|
289
|
+
if n >= rule.attempts:
|
|
290
|
+
raise RetryLimitError(
|
|
291
|
+
attempts=n,
|
|
292
|
+
max_attempts=rule.attempts,
|
|
293
|
+
last_error=e,
|
|
294
|
+
) from e
|
|
295
|
+
|
|
296
|
+
await asyncio.sleep(rule.delay(n - 1))
|
|
342
297
|
|
|
343
298
|
async def send_liteserver_query(
|
|
344
299
|
self,
|
|
@@ -459,7 +414,7 @@ class AdnlProvider:
|
|
|
459
414
|
self,
|
|
460
415
|
workchain: WorkchainID,
|
|
461
416
|
shard: int,
|
|
462
|
-
seqno: int =
|
|
417
|
+
seqno: t.Optional[int] = None,
|
|
463
418
|
lt: t.Optional[int] = None,
|
|
464
419
|
utime: t.Optional[int] = None,
|
|
465
420
|
*,
|
|
@@ -470,43 +425,133 @@ class AdnlProvider:
|
|
|
470
425
|
|
|
471
426
|
:param workchain: Workchain identifier
|
|
472
427
|
:param shard: Shard identifier
|
|
473
|
-
:param seqno: Block
|
|
428
|
+
:param seqno: Block sequence number
|
|
474
429
|
:param lt: Logical time filter
|
|
475
430
|
:param utime: UNIX time filter
|
|
476
431
|
:param priority: Whether to use priority slot in the limiter
|
|
477
432
|
:return: Tuple of BlockIdExt and deserialized Block
|
|
478
433
|
"""
|
|
479
434
|
mode = 0
|
|
480
|
-
|
|
435
|
+
block_seqno = 0
|
|
436
|
+
|
|
437
|
+
if seqno is not None:
|
|
481
438
|
mode = 1
|
|
439
|
+
block_seqno = seqno
|
|
482
440
|
if lt is not None:
|
|
483
441
|
mode = 2
|
|
484
442
|
if utime is not None:
|
|
485
443
|
mode = 4
|
|
486
444
|
|
|
487
445
|
data = {
|
|
446
|
+
"mode": mode,
|
|
488
447
|
"id": {
|
|
489
|
-
"workchain": workchain
|
|
448
|
+
"workchain": workchain,
|
|
490
449
|
"shard": shard,
|
|
491
|
-
"seqno":
|
|
450
|
+
"seqno": block_seqno,
|
|
492
451
|
},
|
|
493
452
|
"lt": lt,
|
|
494
|
-
"mode": mode,
|
|
495
453
|
"utime": utime,
|
|
496
454
|
}
|
|
455
|
+
|
|
456
|
+
result = await self.send_liteserver_query(
|
|
457
|
+
"lookupBlock",
|
|
458
|
+
data=data,
|
|
459
|
+
priority=priority,
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
block_id = BlockIdExt.from_dict(result["id"])
|
|
463
|
+
header_proof = Cell.one_from_boc(result["header_proof"])
|
|
464
|
+
block = Block.deserialize(header_proof[0].begin_parse())
|
|
465
|
+
|
|
466
|
+
return block_id, block
|
|
467
|
+
|
|
468
|
+
async def get_block_header(
|
|
469
|
+
self,
|
|
470
|
+
block: BlockIdExt,
|
|
471
|
+
*,
|
|
472
|
+
priority: bool = False,
|
|
473
|
+
) -> t.Tuple[BlockIdExt, Block]:
|
|
474
|
+
"""
|
|
475
|
+
Fetch and deserialize block header by BlockIdExt.
|
|
476
|
+
|
|
477
|
+
:param block: BlockIdExt to query
|
|
478
|
+
:param priority: Whether to use priority slot in the limiter
|
|
479
|
+
:return: Tuple of BlockIdExt and deserialized Block
|
|
480
|
+
"""
|
|
481
|
+
data = {"id": block.to_dict(), "mode": 0}
|
|
482
|
+
|
|
497
483
|
result = await self.send_liteserver_query(
|
|
498
|
-
|
|
484
|
+
"getBlockHeader",
|
|
499
485
|
data=data,
|
|
500
486
|
priority=priority,
|
|
501
487
|
)
|
|
502
488
|
|
|
503
|
-
|
|
489
|
+
block_id = BlockIdExt.from_dict(result["id"])
|
|
490
|
+
header_proof = Cell.one_from_boc(result["header_proof"])
|
|
491
|
+
block_obj = Block.deserialize(header_proof[0].begin_parse())
|
|
492
|
+
|
|
493
|
+
return block_id, block_obj
|
|
494
|
+
|
|
495
|
+
async def get_block_transactions_ext(
|
|
496
|
+
self,
|
|
497
|
+
block: BlockIdExt,
|
|
498
|
+
count: int = 1024,
|
|
499
|
+
*,
|
|
500
|
+
priority: bool = False,
|
|
501
|
+
) -> t.List[Transaction]:
|
|
502
|
+
"""
|
|
503
|
+
Fetch extended block transactions list.
|
|
504
504
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
505
|
+
:param block: Target block identifier
|
|
506
|
+
:param count: Maximum number of transactions per request
|
|
507
|
+
:param priority: Whether to use priority slot in the limiter
|
|
508
|
+
:return: List of deserialized Transaction objects
|
|
509
|
+
"""
|
|
510
|
+
mode = 39
|
|
511
|
+
result = await self.send_liteserver_query(
|
|
512
|
+
method="listBlockTransactionsExt",
|
|
513
|
+
data={
|
|
514
|
+
"id": block.to_dict(),
|
|
515
|
+
"mode": mode,
|
|
516
|
+
"count": count,
|
|
517
|
+
"want_proof": b"",
|
|
518
|
+
},
|
|
519
|
+
priority=priority,
|
|
508
520
|
)
|
|
509
521
|
|
|
522
|
+
transactions: t.List[Transaction] = []
|
|
523
|
+
|
|
524
|
+
def _append(result_data: dict) -> None:
|
|
525
|
+
if not result_data.get("transactions"):
|
|
526
|
+
return
|
|
527
|
+
for cell in Cell.from_boc(result_data["transactions"]):
|
|
528
|
+
transactions.append(Transaction.deserialize(cell.begin_parse()))
|
|
529
|
+
|
|
530
|
+
_append(result)
|
|
531
|
+
|
|
532
|
+
while result.get("incomplete"):
|
|
533
|
+
mode = 167
|
|
534
|
+
after = {
|
|
535
|
+
"account": transactions[-1].account_addr_hex,
|
|
536
|
+
"lt": transactions[-1].lt,
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
result = await self.send_liteserver_query(
|
|
540
|
+
method="listBlockTransactionsExt",
|
|
541
|
+
data={
|
|
542
|
+
"id": block.to_dict(),
|
|
543
|
+
"mode": mode,
|
|
544
|
+
"count": count,
|
|
545
|
+
"want_proof": b"",
|
|
546
|
+
"after": after,
|
|
547
|
+
},
|
|
548
|
+
priority=priority,
|
|
549
|
+
)
|
|
550
|
+
|
|
551
|
+
_append(result)
|
|
552
|
+
|
|
553
|
+
return transactions
|
|
554
|
+
|
|
510
555
|
async def get_all_shards_info(
|
|
511
556
|
self,
|
|
512
557
|
block: t.Optional[BlockIdExt] = None,
|
|
@@ -586,13 +631,11 @@ class AdnlProvider:
|
|
|
586
631
|
|
|
587
632
|
exit_code = result.get("exit_code")
|
|
588
633
|
if exit_code is None:
|
|
589
|
-
raise
|
|
590
|
-
|
|
591
|
-
message="RunGetMethod: missing `exit_code` in response",
|
|
592
|
-
)
|
|
634
|
+
raise ProviderError("runSmcMethod: missing exit_code in response")
|
|
635
|
+
|
|
593
636
|
if exit_code != 0:
|
|
594
637
|
raise RunGetMethodError(
|
|
595
|
-
address=address,
|
|
638
|
+
address=address.to_str(),
|
|
596
639
|
method_name=method_name,
|
|
597
640
|
exit_code=exit_code,
|
|
598
641
|
)
|
|
@@ -676,7 +719,7 @@ class AdnlProvider:
|
|
|
676
719
|
from_hash: str,
|
|
677
720
|
*,
|
|
678
721
|
priority: bool = False,
|
|
679
|
-
) ->
|
|
722
|
+
) -> t.List[Transaction]:
|
|
680
723
|
"""
|
|
681
724
|
Fetch a chain of transactions for an account.
|
|
682
725
|
|
|
@@ -689,7 +732,7 @@ class AdnlProvider:
|
|
|
689
732
|
"""
|
|
690
733
|
if count > 16:
|
|
691
734
|
raise ClientError(
|
|
692
|
-
"
|
|
735
|
+
"get_transactions supports up to 16 transactions per request"
|
|
693
736
|
)
|
|
694
737
|
|
|
695
738
|
data = {
|
|
@@ -707,13 +750,13 @@ class AdnlProvider:
|
|
|
707
750
|
cells = Cell.from_boc(result["transactions"])
|
|
708
751
|
|
|
709
752
|
prev_tr_hash = from_hash
|
|
710
|
-
transactions:
|
|
753
|
+
transactions: t.List[Transaction] = []
|
|
711
754
|
|
|
712
755
|
for i, cell in enumerate(cells):
|
|
713
756
|
curr_hash = cell.get_hash(0).hex()
|
|
714
757
|
if curr_hash != prev_tr_hash:
|
|
715
758
|
raise ClientError(
|
|
716
|
-
"
|
|
759
|
+
f"transaction hash mismatch: "
|
|
717
760
|
f"expected {prev_tr_hash}, got {curr_hash}"
|
|
718
761
|
)
|
|
719
762
|
|