tonutils 2.0.1b6__py3-none-any.whl → 2.0.1b8__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 +8 -13
- tonutils/cli.py +1 -1
- tonutils/clients/adnl/balancer.py +132 -355
- tonutils/clients/adnl/client.py +32 -202
- tonutils/clients/adnl/mixin.py +268 -0
- tonutils/clients/adnl/provider/config.py +7 -20
- tonutils/clients/adnl/provider/provider.py +61 -16
- tonutils/clients/adnl/provider/transport.py +13 -4
- tonutils/clients/adnl/provider/workers/pinger.py +1 -1
- tonutils/clients/adnl/utils.py +5 -5
- tonutils/clients/base.py +52 -92
- tonutils/clients/http/balancer.py +93 -90
- tonutils/clients/http/clients/tatum.py +1 -0
- tonutils/clients/http/clients/tonapi.py +12 -24
- tonutils/clients/http/clients/toncenter.py +15 -33
- tonutils/clients/http/provider/base.py +75 -60
- tonutils/clients/http/provider/models.py +1 -1
- tonutils/clients/http/provider/tonapi.py +0 -5
- tonutils/clients/http/provider/toncenter.py +4 -8
- tonutils/clients/protocol.py +6 -6
- tonutils/contracts/__init__.py +3 -0
- tonutils/contracts/base.py +32 -32
- tonutils/contracts/protocol.py +9 -9
- tonutils/contracts/telegram/tlb.py +1 -1
- tonutils/contracts/wallet/__init__.py +4 -0
- tonutils/contracts/wallet/base.py +5 -5
- tonutils/contracts/wallet/tlb.py +18 -16
- tonutils/contracts/wallet/versions/v5.py +6 -6
- tonutils/exceptions.py +45 -102
- tonutils/tools/block_scanner/__init__.py +5 -1
- tonutils/tools/block_scanner/scanner.py +1 -1
- tonutils/tools/status_monitor/monitor.py +6 -6
- tonutils/types.py +24 -10
- tonutils/utils.py +47 -7
- {tonutils-2.0.1b6.dist-info → tonutils-2.0.1b8.dist-info}/METADATA +3 -20
- {tonutils-2.0.1b6.dist-info → tonutils-2.0.1b8.dist-info}/RECORD +40 -46
- {tonutils-2.0.1b6.dist-info → tonutils-2.0.1b8.dist-info}/WHEEL +1 -1
- tonutils/__meta__.py +0 -1
- tonutils/tonconnect/__init__.py +0 -0
- tonutils/tonconnect/bridge/__init__.py +0 -0
- tonutils/tonconnect/events.py +0 -0
- tonutils/tonconnect/models/__init__.py +0 -0
- tonutils/tonconnect/storage.py +0 -0
- tonutils/tonconnect/tonconnect.py +0 -0
- {tonutils-2.0.1b6.dist-info → tonutils-2.0.1b8.dist-info}/entry_points.txt +0 -0
- {tonutils-2.0.1b6.dist-info → tonutils-2.0.1b8.dist-info}/licenses/LICENSE +0 -0
- {tonutils-2.0.1b6.dist-info → tonutils-2.0.1b8.dist-info}/top_level.txt +0 -0
tonutils/clients/adnl/client.py
CHANGED
|
@@ -2,32 +2,29 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import typing as t
|
|
4
4
|
|
|
5
|
-
from
|
|
6
|
-
|
|
5
|
+
from tonutils.clients.adnl.mixin import LiteMixin
|
|
7
6
|
from tonutils.clients.adnl.provider import AdnlProvider
|
|
8
7
|
from tonutils.clients.adnl.provider.config import (
|
|
9
8
|
get_mainnet_global_config,
|
|
10
9
|
get_testnet_global_config,
|
|
10
|
+
load_global_config,
|
|
11
11
|
)
|
|
12
12
|
from tonutils.clients.adnl.provider.models import (
|
|
13
13
|
LiteServer,
|
|
14
14
|
GlobalConfig,
|
|
15
|
-
MasterchainInfo,
|
|
16
15
|
)
|
|
17
|
-
from tonutils.clients.adnl.utils import decode_stack, encode_stack
|
|
18
16
|
from tonutils.clients.base import BaseClient
|
|
19
17
|
from tonutils.clients.limiter import RateLimiter
|
|
18
|
+
from tonutils.exceptions import NotConnectedError, ClientError
|
|
20
19
|
from tonutils.types import (
|
|
21
20
|
BinaryLike,
|
|
22
21
|
ClientType,
|
|
23
|
-
ContractStateInfo,
|
|
24
22
|
NetworkGlobalID,
|
|
25
23
|
RetryPolicy,
|
|
26
|
-
WorkchainID,
|
|
27
24
|
)
|
|
28
25
|
|
|
29
26
|
|
|
30
|
-
class LiteClient(BaseClient):
|
|
27
|
+
class LiteClient(LiteMixin, BaseClient):
|
|
31
28
|
"""TON blockchain client for lite-server communication over ADNL provider."""
|
|
32
29
|
|
|
33
30
|
TYPE = ClientType.ADNL
|
|
@@ -96,32 +93,20 @@ class LiteClient(BaseClient):
|
|
|
96
93
|
return self._provider
|
|
97
94
|
|
|
98
95
|
@property
|
|
99
|
-
def
|
|
96
|
+
def connected(self) -> bool:
|
|
100
97
|
"""
|
|
101
98
|
Check whether the lite-server connection is established.
|
|
102
99
|
|
|
103
100
|
:return: True if connected, False otherwise
|
|
104
101
|
"""
|
|
105
|
-
return self._provider.
|
|
106
|
-
|
|
107
|
-
async def __aenter__(self) -> LiteClient:
|
|
108
|
-
await self.connect()
|
|
109
|
-
return self
|
|
110
|
-
|
|
111
|
-
async def __aexit__(
|
|
112
|
-
self,
|
|
113
|
-
exc_type: t.Optional[t.Type[BaseException]],
|
|
114
|
-
exc_value: t.Optional[BaseException],
|
|
115
|
-
traceback: t.Optional[t.Any],
|
|
116
|
-
) -> None:
|
|
117
|
-
await self.close()
|
|
102
|
+
return self._provider.connected
|
|
118
103
|
|
|
119
104
|
@classmethod
|
|
120
105
|
def from_config(
|
|
121
106
|
cls,
|
|
122
107
|
network: NetworkGlobalID = NetworkGlobalID.MAINNET,
|
|
123
108
|
*,
|
|
124
|
-
config: t.Union[GlobalConfig, t.Dict[str, t.Any]],
|
|
109
|
+
config: t.Union[GlobalConfig, t.Dict[str, t.Any], str],
|
|
125
110
|
index: int,
|
|
126
111
|
connect_timeout: float = 2.0,
|
|
127
112
|
request_timeout: float = 10.0,
|
|
@@ -141,7 +126,7 @@ class LiteClient(BaseClient):
|
|
|
141
126
|
Public free configs may also be used, but may be unstable under load.
|
|
142
127
|
|
|
143
128
|
:param network: Target TON network
|
|
144
|
-
:param config: GlobalConfig instance or raw dict
|
|
129
|
+
:param config: GlobalConfig instance, config file path as string, or raw dict
|
|
145
130
|
:param index: Index of lite-server entry in the configuration
|
|
146
131
|
:param connect_timeout: Timeout in seconds for connect/handshake performed
|
|
147
132
|
by this client.
|
|
@@ -152,9 +137,20 @@ class LiteClient(BaseClient):
|
|
|
152
137
|
:param retry_policy: Optional retry policy that defines per-error-code retry rules
|
|
153
138
|
:return: Configured LiteClient instance
|
|
154
139
|
"""
|
|
140
|
+
if isinstance(config, str):
|
|
141
|
+
config = load_global_config(config)
|
|
155
142
|
if isinstance(config, dict):
|
|
156
143
|
config = GlobalConfig(**config)
|
|
144
|
+
|
|
145
|
+
liteservers = config.liteservers
|
|
146
|
+
if not 0 <= index < len(liteservers):
|
|
147
|
+
raise ClientError(
|
|
148
|
+
f"{cls.__name__}.from_config: "
|
|
149
|
+
f"liteserver index {index} is out of range "
|
|
150
|
+
f"(available: 0..{len(liteservers) - 1})."
|
|
151
|
+
)
|
|
157
152
|
ls = config.liteservers[index]
|
|
153
|
+
|
|
158
154
|
return cls(
|
|
159
155
|
network=network,
|
|
160
156
|
ip=ls.host,
|
|
@@ -216,194 +212,28 @@ class LiteClient(BaseClient):
|
|
|
216
212
|
retry_policy=retry_policy,
|
|
217
213
|
)
|
|
218
214
|
|
|
219
|
-
async def _send_boc(self, boc: str) -> None:
|
|
220
|
-
return await self.provider.send_message(bytes.fromhex(boc))
|
|
221
|
-
|
|
222
|
-
async def _get_blockchain_config(self) -> t.Dict[int, t.Any]:
|
|
223
|
-
return await self.provider.get_config_all()
|
|
224
|
-
|
|
225
|
-
async def _get_contract_info(self, address: str) -> ContractStateInfo:
|
|
226
|
-
return await self.provider.get_account_state(Address(address))
|
|
227
|
-
|
|
228
|
-
async def _get_transactions(
|
|
229
|
-
self,
|
|
230
|
-
address: str,
|
|
231
|
-
limit: int = 100,
|
|
232
|
-
from_lt: t.Optional[int] = None,
|
|
233
|
-
to_lt: t.Optional[int] = None,
|
|
234
|
-
) -> t.List[Transaction]:
|
|
235
|
-
to_lt = 0 if to_lt is None else to_lt
|
|
236
|
-
state = await self._get_contract_info(address)
|
|
237
|
-
account = Address(address).to_tl_account_id()
|
|
238
|
-
|
|
239
|
-
if state.last_transaction_lt is None or state.last_transaction_hash is None:
|
|
240
|
-
return []
|
|
241
|
-
|
|
242
|
-
curr_lt = state.last_transaction_lt
|
|
243
|
-
curr_hash = state.last_transaction_hash
|
|
244
|
-
transactions: t.List[Transaction] = []
|
|
245
|
-
|
|
246
|
-
while curr_lt != 0:
|
|
247
|
-
fetch_lt = curr_lt
|
|
248
|
-
fetch_hash = curr_hash
|
|
249
|
-
|
|
250
|
-
txs = await self.provider.get_transactions(
|
|
251
|
-
account=account,
|
|
252
|
-
count=16,
|
|
253
|
-
from_lt=fetch_lt,
|
|
254
|
-
from_hash=fetch_hash,
|
|
255
|
-
)
|
|
256
|
-
if not txs:
|
|
257
|
-
break
|
|
258
|
-
|
|
259
|
-
for tx in txs:
|
|
260
|
-
if from_lt is not None and tx.lt > from_lt:
|
|
261
|
-
continue
|
|
262
|
-
if to_lt > 0 and tx.lt <= to_lt:
|
|
263
|
-
return transactions[:limit]
|
|
264
|
-
|
|
265
|
-
transactions.append(tx)
|
|
266
|
-
if len(transactions) >= limit:
|
|
267
|
-
return transactions
|
|
268
|
-
|
|
269
|
-
last_tx = txs[-1]
|
|
270
|
-
curr_lt = last_tx.prev_trans_lt
|
|
271
|
-
curr_hash = last_tx.prev_trans_hash.hex()
|
|
272
|
-
|
|
273
|
-
return transactions[:limit]
|
|
274
|
-
|
|
275
|
-
async def _run_get_method(
|
|
276
|
-
self,
|
|
277
|
-
address: str,
|
|
278
|
-
method_name: str,
|
|
279
|
-
stack: t.Optional[t.List[t.Any]] = None,
|
|
280
|
-
) -> t.List[t.Any]:
|
|
281
|
-
result = await self.provider.run_smc_method(
|
|
282
|
-
address=Address(address),
|
|
283
|
-
method_name=method_name,
|
|
284
|
-
stack=encode_stack(stack or []),
|
|
285
|
-
)
|
|
286
|
-
return decode_stack(result or [])
|
|
287
|
-
|
|
288
215
|
async def connect(self) -> None:
|
|
289
216
|
"""Establish connection to the lite-server."""
|
|
290
217
|
await self.provider.connect()
|
|
291
218
|
|
|
292
|
-
async def reconnect(self) -> None:
|
|
293
|
-
"""Force reconnection to the lite-server."""
|
|
294
|
-
await self.provider.reconnect()
|
|
295
|
-
|
|
296
219
|
async def close(self) -> None:
|
|
297
220
|
"""Close the lite-server connection."""
|
|
298
221
|
await self.provider.close()
|
|
299
222
|
|
|
300
|
-
async def
|
|
301
|
-
"""
|
|
302
|
-
Fetch current network time from lite-server.
|
|
303
|
-
|
|
304
|
-
:return: Current UNIX timestamp
|
|
223
|
+
async def _adnl_call(self, method: str, /, *args: t.Any, **kwargs: t.Any) -> t.Any:
|
|
305
224
|
"""
|
|
306
|
-
|
|
225
|
+
Execute lite-server call using the current provider.
|
|
307
226
|
|
|
308
|
-
|
|
227
|
+
:param method: Provider coroutine method name.
|
|
228
|
+
:param args: Positional arguments forwarded to the provider method.
|
|
229
|
+
:param kwargs: Keyword arguments forwarded to the provider method.
|
|
230
|
+
:return: Provider method result.
|
|
309
231
|
"""
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
async def wait_masterchain_seqno(
|
|
317
|
-
self,
|
|
318
|
-
seqno: int,
|
|
319
|
-
timeout_ms: int,
|
|
320
|
-
schema_name: str,
|
|
321
|
-
data: t.Optional[dict] = None,
|
|
322
|
-
) -> dict:
|
|
323
|
-
"""
|
|
324
|
-
Combine waitMasterchainSeqno with another lite-server query.
|
|
325
|
-
|
|
326
|
-
:param seqno: Masterchain seqno to wait for
|
|
327
|
-
:param timeout_ms: Wait timeout in milliseconds
|
|
328
|
-
:param schema_name: Lite-server TL method name without prefix
|
|
329
|
-
:param data: Additional method arguments
|
|
330
|
-
:return: Lite-server response as dictionary
|
|
331
|
-
"""
|
|
332
|
-
return await self.provider.wait_masterchain_seqno(
|
|
333
|
-
seqno=seqno,
|
|
334
|
-
timeout_ms=timeout_ms,
|
|
335
|
-
schema_name=schema_name,
|
|
336
|
-
data=data,
|
|
337
|
-
)
|
|
338
|
-
|
|
339
|
-
async def get_masterchain_info(self) -> MasterchainInfo:
|
|
340
|
-
"""
|
|
341
|
-
Fetch basic masterchain information.
|
|
342
|
-
|
|
343
|
-
:return: MasterchainInfo instance
|
|
344
|
-
"""
|
|
345
|
-
return await self.provider.get_masterchain_info()
|
|
346
|
-
|
|
347
|
-
async def lookup_block(
|
|
348
|
-
self,
|
|
349
|
-
workchain: WorkchainID,
|
|
350
|
-
shard: int,
|
|
351
|
-
seqno: t.Optional[int] = None,
|
|
352
|
-
lt: t.Optional[int] = None,
|
|
353
|
-
utime: t.Optional[int] = None,
|
|
354
|
-
) -> t.Tuple[BlockIdExt, Block]:
|
|
355
|
-
"""
|
|
356
|
-
Locate a block by workchain/shard and one of seqno/lt/utime.
|
|
357
|
-
|
|
358
|
-
:param workchain: Workchain identifier
|
|
359
|
-
:param shard: Shard identifier
|
|
360
|
-
:param seqno: Block sequence number
|
|
361
|
-
:param lt: Logical time filter
|
|
362
|
-
:param utime: UNIX time filter
|
|
363
|
-
:return: Tuple of BlockIdExt and deserialized Block
|
|
364
|
-
"""
|
|
365
|
-
return await self.provider.lookup_block(
|
|
366
|
-
workchain=workchain,
|
|
367
|
-
shard=shard,
|
|
368
|
-
seqno=seqno,
|
|
369
|
-
lt=lt,
|
|
370
|
-
utime=utime,
|
|
371
|
-
)
|
|
372
|
-
|
|
373
|
-
async def get_block_header(
|
|
374
|
-
self,
|
|
375
|
-
block: BlockIdExt,
|
|
376
|
-
) -> t.Tuple[BlockIdExt, Block]:
|
|
377
|
-
"""
|
|
378
|
-
Fetch and deserialize block header by BlockIdExt.
|
|
379
|
-
|
|
380
|
-
:param block: BlockIdExt to query
|
|
381
|
-
:return: Tuple of BlockIdExt and deserialized Block
|
|
382
|
-
"""
|
|
383
|
-
return await self.provider.get_block_header(block)
|
|
384
|
-
|
|
385
|
-
async def get_block_transactions_ext(
|
|
386
|
-
self,
|
|
387
|
-
block: BlockIdExt,
|
|
388
|
-
count: int = 1024,
|
|
389
|
-
) -> t.List[Transaction]:
|
|
390
|
-
"""
|
|
391
|
-
Fetch extended block transactions list.
|
|
392
|
-
|
|
393
|
-
:param block: Target block identifier
|
|
394
|
-
:param count: Maximum number of transactions per request
|
|
395
|
-
:return: List of deserialized Transaction objects
|
|
396
|
-
"""
|
|
397
|
-
return await self.provider.get_block_transactions_ext(block, count=count)
|
|
398
|
-
|
|
399
|
-
async def get_all_shards_info(
|
|
400
|
-
self,
|
|
401
|
-
block: t.Optional[BlockIdExt] = None,
|
|
402
|
-
) -> t.List[BlockIdExt]:
|
|
403
|
-
"""
|
|
404
|
-
Fetch shard info for all workchains at a given masterchain block.
|
|
232
|
+
if not self.connected:
|
|
233
|
+
raise NotConnectedError(
|
|
234
|
+
component=self.__class__.__name__,
|
|
235
|
+
operation=method,
|
|
236
|
+
)
|
|
405
237
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
"""
|
|
409
|
-
return await self.provider.get_all_shards_info(block)
|
|
238
|
+
fn = getattr(self.provider, method)
|
|
239
|
+
return await fn(*args, **kwargs)
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import typing as t
|
|
2
|
+
|
|
3
|
+
from pytoniq_core import Address, Block, BlockIdExt, Transaction, Account, ShardAccount
|
|
4
|
+
|
|
5
|
+
from tonutils.clients.adnl.provider.models import MasterchainInfo
|
|
6
|
+
from tonutils.clients.adnl.utils import decode_stack, encode_stack
|
|
7
|
+
from tonutils.types import ContractInfo, WorkchainID, AddressLike
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class LiteMixin:
|
|
11
|
+
|
|
12
|
+
async def _adnl_call(
|
|
13
|
+
self,
|
|
14
|
+
method: str,
|
|
15
|
+
/,
|
|
16
|
+
*args: t.Any,
|
|
17
|
+
**kwargs: t.Any,
|
|
18
|
+
) -> t.Any:
|
|
19
|
+
"""
|
|
20
|
+
Execute a single lite-server provider call.
|
|
21
|
+
|
|
22
|
+
This is an internal hook used by the mixin to unify implementations between
|
|
23
|
+
LiteClient (direct call) and LiteBalancer (failover / retry call).
|
|
24
|
+
|
|
25
|
+
:param method: Provider coroutine method name (e.g. "get_time", "lookup_block").
|
|
26
|
+
:param args: Positional arguments forwarded to the provider method.
|
|
27
|
+
:param kwargs: Keyword arguments forwarded to the provider method.
|
|
28
|
+
:return: Provider method result.
|
|
29
|
+
"""
|
|
30
|
+
raise NotImplementedError("LiteMixin requires `_adnl_call()` implementation.")
|
|
31
|
+
|
|
32
|
+
async def _send_message(self, boc: str) -> None:
|
|
33
|
+
method = "send_message"
|
|
34
|
+
await self._adnl_call(method, bytes.fromhex(boc))
|
|
35
|
+
|
|
36
|
+
async def _get_config(self) -> t.Dict[int, t.Any]:
|
|
37
|
+
method = "get_config"
|
|
38
|
+
return t.cast(t.Dict[int, t.Any], await self._adnl_call(method))
|
|
39
|
+
|
|
40
|
+
async def _get_info(self, address: str) -> ContractInfo:
|
|
41
|
+
method = "get_info"
|
|
42
|
+
return t.cast(
|
|
43
|
+
ContractInfo,
|
|
44
|
+
await self._adnl_call(method, Address(address)),
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
async def _run_get_method(
|
|
48
|
+
self,
|
|
49
|
+
address: str,
|
|
50
|
+
method_name: str,
|
|
51
|
+
stack: t.Optional[t.List[t.Any]] = None,
|
|
52
|
+
) -> t.List[t.Any]:
|
|
53
|
+
method = "run_get_method"
|
|
54
|
+
res = await self._adnl_call(
|
|
55
|
+
method,
|
|
56
|
+
address=Address(address),
|
|
57
|
+
method_name=method_name,
|
|
58
|
+
stack=encode_stack(stack or []),
|
|
59
|
+
)
|
|
60
|
+
return decode_stack(res or [])
|
|
61
|
+
|
|
62
|
+
async def _get_transactions(
|
|
63
|
+
self,
|
|
64
|
+
address: str,
|
|
65
|
+
limit: int = 100,
|
|
66
|
+
from_lt: t.Optional[int] = None,
|
|
67
|
+
to_lt: t.Optional[int] = None,
|
|
68
|
+
) -> t.List[Transaction]:
|
|
69
|
+
method = "get_transactions"
|
|
70
|
+
|
|
71
|
+
to_lt_i = 0 if to_lt is None else to_lt
|
|
72
|
+
state = await self._get_info(address)
|
|
73
|
+
account = Address(address).to_tl_account_id()
|
|
74
|
+
|
|
75
|
+
if state.last_transaction_lt is None or state.last_transaction_hash is None:
|
|
76
|
+
return []
|
|
77
|
+
|
|
78
|
+
curr_lt = state.last_transaction_lt
|
|
79
|
+
curr_hash = state.last_transaction_hash
|
|
80
|
+
out: t.List[Transaction] = []
|
|
81
|
+
|
|
82
|
+
while curr_lt != 0:
|
|
83
|
+
fetch_lt = curr_lt
|
|
84
|
+
fetch_hash = curr_hash
|
|
85
|
+
|
|
86
|
+
txs = t.cast(
|
|
87
|
+
t.List[Transaction],
|
|
88
|
+
await self._adnl_call(
|
|
89
|
+
method,
|
|
90
|
+
account=account,
|
|
91
|
+
count=16,
|
|
92
|
+
from_lt=fetch_lt,
|
|
93
|
+
from_hash=fetch_hash,
|
|
94
|
+
),
|
|
95
|
+
)
|
|
96
|
+
if not txs:
|
|
97
|
+
break
|
|
98
|
+
|
|
99
|
+
for tx in txs:
|
|
100
|
+
if from_lt is not None and tx.lt > from_lt:
|
|
101
|
+
continue
|
|
102
|
+
if to_lt_i > 0 and tx.lt <= to_lt_i:
|
|
103
|
+
return out[:limit]
|
|
104
|
+
|
|
105
|
+
out.append(tx)
|
|
106
|
+
if len(out) >= limit:
|
|
107
|
+
return out
|
|
108
|
+
|
|
109
|
+
last_tx = txs[-1]
|
|
110
|
+
curr_lt = last_tx.prev_trans_lt
|
|
111
|
+
curr_hash = last_tx.prev_trans_hash.hex()
|
|
112
|
+
|
|
113
|
+
return out[:limit]
|
|
114
|
+
|
|
115
|
+
async def get_time(self) -> int:
|
|
116
|
+
"""
|
|
117
|
+
Fetch current network time from lite-server.
|
|
118
|
+
|
|
119
|
+
:return: Current UNIX timestamp
|
|
120
|
+
"""
|
|
121
|
+
method = "get_time"
|
|
122
|
+
return t.cast(int, await self._adnl_call(method))
|
|
123
|
+
|
|
124
|
+
async def get_version(self) -> int:
|
|
125
|
+
"""
|
|
126
|
+
Fetch lite-server protocol version.
|
|
127
|
+
|
|
128
|
+
:return: Version number
|
|
129
|
+
"""
|
|
130
|
+
method = "get_version"
|
|
131
|
+
return t.cast(int, await self._adnl_call(method))
|
|
132
|
+
|
|
133
|
+
async def get_masterchain_info(self) -> MasterchainInfo:
|
|
134
|
+
"""
|
|
135
|
+
Fetch basic masterchain information.
|
|
136
|
+
|
|
137
|
+
:return: MasterchainInfo instance
|
|
138
|
+
"""
|
|
139
|
+
method = "get_masterchain_info"
|
|
140
|
+
return t.cast(MasterchainInfo, await self._adnl_call(method))
|
|
141
|
+
|
|
142
|
+
async def wait_masterchain_seqno(
|
|
143
|
+
self,
|
|
144
|
+
seqno: int,
|
|
145
|
+
timeout_ms: int,
|
|
146
|
+
schema_name: str,
|
|
147
|
+
data: t.Optional[dict] = None,
|
|
148
|
+
) -> t.Dict[str, t.Any]:
|
|
149
|
+
"""
|
|
150
|
+
Combine waitMasterchainSeqno with another lite-server query.
|
|
151
|
+
|
|
152
|
+
:param seqno: Masterchain seqno to wait for
|
|
153
|
+
:param timeout_ms: Wait timeout in milliseconds
|
|
154
|
+
:param schema_name: Lite-server TL method name without prefix
|
|
155
|
+
:param data: Additional method arguments
|
|
156
|
+
:return: Lite-server response as dictionary
|
|
157
|
+
"""
|
|
158
|
+
method = "wait_masterchain_seqno"
|
|
159
|
+
return t.cast(
|
|
160
|
+
t.Dict[str, t.Any],
|
|
161
|
+
await self._adnl_call(
|
|
162
|
+
method,
|
|
163
|
+
seqno=seqno,
|
|
164
|
+
timeout_ms=timeout_ms,
|
|
165
|
+
schema_name=schema_name,
|
|
166
|
+
data=data,
|
|
167
|
+
),
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
async def lookup_block(
|
|
171
|
+
self,
|
|
172
|
+
workchain: WorkchainID,
|
|
173
|
+
shard: int,
|
|
174
|
+
seqno: t.Optional[int] = None,
|
|
175
|
+
lt: t.Optional[int] = None,
|
|
176
|
+
utime: t.Optional[int] = None,
|
|
177
|
+
) -> t.Tuple[BlockIdExt, Block]:
|
|
178
|
+
"""
|
|
179
|
+
Locate a block by workchain/shard and one of seqno/lt/utime.
|
|
180
|
+
|
|
181
|
+
:param workchain: Workchain identifier
|
|
182
|
+
:param shard: Shard identifier
|
|
183
|
+
:param seqno: Block sequence number
|
|
184
|
+
:param lt: Logical time filter
|
|
185
|
+
:param utime: UNIX time filter
|
|
186
|
+
:return: Tuple of BlockIdExt and deserialized Block
|
|
187
|
+
"""
|
|
188
|
+
method = "lookup_block"
|
|
189
|
+
return t.cast(
|
|
190
|
+
t.Tuple[BlockIdExt, Block],
|
|
191
|
+
await self._adnl_call(
|
|
192
|
+
method,
|
|
193
|
+
workchain=workchain,
|
|
194
|
+
shard=shard,
|
|
195
|
+
seqno=seqno,
|
|
196
|
+
lt=lt,
|
|
197
|
+
utime=utime,
|
|
198
|
+
),
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
async def get_block_header(
|
|
202
|
+
self,
|
|
203
|
+
block: BlockIdExt,
|
|
204
|
+
) -> t.Tuple[BlockIdExt, Block]:
|
|
205
|
+
"""
|
|
206
|
+
Fetch and deserialize block header by BlockIdExt.
|
|
207
|
+
|
|
208
|
+
:param block: BlockIdExt to query
|
|
209
|
+
:return: Tuple of BlockIdExt and deserialized Block
|
|
210
|
+
"""
|
|
211
|
+
method = "get_block_header"
|
|
212
|
+
return t.cast(
|
|
213
|
+
t.Tuple[BlockIdExt, Block],
|
|
214
|
+
await self._adnl_call(method, block),
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
async def get_block_transactions(
|
|
218
|
+
self,
|
|
219
|
+
block: BlockIdExt,
|
|
220
|
+
count: int = 1024,
|
|
221
|
+
) -> t.List[Transaction]:
|
|
222
|
+
"""
|
|
223
|
+
Fetch extended block transactions list.
|
|
224
|
+
|
|
225
|
+
:param block: Target block identifier
|
|
226
|
+
:param count: Maximum number of transactions per request
|
|
227
|
+
:return: List of deserialized Transaction objects
|
|
228
|
+
"""
|
|
229
|
+
method = "get_block_transactions"
|
|
230
|
+
return t.cast(
|
|
231
|
+
t.List[Transaction],
|
|
232
|
+
await self._adnl_call(method, block, count=count),
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
async def get_all_shards_info(
|
|
236
|
+
self,
|
|
237
|
+
block: t.Optional[BlockIdExt] = None,
|
|
238
|
+
) -> t.List[BlockIdExt]:
|
|
239
|
+
"""
|
|
240
|
+
Fetch shard info for all workchains at a given masterchain block.
|
|
241
|
+
|
|
242
|
+
:param block: Masterchain block ID or None to use latest
|
|
243
|
+
:return: List of shard BlockIdExt objects
|
|
244
|
+
"""
|
|
245
|
+
method = "get_all_shards_info"
|
|
246
|
+
return t.cast(
|
|
247
|
+
t.List[BlockIdExt],
|
|
248
|
+
await self._adnl_call(method, block),
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
async def get_account_state(
|
|
252
|
+
self,
|
|
253
|
+
address: AddressLike,
|
|
254
|
+
) -> t.Tuple[t.Optional[Account], t.Optional[ShardAccount]]:
|
|
255
|
+
"""
|
|
256
|
+
Fetch account state and shard account from lite-server.
|
|
257
|
+
|
|
258
|
+
:param address: Contract address as Address object or string
|
|
259
|
+
:return: Tuple of (Account | None, ShardAccount | None)
|
|
260
|
+
"""
|
|
261
|
+
if isinstance(address, str):
|
|
262
|
+
address = Address(address)
|
|
263
|
+
|
|
264
|
+
method = "get_account_state"
|
|
265
|
+
return t.cast(
|
|
266
|
+
t.Tuple[t.Optional[Account], t.Optional[ShardAccount]],
|
|
267
|
+
await self._adnl_call(method, address),
|
|
268
|
+
)
|
|
@@ -1,33 +1,20 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import urllib.request
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
from urllib.error import HTTPError, URLError
|
|
5
|
-
|
|
6
1
|
from pydantic import ValidationError
|
|
7
2
|
|
|
8
3
|
from tonutils.clients.adnl.provider.models import GlobalConfig
|
|
4
|
+
from tonutils.utils import load_json
|
|
9
5
|
|
|
10
6
|
|
|
11
7
|
def load_global_config(source: str) -> GlobalConfig:
|
|
8
|
+
"""
|
|
9
|
+
Fetch global configuration from source.
|
|
10
|
+
|
|
11
|
+
:return: Parsed GlobalConfig instance
|
|
12
|
+
"""
|
|
12
13
|
try:
|
|
13
|
-
|
|
14
|
-
with urllib.request.urlopen(source) as r:
|
|
15
|
-
data = json.loads(r.read().decode("utf-8"))
|
|
16
|
-
else:
|
|
17
|
-
data = json.loads(Path(source).read_text(encoding="utf-8"))
|
|
14
|
+
data = load_json(source)
|
|
18
15
|
return GlobalConfig.model_validate(data)
|
|
19
|
-
except HTTPError as e:
|
|
20
|
-
raise RuntimeError(f"Config fetch failed: {e} ({source})") from e
|
|
21
|
-
except URLError as e:
|
|
22
|
-
raise RuntimeError(f"Config fetch failed: {e.reason} ({source})") from e
|
|
23
|
-
except json.JSONDecodeError as e:
|
|
24
|
-
raise RuntimeError(f"Config JSON is invalid: {e.msg} ({source})") from e
|
|
25
16
|
except ValidationError as e:
|
|
26
17
|
raise RuntimeError(f"Config validation failed: {e} ({source})") from e
|
|
27
|
-
except OSError as e:
|
|
28
|
-
raise RuntimeError(f"Config read failed: {e} ({source})") from e
|
|
29
|
-
except Exception as e:
|
|
30
|
-
raise RuntimeError(f"Config load failed: {e} ({source})") from e
|
|
31
18
|
|
|
32
19
|
|
|
33
20
|
def get_mainnet_global_config() -> GlobalConfig:
|