tonutils 2.0.1b5__py3-none-any.whl → 2.0.1b6__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/__meta__.py +1 -1
- tonutils/clients/__init__.py +10 -10
- tonutils/clients/adnl/balancer.py +21 -24
- tonutils/clients/adnl/client.py +21 -24
- tonutils/clients/adnl/provider/config.py +22 -7
- tonutils/clients/base.py +17 -11
- tonutils/clients/http/__init__.py +11 -11
- tonutils/clients/http/balancer.py +11 -11
- tonutils/clients/http/clients/__init__.py +10 -10
- tonutils/clients/http/clients/chainstack.py +3 -3
- tonutils/clients/http/clients/quicknode.py +2 -3
- tonutils/clients/http/clients/tatum.py +3 -3
- tonutils/clients/http/clients/tonapi.py +9 -10
- tonutils/clients/http/clients/toncenter.py +50 -23
- tonutils/clients/http/{providers → provider}/__init__.py +4 -1
- tonutils/clients/http/{providers → provider}/base.py +71 -7
- tonutils/clients/http/{providers/toncenter → provider}/models.py +43 -1
- tonutils/clients/http/{providers/tonapi/provider.py → provider/tonapi.py} +8 -8
- tonutils/clients/http/{providers/toncenter/provider.py → provider/toncenter.py} +22 -14
- tonutils/clients/limiter.py +61 -59
- tonutils/clients/protocol.py +2 -2
- tonutils/contracts/wallet/base.py +2 -3
- tonutils/contracts/wallet/messages.py +4 -8
- 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/tools/block_scanner/__init__.py +2 -9
- tonutils/tools/block_scanner/events.py +48 -7
- tonutils/tools/block_scanner/scanner.py +316 -222
- tonutils/tools/block_scanner/storage.py +11 -0
- tonutils/utils.py +0 -48
- {tonutils-2.0.1b5.dist-info → tonutils-2.0.1b6.dist-info}/METADATA +1 -1
- {tonutils-2.0.1b5.dist-info → tonutils-2.0.1b6.dist-info}/RECORD +39 -41
- {tonutils-2.0.1b5.dist-info → tonutils-2.0.1b6.dist-info}/WHEEL +1 -1
- tonutils/clients/http/providers/response.py +0 -85
- tonutils/clients/http/providers/tonapi/__init__.py +0 -3
- tonutils/clients/http/providers/tonapi/models.py +0 -47
- tonutils/clients/http/providers/toncenter/__init__.py +0 -3
- tonutils/tools/block_scanner/annotations.py +0 -23
- tonutils/tools/block_scanner/dispatcher.py +0 -141
- tonutils/tools/block_scanner/traversal.py +0 -97
- tonutils/tools/block_scanner/where.py +0 -53
- {tonutils-2.0.1b5.dist-info → tonutils-2.0.1b6.dist-info}/entry_points.txt +0 -0
- {tonutils-2.0.1b5.dist-info → tonutils-2.0.1b6.dist-info}/licenses/LICENSE +0 -0
- {tonutils-2.0.1b5.dist-info → tonutils-2.0.1b6.dist-info}/top_level.txt +0 -0
tonutils/utils.py
CHANGED
|
@@ -30,13 +30,8 @@ from tonutils.types import (
|
|
|
30
30
|
AddressLike,
|
|
31
31
|
PrivateKey,
|
|
32
32
|
PublicKey,
|
|
33
|
-
DNSCategory,
|
|
34
33
|
)
|
|
35
34
|
|
|
36
|
-
if t.TYPE_CHECKING:
|
|
37
|
-
from tonutils.clients.protocol import ClientProtocol
|
|
38
|
-
|
|
39
|
-
|
|
40
35
|
__all__ = [
|
|
41
36
|
"TextCipher",
|
|
42
37
|
"calc_valid_until",
|
|
@@ -50,7 +45,6 @@ __all__ = [
|
|
|
50
45
|
"norm_stack_num",
|
|
51
46
|
"normalize_hash",
|
|
52
47
|
"parse_stack_config",
|
|
53
|
-
"resolve_wallet_address",
|
|
54
48
|
"slice_hash",
|
|
55
49
|
"string_hash",
|
|
56
50
|
"to_amount",
|
|
@@ -310,48 +304,6 @@ def calc_valid_until(seqno: int, ttl: int = 60) -> int:
|
|
|
310
304
|
return 0xFFFFFFFF if seqno == 0 else now + ttl
|
|
311
305
|
|
|
312
306
|
|
|
313
|
-
async def resolve_wallet_address(
|
|
314
|
-
client: ClientProtocol,
|
|
315
|
-
domain: AddressLike,
|
|
316
|
-
) -> Address:
|
|
317
|
-
"""
|
|
318
|
-
Resolve a TON address from domain name or address string.
|
|
319
|
-
|
|
320
|
-
Supports:
|
|
321
|
-
- Direct Address objects (returned as-is)
|
|
322
|
-
- Address strings in any format (EQ..., UQ..., 0:...)
|
|
323
|
-
- TON DNS domains (.ton, .t.me) - queries wallet record
|
|
324
|
-
|
|
325
|
-
:param client: TON client for DNS resolution
|
|
326
|
-
:param domain: Address object, address string, or DNS domain
|
|
327
|
-
"""
|
|
328
|
-
from tonutils.contracts.dns.tlb import ALLOWED_DNS_ZONES
|
|
329
|
-
|
|
330
|
-
if isinstance(domain, Address):
|
|
331
|
-
return domain
|
|
332
|
-
|
|
333
|
-
if isinstance(domain, str):
|
|
334
|
-
try:
|
|
335
|
-
return Address(domain)
|
|
336
|
-
except (Exception,):
|
|
337
|
-
if not domain.endswith(ALLOWED_DNS_ZONES):
|
|
338
|
-
allowed = ", ".join(ALLOWED_DNS_ZONES)
|
|
339
|
-
raise ValueError(
|
|
340
|
-
f"Invalid DNS domain: {domain}. Supported zones: {allowed}."
|
|
341
|
-
)
|
|
342
|
-
|
|
343
|
-
record = await client.dnsresolve(
|
|
344
|
-
domain=domain,
|
|
345
|
-
category=DNSCategory.WALLET,
|
|
346
|
-
)
|
|
347
|
-
if record is None:
|
|
348
|
-
raise ValueError(f"DNS record not found for: {domain}.")
|
|
349
|
-
|
|
350
|
-
return record.value
|
|
351
|
-
|
|
352
|
-
raise TypeError(f"Invalid domain type: {type(domain)!r}. Expected Address or str.")
|
|
353
|
-
|
|
354
|
-
|
|
355
307
|
class TextCipher:
|
|
356
308
|
"""
|
|
357
309
|
End-to-end encryption for TON wallet text comments.
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
tonutils/__init__.py,sha256=ueJrDkU1JBlZiX0q8roQfzYOZY62Of_CiHZlxIIQFO0,228
|
|
2
|
-
tonutils/__meta__.py,sha256=
|
|
2
|
+
tonutils/__meta__.py,sha256=sMnfai_0fIysG3AVFpGIoOqzV0PSnBl6cpIF5XzeFNk,24
|
|
3
3
|
tonutils/cli.py,sha256=WGir-ihgPuKTgKGmhjPZeKk9wgsm64jiJciOnVlsdco,2645
|
|
4
4
|
tonutils/exceptions.py,sha256=67jXCFPyOnVnd8EaqYg1osVIXg34VZX-aJHPunpc-oI,6462
|
|
5
5
|
tonutils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
tonutils/types.py,sha256=ORevKllLjb7pmL3AQTMeSoiZQ4KFhoB_rA7KpGqZZjU,14542
|
|
7
|
-
tonutils/utils.py,sha256=
|
|
8
|
-
tonutils/clients/__init__.py,sha256=
|
|
9
|
-
tonutils/clients/base.py,sha256=
|
|
10
|
-
tonutils/clients/limiter.py,sha256=
|
|
11
|
-
tonutils/clients/protocol.py,sha256=
|
|
7
|
+
tonutils/utils.py,sha256=10R2eGjzNMEN9glngcJhZ36O76ec55NodH-c8IgN6yw,15062
|
|
8
|
+
tonutils/clients/__init__.py,sha256=F0aPLPOI8-HcqcweeCSG_fr2VArxiZxfsWHuzHDwE4k,521
|
|
9
|
+
tonutils/clients/base.py,sha256=3qpGm0-1lSKYjmKbQEP-qNFbYn0NUJ-0_E_UfOg_oAw,9981
|
|
10
|
+
tonutils/clients/limiter.py,sha256=lSUo6AhEuWUlo0y2sUc-P4YltRI2zjbicelYKkMTrls,3896
|
|
11
|
+
tonutils/clients/protocol.py,sha256=CMWpLdeQUYluHVQtSZ0Id73EnagUCYiGinqW6Y5ulcA,2563
|
|
12
12
|
tonutils/clients/adnl/__init__.py,sha256=shkczPIYlTrOHjpnOBIoRwEYRQ4rVGfLnOZvnQY0a5U,174
|
|
13
|
-
tonutils/clients/adnl/balancer.py,sha256=
|
|
14
|
-
tonutils/clients/adnl/client.py,sha256=
|
|
13
|
+
tonutils/clients/adnl/balancer.py,sha256=EVHeAhgkM1Vuq3pWC8FHG1Yg_-6eloMawkGnRy3Tmog,26781
|
|
14
|
+
tonutils/clients/adnl/client.py,sha256=ixGSDvpq46i2PxP5QuFJu3kMI24REt6bbD32_RZBn44,14015
|
|
15
15
|
tonutils/clients/adnl/utils.py,sha256=rKLbTiGbZQ0ozvh5jYjjaFEKsmqEschjuUiHOX9e6ps,5154
|
|
16
16
|
tonutils/clients/adnl/provider/__init__.py,sha256=lLwFEEgCifMlYozwSzQbvq97R6Du7TzgGFnTgUnk4gw,63
|
|
17
|
-
tonutils/clients/adnl/provider/config.py,sha256=
|
|
17
|
+
tonutils/clients/adnl/provider/config.py,sha256=jMeCdg14KjS6Zh7sgcjop4LdLtrHA91PbWm1zD1mnt0,1655
|
|
18
18
|
tonutils/clients/adnl/provider/models.py,sha256=3dn4oZv7PIgiwlP2lGs0O6VckC19ejxCFlSPhzU0wX8,4537
|
|
19
19
|
tonutils/clients/adnl/provider/provider.py,sha256=Er5RNR490RIQlRTI5KMxVarshHRNVseAbUYGM48fcbg,24180
|
|
20
20
|
tonutils/clients/adnl/provider/transport.py,sha256=lgp1N0LGjYYIKWiwBIm-pnF064TkkCsSTDAFKt8_U-I,10983
|
|
@@ -23,24 +23,20 @@ tonutils/clients/adnl/provider/workers/base.py,sha256=8RenR2MU_B-b8mevzCytLJmPgj
|
|
|
23
23
|
tonutils/clients/adnl/provider/workers/pinger.py,sha256=lBpy4TU8L-I_6sxEft-Bn9XmntJhMg5Rm2o2tN2Mp0A,2443
|
|
24
24
|
tonutils/clients/adnl/provider/workers/reader.py,sha256=qvkaBBrRNu_nLTQOd0w6lDdN_wPOnzPbfAa3UToJWd8,1944
|
|
25
25
|
tonutils/clients/adnl/provider/workers/updater.py,sha256=r7NrZXDg3nY4jAF-sYkX1ZvxTE8sN99qSFctbAmHTME,1978
|
|
26
|
-
tonutils/clients/http/__init__.py,sha256=
|
|
27
|
-
tonutils/clients/http/balancer.py,sha256=
|
|
26
|
+
tonutils/clients/http/__init__.py,sha256=M05D4r8sLZk1dY_LZa6-LhPZdzCzyCJ3MJnCxwE9xk8,435
|
|
27
|
+
tonutils/clients/http/balancer.py,sha256=O14K5NHatZ9-CUY5OgF_KMzz_EDU1Zo9YBCa_GojR1A,12345
|
|
28
28
|
tonutils/clients/http/utils.py,sha256=mv9kCwLu8qjayy03E524WZ3q7Zf96t5VCE6H9j5kHRE,4994
|
|
29
|
-
tonutils/clients/http/clients/__init__.py,sha256=
|
|
30
|
-
tonutils/clients/http/clients/chainstack.py,sha256=
|
|
31
|
-
tonutils/clients/http/clients/quicknode.py,sha256=
|
|
32
|
-
tonutils/clients/http/clients/tatum.py,sha256=
|
|
33
|
-
tonutils/clients/http/clients/tonapi.py,sha256=
|
|
34
|
-
tonutils/clients/http/clients/toncenter.py,sha256=
|
|
35
|
-
tonutils/clients/http/
|
|
36
|
-
tonutils/clients/http/
|
|
37
|
-
tonutils/clients/http/
|
|
38
|
-
tonutils/clients/http/
|
|
39
|
-
tonutils/clients/http/
|
|
40
|
-
tonutils/clients/http/providers/tonapi/provider.py,sha256=iPquCsJglbgxtnHbUrkGYbiJG1rf5zmyh4XKMsncj-4,3727
|
|
41
|
-
tonutils/clients/http/providers/toncenter/__init__.py,sha256=PSzpwMrwcs_LY2Aw5omErjaLSVzy_9LB5EpRjtITyTs,81
|
|
42
|
-
tonutils/clients/http/providers/toncenter/models.py,sha256=ZPx6EhjhrNWFMWF_055EIolMwaLfQAGio0fqTUmljy8,2397
|
|
43
|
-
tonutils/clients/http/providers/toncenter/provider.py,sha256=QoNrobRgytG0Gc9Lo-QXrdMCtyJk1rOS-B2nPzGwaV0,3391
|
|
29
|
+
tonutils/clients/http/clients/__init__.py,sha256=RpoIk4KaVC3pBlxkatSozMN6cMY_UW1cR8PxA1d0Xyo,307
|
|
30
|
+
tonutils/clients/http/clients/chainstack.py,sha256=U_UaEDM8_KB8SHRA6l22utDfGqZ4dLvKJ-VLgbg86s0,1737
|
|
31
|
+
tonutils/clients/http/clients/quicknode.py,sha256=TZOwVZTLjTHHd1OiOZkdAzkM91vyX6_1vEV-bUqCjmE,1655
|
|
32
|
+
tonutils/clients/http/clients/tatum.py,sha256=isqomiGHmOTuR2fc_pB2AQihEvMdxxDxEzsmO_KilMg,2013
|
|
33
|
+
tonutils/clients/http/clients/tonapi.py,sha256=0EtoIfLrLh20uZtM4cTL7AngT3rnThEQL0-nN0tSTC8,5759
|
|
34
|
+
tonutils/clients/http/clients/toncenter.py,sha256=pw6VjzsMatW6xH3Zjiqe8PPkW4_9qoVNoverLSqCnC8,8279
|
|
35
|
+
tonutils/clients/http/provider/__init__.py,sha256=V4JOQuTqLU7taZojxvXo0yVAXESbbyQR9O5iDPyp5x8,154
|
|
36
|
+
tonutils/clients/http/provider/base.py,sha256=pUO3gtaHwhRRYNYyxkaUSMUYH2H6WD5GCyVEgf_hXIM,8336
|
|
37
|
+
tonutils/clients/http/provider/models.py,sha256=RrZZp25Q9UTao-xNcSo7fw9Xk6Rymt-vNZ9iUII9pDw,3509
|
|
38
|
+
tonutils/clients/http/provider/tonapi.py,sha256=l66seJGScfQrPDPqjvCAX9nyvfx14pOfntGuRC6ykTI,3651
|
|
39
|
+
tonutils/clients/http/provider/toncenter.py,sha256=dNbLF13rwaTmG8L6qoagf2EVN1D6XBhQXIccL57-j34,3613
|
|
44
40
|
tonutils/contracts/__init__.py,sha256=KZm3_rQwoY0kO6zFGpPcjrN9XBTjDDvpB2dfaHjwjjw,9561
|
|
45
41
|
tonutils/contracts/base.py,sha256=7AVjsBmcM30Y1fKIIKMVXGr58ZmMfpublunecsSn2W4,10521
|
|
46
42
|
tonutils/contracts/codes.py,sha256=1Sbbs_izHZHd-i1cjWHRP8VN3Xc2BDPr4pnjojj6mZc,37741
|
|
@@ -72,9 +68,9 @@ tonutils/contracts/vanity/models.py,sha256=B6W1TN4CyrMs4SfBDAjuQ8QP-wn5QFhNpcSzO
|
|
|
72
68
|
tonutils/contracts/vanity/tlb.py,sha256=gcNYEGPWMUHYbg_Je9QbBUlmVXF5RmobL-FoCMCF1HA,1078
|
|
73
69
|
tonutils/contracts/vanity/vanity.py,sha256=uYH1zybcOTQQBPciUFxAS6wksBwawKx06YES2tLuguI,1242
|
|
74
70
|
tonutils/contracts/wallet/__init__.py,sha256=Ho3-3C09JNk53ySnQaUnNscchfCtbUdyA2kpWAFzOf4,3295
|
|
75
|
-
tonutils/contracts/wallet/base.py,sha256=
|
|
71
|
+
tonutils/contracts/wallet/base.py,sha256=qv2UzqhPh8hcJoguF9cwVo_K3lx1MOfKJ_q5Ml_-zv4,15830
|
|
76
72
|
tonutils/contracts/wallet/configs.py,sha256=yQfuCEGL_fBuc5qGJ93rPIUATTR8V1wpYscgrWb7cEQ,4082
|
|
77
|
-
tonutils/contracts/wallet/messages.py,sha256=
|
|
73
|
+
tonutils/contracts/wallet/messages.py,sha256=MDzM3HdRYIc_vhmsjeHZcF9z1zpcfSdSh3_s4ecSx7o,13610
|
|
78
74
|
tonutils/contracts/wallet/methods.py,sha256=x7aPt71v3PUFNYHStWQrjLK7_SWPC2MiTG0c15X5TRI,10732
|
|
79
75
|
tonutils/contracts/wallet/params.py,sha256=hqinZJmhWiZUywDcmolvRxB0HYJgMAPDWYJiTmgjZ7w,4569
|
|
80
76
|
tonutils/contracts/wallet/protocol.py,sha256=DCu3CNbcZJ_wwROEK3GlpnwxNY2ZLdE0D2Z23WiyVDY,6200
|
|
@@ -88,21 +84,23 @@ tonutils/contracts/wallet/versions/v3.py,sha256=d7cM8wjmW-1H7jGuY3AuUd7eTY3wq9ZY
|
|
|
88
84
|
tonutils/contracts/wallet/versions/v4.py,sha256=2sAsjJ8_3oYAj5JwWH3PiMyoGbgl6-f7-p6T5X7MGTI,2713
|
|
89
85
|
tonutils/contracts/wallet/versions/v5.py,sha256=1J6KXPOc7Q5S5EdFM9WXQzNGRZrw5EgxDZ9dmyHwsXE,8890
|
|
90
86
|
tonutils/tonconnect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
87
|
+
tonutils/tonconnect/events.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
88
|
+
tonutils/tonconnect/storage.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
89
|
+
tonutils/tonconnect/tonconnect.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
90
|
+
tonutils/tonconnect/bridge/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
91
|
+
tonutils/tonconnect/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
91
92
|
tonutils/tools/__init__.py,sha256=QYOVuGY50FFkWlgIvHc2RPU3xiEWSbwnwZ6wuZPQnCA,102
|
|
92
|
-
tonutils/tools/block_scanner/__init__.py,sha256=
|
|
93
|
-
tonutils/tools/block_scanner/
|
|
94
|
-
tonutils/tools/block_scanner/
|
|
95
|
-
tonutils/tools/block_scanner/
|
|
96
|
-
tonutils/tools/block_scanner/scanner.py,sha256=2arPhNPu-6Klcj-PnSnP3DBVWekhlYjn2iqvN-1wigU,9929
|
|
97
|
-
tonutils/tools/block_scanner/traversal.py,sha256=Zp0Uon0OTvLTsZi-zviMyvJHBsZRUx9XExxLU6LMkVA,3101
|
|
98
|
-
tonutils/tools/block_scanner/where.py,sha256=sZUuabQ5joATkJqUh5R3N5r4P9WblmRrVYEVdZeJvZw,1239
|
|
93
|
+
tonutils/tools/block_scanner/__init__.py,sha256=pYkxmCKXlTtoy96JE41wHMoi0gZxSvoKn_fk1368Ti4,192
|
|
94
|
+
tonutils/tools/block_scanner/events.py,sha256=02K85PR3Jfe6qK-Ve1Mbukk4AWkxCJv1d-C-0tGdH_s,1881
|
|
95
|
+
tonutils/tools/block_scanner/scanner.py,sha256=4kT6WEDSeTFvTfYMOY9Uyefu0PTL27JCUTXdU84VbGQ,14170
|
|
96
|
+
tonutils/tools/block_scanner/storage.py,sha256=7Kw6rdyLkPpBF5Y1mp2qkVZLnexyPumv2hMl9gNk_EI,357
|
|
99
97
|
tonutils/tools/status_monitor/__init__.py,sha256=QnMlA0IDLtCGgXsEgB9q3EJTBo2s5js6lSJk0oZkQZQ,72
|
|
100
98
|
tonutils/tools/status_monitor/console.py,sha256=UX3BzjjzeS_nKFGg4NkZJpu9fR_IAJZdQUMz0HcJCdg,5036
|
|
101
99
|
tonutils/tools/status_monitor/models.py,sha256=yHuiEuij4h2kVoOK3sbhNq6SwiGDW_evZmzUwMy1GQs,608
|
|
102
100
|
tonutils/tools/status_monitor/monitor.py,sha256=8zUwNwFScmcjK9ES7XX1LZWjw49lk8CSUQATcUYM57E,10085
|
|
103
|
-
tonutils-2.0.
|
|
104
|
-
tonutils-2.0.
|
|
105
|
-
tonutils-2.0.
|
|
106
|
-
tonutils-2.0.
|
|
107
|
-
tonutils-2.0.
|
|
108
|
-
tonutils-2.0.
|
|
101
|
+
tonutils-2.0.1b6.dist-info/licenses/LICENSE,sha256=fG-yM-8DSkOTaJ558P7uF5PNXBmineVO9-HC12YbIxs,1060
|
|
102
|
+
tonutils-2.0.1b6.dist-info/METADATA,sha256=tl-rYVN015-v1X54eVQ0jy9pvOpWMo50QnNHQKl_ONs,4181
|
|
103
|
+
tonutils-2.0.1b6.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
|
|
104
|
+
tonutils-2.0.1b6.dist-info/entry_points.txt,sha256=qijo1cqvbbzLVbXp-PCYh19Pgmd7duH6yljmnUPd55I,47
|
|
105
|
+
tonutils-2.0.1b6.dist-info/top_level.txt,sha256=-7H_mGl8S9HKQrkUiTLmEbtMM-knzRzd_a0cZZnuZIU,9
|
|
106
|
+
tonutils-2.0.1b6.dist-info/RECORD,,
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import json
|
|
4
|
-
import typing as t
|
|
5
|
-
|
|
6
|
-
import aiohttp
|
|
7
|
-
|
|
8
|
-
from tonutils.exceptions import ProviderResponseError, CDN_CHALLENGE_MARKERS
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class HttpResponse:
|
|
12
|
-
|
|
13
|
-
@classmethod
|
|
14
|
-
async def read(cls, resp: aiohttp.ClientResponse) -> t.Any:
|
|
15
|
-
body = await resp.read()
|
|
16
|
-
if not body:
|
|
17
|
-
return ""
|
|
18
|
-
|
|
19
|
-
data = body.decode("utf-8", errors="replace").strip()
|
|
20
|
-
if not data:
|
|
21
|
-
return ""
|
|
22
|
-
|
|
23
|
-
try:
|
|
24
|
-
return json.loads(data)
|
|
25
|
-
except (Exception,):
|
|
26
|
-
return data
|
|
27
|
-
|
|
28
|
-
@classmethod
|
|
29
|
-
def raise_error(
|
|
30
|
-
cls,
|
|
31
|
-
*,
|
|
32
|
-
status: int,
|
|
33
|
-
url: str,
|
|
34
|
-
data: t.Any,
|
|
35
|
-
) -> None:
|
|
36
|
-
exc = cls._detect_proxy_error(data, status=status, url=url)
|
|
37
|
-
if exc is not None:
|
|
38
|
-
raise exc
|
|
39
|
-
|
|
40
|
-
message = cls._extract_error_message(data)
|
|
41
|
-
raise ProviderResponseError(
|
|
42
|
-
code=status,
|
|
43
|
-
message=message,
|
|
44
|
-
endpoint=url,
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
@classmethod
|
|
48
|
-
def _detect_proxy_error(
|
|
49
|
-
cls,
|
|
50
|
-
data: t.Any,
|
|
51
|
-
*,
|
|
52
|
-
status: int,
|
|
53
|
-
url: str,
|
|
54
|
-
) -> t.Optional[ProviderResponseError]:
|
|
55
|
-
body = (
|
|
56
|
-
" ".join(str(v) for v in data.values())
|
|
57
|
-
if isinstance(data, dict)
|
|
58
|
-
else str(data)
|
|
59
|
-
).lower()
|
|
60
|
-
|
|
61
|
-
for marker, message in CDN_CHALLENGE_MARKERS.items():
|
|
62
|
-
if marker in body:
|
|
63
|
-
return ProviderResponseError(
|
|
64
|
-
code=status,
|
|
65
|
-
message=message,
|
|
66
|
-
endpoint=url,
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
return None
|
|
70
|
-
|
|
71
|
-
@staticmethod
|
|
72
|
-
def _extract_error_message(data: t.Any) -> str:
|
|
73
|
-
if isinstance(data, dict):
|
|
74
|
-
lowered = {k.lower(): v for k, v in data.items()}
|
|
75
|
-
for key in ("error", "message", "detail", "description"):
|
|
76
|
-
if key in lowered and isinstance(lowered[key], str):
|
|
77
|
-
return lowered[key]
|
|
78
|
-
string_values = [str(v) for v in data.values() if isinstance(v, str)]
|
|
79
|
-
return "; ".join(string_values) if string_values else str(data)
|
|
80
|
-
|
|
81
|
-
if isinstance(data, list):
|
|
82
|
-
return "; ".join(map(str, data))
|
|
83
|
-
if isinstance(data, str):
|
|
84
|
-
return data
|
|
85
|
-
return repr(data)
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import typing as t
|
|
2
|
-
|
|
3
|
-
from pydantic import BaseModel
|
|
4
|
-
|
|
5
|
-
from tonutils.types import ContractState
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class BlockchainMessagePayload(BaseModel):
|
|
9
|
-
"""Payload for /blockchain/message endpoint."""
|
|
10
|
-
|
|
11
|
-
boc: str
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class BlockchainConfigResult(BaseModel):
|
|
15
|
-
"""Result model for /blockchain/config."""
|
|
16
|
-
|
|
17
|
-
raw: t.Optional[str] = None
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class BlockchainAccountResult(BaseModel):
|
|
21
|
-
"""Result model for /blockchain/accounts/{address}."""
|
|
22
|
-
|
|
23
|
-
balance: int = 0
|
|
24
|
-
status: str = ContractState.NONEXIST.value
|
|
25
|
-
code: t.Optional[str] = None
|
|
26
|
-
data: t.Optional[str] = None
|
|
27
|
-
last_transaction_lt: t.Optional[int] = None
|
|
28
|
-
last_transaction_hash: t.Optional[str] = None
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class _BlockchainAccountTransaction(BaseModel):
|
|
32
|
-
"""Single account transaction with raw BoC payload."""
|
|
33
|
-
|
|
34
|
-
raw: t.Optional[str] = None
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class BlockchainAccountTransactionsResult(BaseModel):
|
|
38
|
-
"""Result model for /blockchain/accounts/{address}/transactions."""
|
|
39
|
-
|
|
40
|
-
transactions: t.Optional[t.List[_BlockchainAccountTransaction]] = None
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
class BlockchainAccountMethodResult(BaseModel):
|
|
44
|
-
"""Result model for /blockchain/accounts/{address}/methods/{method_name}."""
|
|
45
|
-
|
|
46
|
-
stack: t.Optional[t.List[t.Any]] = None
|
|
47
|
-
exit_code: int
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import typing as t
|
|
2
|
-
|
|
3
|
-
from tonutils.tools.block_scanner.events import (
|
|
4
|
-
BlockEvent,
|
|
5
|
-
EventBase,
|
|
6
|
-
TransactionEvent,
|
|
7
|
-
TransactionsEvent,
|
|
8
|
-
)
|
|
9
|
-
|
|
10
|
-
TEvent = t.TypeVar("TEvent", bound=EventBase)
|
|
11
|
-
|
|
12
|
-
Handler = t.Callable[[TEvent], t.Awaitable[None]]
|
|
13
|
-
Where = t.Callable[[TEvent], t.Union[bool, t.Awaitable[bool]]]
|
|
14
|
-
|
|
15
|
-
BlockWhere = t.Callable[[BlockEvent], t.Union[bool, t.Awaitable[bool]]]
|
|
16
|
-
TransactionWhere = t.Callable[[TransactionEvent], t.Union[bool, t.Awaitable[bool]]]
|
|
17
|
-
TransactionsWhere = t.Callable[[TransactionsEvent], t.Union[bool, t.Awaitable[bool]]]
|
|
18
|
-
|
|
19
|
-
AnyHandler = t.Callable[[EventBase], t.Awaitable[None]]
|
|
20
|
-
AnyWhere = t.Callable[[EventBase], t.Union[bool, t.Awaitable[bool]]]
|
|
21
|
-
|
|
22
|
-
HandlerEntry = t.Tuple[AnyHandler, t.Optional[AnyWhere]]
|
|
23
|
-
Decorator = t.Callable[[Handler[TEvent]], Handler[TEvent]]
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import inspect
|
|
3
|
-
import traceback
|
|
4
|
-
import typing as t
|
|
5
|
-
|
|
6
|
-
from tonutils.tools.block_scanner.annotations import (
|
|
7
|
-
AnyHandler,
|
|
8
|
-
AnyWhere,
|
|
9
|
-
Decorator,
|
|
10
|
-
Handler,
|
|
11
|
-
HandlerEntry,
|
|
12
|
-
TEvent,
|
|
13
|
-
Where,
|
|
14
|
-
)
|
|
15
|
-
from tonutils.tools.block_scanner.events import EventBase
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class EventDispatcher:
|
|
19
|
-
"""Dispatches events to registered handlers asynchronously."""
|
|
20
|
-
|
|
21
|
-
def __init__(self, max_concurrency: int = 1000) -> None:
|
|
22
|
-
"""
|
|
23
|
-
Initialize EventDispatcher.
|
|
24
|
-
|
|
25
|
-
:param max_concurrency: maximum number of concurrent handler tasks.
|
|
26
|
-
"""
|
|
27
|
-
self._handlers: t.Dict[t.Type[EventBase], t.List[HandlerEntry]] = {}
|
|
28
|
-
self._sem = asyncio.Semaphore(max(1, max_concurrency))
|
|
29
|
-
self._tasks: t.Set[asyncio.Task[None]] = set()
|
|
30
|
-
self._closed = False
|
|
31
|
-
|
|
32
|
-
def register(
|
|
33
|
-
self,
|
|
34
|
-
event_type: t.Type[TEvent],
|
|
35
|
-
handler: Handler[TEvent],
|
|
36
|
-
*,
|
|
37
|
-
where: t.Optional[Where[TEvent]] = None,
|
|
38
|
-
) -> None:
|
|
39
|
-
"""
|
|
40
|
-
Register a handler for a specific event type.
|
|
41
|
-
|
|
42
|
-
:param event_type: subclass of EventBase to handle.
|
|
43
|
-
:param handler: callable receiving the event.
|
|
44
|
-
:param where: optional filter predicate. Handler is invoked only if predicate returns True.
|
|
45
|
-
"""
|
|
46
|
-
if not callable(handler):
|
|
47
|
-
raise TypeError("handler must be callable")
|
|
48
|
-
|
|
49
|
-
entry: HandlerEntry = (
|
|
50
|
-
t.cast(AnyHandler, handler),
|
|
51
|
-
t.cast(t.Optional[AnyWhere], where),
|
|
52
|
-
)
|
|
53
|
-
self._handlers.setdefault(event_type, []).append(entry)
|
|
54
|
-
|
|
55
|
-
def on(
|
|
56
|
-
self,
|
|
57
|
-
event_type: t.Type[TEvent],
|
|
58
|
-
*,
|
|
59
|
-
where: t.Optional[Where[TEvent]] = None,
|
|
60
|
-
) -> Decorator[TEvent]:
|
|
61
|
-
"""
|
|
62
|
-
Decorator to register a handler for an event type.
|
|
63
|
-
|
|
64
|
-
:param event_type: event class to handle.
|
|
65
|
-
:param where: optional filter predicate.
|
|
66
|
-
:return: Decorator that registers the handler.
|
|
67
|
-
"""
|
|
68
|
-
|
|
69
|
-
def decorator(fn: Handler[TEvent]) -> Handler[TEvent]:
|
|
70
|
-
self.register(event_type=event_type, handler=fn, where=where)
|
|
71
|
-
return fn
|
|
72
|
-
|
|
73
|
-
return decorator
|
|
74
|
-
|
|
75
|
-
def _iter_handlers(self, event: EventBase) -> t.Sequence[HandlerEntry]:
|
|
76
|
-
"""Return all handlers matching the type of `event`."""
|
|
77
|
-
out: t.List[HandlerEntry] = []
|
|
78
|
-
for tp in type(event).mro():
|
|
79
|
-
if tp is EventBase:
|
|
80
|
-
break
|
|
81
|
-
entries = self._handlers.get(t.cast(t.Type[EventBase], tp))
|
|
82
|
-
if entries:
|
|
83
|
-
out.extend(entries)
|
|
84
|
-
return out
|
|
85
|
-
|
|
86
|
-
def _on_task_done(self, task: asyncio.Task[None]) -> None:
|
|
87
|
-
"""Callback to handle task completion and print exceptions."""
|
|
88
|
-
self._tasks.discard(task)
|
|
89
|
-
try:
|
|
90
|
-
exc = task.exception()
|
|
91
|
-
except asyncio.CancelledError:
|
|
92
|
-
return
|
|
93
|
-
if exc is not None:
|
|
94
|
-
traceback.print_exception(type(exc), exc, exc.__traceback__)
|
|
95
|
-
|
|
96
|
-
async def _run_task(
|
|
97
|
-
self,
|
|
98
|
-
handler: AnyHandler,
|
|
99
|
-
event: EventBase,
|
|
100
|
-
where: t.Optional[AnyWhere] = None,
|
|
101
|
-
) -> None:
|
|
102
|
-
"""
|
|
103
|
-
Run a single handler task with optional 'where' filtering.
|
|
104
|
-
|
|
105
|
-
:param handler: async callable to execute.
|
|
106
|
-
:param event: event instance to pass.
|
|
107
|
-
:param where: optional predicate, skip handler if False.
|
|
108
|
-
"""
|
|
109
|
-
async with self._sem:
|
|
110
|
-
if where is not None:
|
|
111
|
-
result = where(event)
|
|
112
|
-
if inspect.isawaitable(result):
|
|
113
|
-
result = await result
|
|
114
|
-
if not result:
|
|
115
|
-
return
|
|
116
|
-
await handler(event)
|
|
117
|
-
|
|
118
|
-
def emit(self, event: EventBase) -> None:
|
|
119
|
-
"""
|
|
120
|
-
Emit an event to all matching handlers.
|
|
121
|
-
|
|
122
|
-
Handlers are executed asynchronously.
|
|
123
|
-
"""
|
|
124
|
-
if self._closed:
|
|
125
|
-
return
|
|
126
|
-
|
|
127
|
-
for handler, where in self._iter_handlers(event):
|
|
128
|
-
task = asyncio.create_task(self._run_task(handler, event, where))
|
|
129
|
-
self._tasks.add(task)
|
|
130
|
-
task.add_done_callback(self._on_task_done)
|
|
131
|
-
|
|
132
|
-
async def aclose(self) -> None:
|
|
133
|
-
"""
|
|
134
|
-
Close the dispatcher and wait for all running handler tasks.
|
|
135
|
-
|
|
136
|
-
After calling, no new events will be dispatched.
|
|
137
|
-
"""
|
|
138
|
-
self._closed = True
|
|
139
|
-
if self._tasks:
|
|
140
|
-
await asyncio.gather(*self._tasks, return_exceptions=True)
|
|
141
|
-
self._tasks.clear()
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import typing as t
|
|
2
|
-
|
|
3
|
-
from pytoniq_core.tl import BlockIdExt
|
|
4
|
-
from pytoniq_core.tlb.block import ExtBlkRef
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class ShardTraversal:
|
|
8
|
-
|
|
9
|
-
@staticmethod
|
|
10
|
-
def shard_key(blk: BlockIdExt) -> t.Tuple[int, int]:
|
|
11
|
-
return blk.workchain, blk.shard
|
|
12
|
-
|
|
13
|
-
@staticmethod
|
|
14
|
-
def simulate_overflow(x: int) -> int:
|
|
15
|
-
return (x + 2**63) % 2**64 - 2**63
|
|
16
|
-
|
|
17
|
-
@staticmethod
|
|
18
|
-
def lower_bit64(num: int) -> int:
|
|
19
|
-
return num & (~num + 1)
|
|
20
|
-
|
|
21
|
-
def get_child_shard(self, shard: int, *, left: bool) -> int:
|
|
22
|
-
x = self.lower_bit64(shard) >> 1
|
|
23
|
-
if left:
|
|
24
|
-
return self.simulate_overflow(shard - x)
|
|
25
|
-
return self.simulate_overflow(shard + x)
|
|
26
|
-
|
|
27
|
-
def get_parent_shard(self, shard: int) -> int:
|
|
28
|
-
x = self.lower_bit64(shard)
|
|
29
|
-
return self.simulate_overflow((shard - x) | (x << 1))
|
|
30
|
-
|
|
31
|
-
async def walk_unseen(
|
|
32
|
-
self,
|
|
33
|
-
*,
|
|
34
|
-
root: BlockIdExt,
|
|
35
|
-
seen_seqno: t.Dict[t.Tuple[int, int], int],
|
|
36
|
-
get_header: t.Callable[[BlockIdExt], t.Awaitable[t.Any]],
|
|
37
|
-
out: t.Optional[t.List[BlockIdExt]] = None,
|
|
38
|
-
) -> t.List[BlockIdExt]:
|
|
39
|
-
"""Recursively walk from root block back to seen blocks."""
|
|
40
|
-
if out is None:
|
|
41
|
-
out = []
|
|
42
|
-
|
|
43
|
-
key = self.shard_key(root)
|
|
44
|
-
if seen_seqno.get(key, -1) >= root.seqno:
|
|
45
|
-
return out
|
|
46
|
-
|
|
47
|
-
_, header = await get_header(root)
|
|
48
|
-
prev_ref = header.info.prev_ref
|
|
49
|
-
|
|
50
|
-
if prev_ref.type_ == "prev_blk_info":
|
|
51
|
-
prev: ExtBlkRef = prev_ref.prev
|
|
52
|
-
prev_shard = (
|
|
53
|
-
self.get_parent_shard(root.shard)
|
|
54
|
-
if header.info.after_split
|
|
55
|
-
else root.shard
|
|
56
|
-
)
|
|
57
|
-
await self.walk_unseen(
|
|
58
|
-
root=BlockIdExt(
|
|
59
|
-
workchain=root.workchain,
|
|
60
|
-
shard=prev_shard,
|
|
61
|
-
seqno=prev.seqno,
|
|
62
|
-
root_hash=prev.root_hash,
|
|
63
|
-
file_hash=prev.file_hash,
|
|
64
|
-
),
|
|
65
|
-
seen_seqno=seen_seqno,
|
|
66
|
-
get_header=get_header,
|
|
67
|
-
out=out,
|
|
68
|
-
)
|
|
69
|
-
else:
|
|
70
|
-
prev1, prev2 = prev_ref.prev1, prev_ref.prev2
|
|
71
|
-
await self.walk_unseen(
|
|
72
|
-
root=BlockIdExt(
|
|
73
|
-
workchain=root.workchain,
|
|
74
|
-
shard=self.get_child_shard(root.shard, left=True),
|
|
75
|
-
seqno=prev1.seqno,
|
|
76
|
-
root_hash=prev1.root_hash,
|
|
77
|
-
file_hash=prev1.file_hash,
|
|
78
|
-
),
|
|
79
|
-
seen_seqno=seen_seqno,
|
|
80
|
-
get_header=get_header,
|
|
81
|
-
out=out,
|
|
82
|
-
)
|
|
83
|
-
await self.walk_unseen(
|
|
84
|
-
root=BlockIdExt(
|
|
85
|
-
workchain=root.workchain,
|
|
86
|
-
shard=self.get_child_shard(root.shard, left=False),
|
|
87
|
-
seqno=prev2.seqno,
|
|
88
|
-
root_hash=prev2.root_hash,
|
|
89
|
-
file_hash=prev2.file_hash,
|
|
90
|
-
),
|
|
91
|
-
seen_seqno=seen_seqno,
|
|
92
|
-
get_header=get_header,
|
|
93
|
-
out=out,
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
out.append(root)
|
|
97
|
-
return out
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import typing as t
|
|
4
|
-
|
|
5
|
-
from tonutils.tools.block_scanner.annotations import TEvent
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class Where(t.Generic[TEvent]):
|
|
9
|
-
__slots__ = ()
|
|
10
|
-
|
|
11
|
-
def __call__(self, event: TEvent) -> bool:
|
|
12
|
-
raise NotImplementedError
|
|
13
|
-
|
|
14
|
-
def __and__(self, other: Where[TEvent]) -> _And[TEvent]:
|
|
15
|
-
return _And(self, other)
|
|
16
|
-
|
|
17
|
-
def __or__(self, other: Where[TEvent]) -> _Or[TEvent]:
|
|
18
|
-
return _Or(self, other)
|
|
19
|
-
|
|
20
|
-
def __invert__(self) -> _Not[TEvent]:
|
|
21
|
-
return _Not(self)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class _And(Where[TEvent]):
|
|
25
|
-
__slots__ = ("_a", "_b")
|
|
26
|
-
|
|
27
|
-
def __init__(self, a: Where[TEvent], b: Where[TEvent]) -> None:
|
|
28
|
-
self._a = a
|
|
29
|
-
self._b = b
|
|
30
|
-
|
|
31
|
-
def __call__(self, event: TEvent) -> bool:
|
|
32
|
-
return self._a(event) and self._b(event)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class _Or(Where[TEvent]):
|
|
36
|
-
__slots__ = ("_a", "_b")
|
|
37
|
-
|
|
38
|
-
def __init__(self, a: Where[TEvent], b: Where[TEvent]) -> None:
|
|
39
|
-
self._a = a
|
|
40
|
-
self._b = b
|
|
41
|
-
|
|
42
|
-
def __call__(self, event: TEvent) -> bool:
|
|
43
|
-
return self._a(event) or self._b(event)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
class _Not(Where[TEvent]):
|
|
47
|
-
__slots__ = ("_f",)
|
|
48
|
-
|
|
49
|
-
def __init__(self, f: Where[TEvent]) -> None:
|
|
50
|
-
self._f = f
|
|
51
|
-
|
|
52
|
-
def __call__(self, event: TEvent) -> bool:
|
|
53
|
-
return not self._f(event)
|
|
File without changes
|
|
File without changes
|