tonutils 2.0.1b6__py3-none-any.whl → 2.0.1b7__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/adnl/balancer.py +132 -355
- tonutils/clients/adnl/client.py +32 -202
- tonutils/clients/adnl/mixin.py +268 -0
- 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/base.py +32 -32
- tonutils/contracts/protocol.py +9 -9
- tonutils/contracts/wallet/base.py +5 -5
- tonutils/contracts/wallet/versions/v5.py +2 -2
- tonutils/exceptions.py +29 -13
- 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 +2 -2
- {tonutils-2.0.1b6.dist-info → tonutils-2.0.1b7.dist-info}/METADATA +3 -18
- {tonutils-2.0.1b6.dist-info → tonutils-2.0.1b7.dist-info}/RECORD +33 -32
- {tonutils-2.0.1b6.dist-info → tonutils-2.0.1b7.dist-info}/WHEEL +0 -0
- {tonutils-2.0.1b6.dist-info → tonutils-2.0.1b7.dist-info}/entry_points.txt +0 -0
- {tonutils-2.0.1b6.dist-info → tonutils-2.0.1b7.dist-info}/licenses/LICENSE +0 -0
- {tonutils-2.0.1b6.dist-info → tonutils-2.0.1b7.dist-info}/top_level.txt +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import typing as t
|
|
2
2
|
|
|
3
3
|
import aiohttp
|
|
4
|
-
from pydantic import BaseModel
|
|
5
4
|
|
|
6
5
|
from tonutils.clients.http.provider.base import HttpProvider
|
|
7
6
|
from tonutils.clients.http.provider.models import (
|
|
@@ -10,7 +9,7 @@ from tonutils.clients.http.provider.models import (
|
|
|
10
9
|
GetAddressInformationResult,
|
|
11
10
|
GetTransactionsResult,
|
|
12
11
|
RunGetMethodPayload,
|
|
13
|
-
|
|
12
|
+
RunGetMethodResult,
|
|
14
13
|
)
|
|
15
14
|
from tonutils.types import NetworkGlobalID, RetryPolicy
|
|
16
15
|
|
|
@@ -37,6 +36,7 @@ class ToncenterHttpProvider(HttpProvider):
|
|
|
37
36
|
}
|
|
38
37
|
base_url = base_url or urls[network]
|
|
39
38
|
headers = {**(headers or {}), **({"X-Api-Key": api_key} if api_key else {})}
|
|
39
|
+
|
|
40
40
|
super().__init__(
|
|
41
41
|
base_url=base_url,
|
|
42
42
|
session=session,
|
|
@@ -48,10 +48,6 @@ class ToncenterHttpProvider(HttpProvider):
|
|
|
48
48
|
retry_policy=retry_policy,
|
|
49
49
|
)
|
|
50
50
|
|
|
51
|
-
@staticmethod
|
|
52
|
-
def _model(model: t.Type[BaseModel], data: t.Any) -> t.Any:
|
|
53
|
-
return model.model_validate(data)
|
|
54
|
-
|
|
55
51
|
async def send_boc(
|
|
56
52
|
self,
|
|
57
53
|
payload: SendBocPayload,
|
|
@@ -116,9 +112,9 @@ class ToncenterHttpProvider(HttpProvider):
|
|
|
116
112
|
async def run_get_method(
|
|
117
113
|
self,
|
|
118
114
|
payload: RunGetMethodPayload,
|
|
119
|
-
) ->
|
|
115
|
+
) -> RunGetMethodResult:
|
|
120
116
|
return self._model(
|
|
121
|
-
|
|
117
|
+
RunGetMethodResult,
|
|
122
118
|
await self.send_http_request(
|
|
123
119
|
"POST",
|
|
124
120
|
"/runGetMethod",
|
tonutils/clients/protocol.py
CHANGED
|
@@ -6,7 +6,7 @@ from pytoniq_core import Cell, Transaction
|
|
|
6
6
|
|
|
7
7
|
from tonutils.types import (
|
|
8
8
|
AddressLike,
|
|
9
|
-
|
|
9
|
+
ContractInfo,
|
|
10
10
|
DNSCategory,
|
|
11
11
|
NetworkGlobalID,
|
|
12
12
|
ClientType,
|
|
@@ -40,19 +40,19 @@ class ClientProtocol(t.Protocol):
|
|
|
40
40
|
"""Underlying provider or transport backend."""
|
|
41
41
|
|
|
42
42
|
@property
|
|
43
|
-
def
|
|
43
|
+
def connected(self) -> bool:
|
|
44
44
|
"""Whether the client is connected and ready for requests."""
|
|
45
45
|
|
|
46
|
-
async def
|
|
46
|
+
async def send_message(self, boc: str) -> None:
|
|
47
47
|
"""Send an external message to the blockchain."""
|
|
48
48
|
|
|
49
|
-
async def
|
|
49
|
+
async def get_config(self) -> t.Dict[int, t.Any]:
|
|
50
50
|
"""Fetch global blockchain configuration."""
|
|
51
51
|
|
|
52
|
-
async def
|
|
52
|
+
async def get_info(
|
|
53
53
|
self,
|
|
54
54
|
address: AddressLike,
|
|
55
|
-
) ->
|
|
55
|
+
) -> ContractInfo:
|
|
56
56
|
"""Fetch basic contract state information."""
|
|
57
57
|
|
|
58
58
|
async def get_transactions(
|
tonutils/contracts/base.py
CHANGED
|
@@ -13,7 +13,7 @@ from tonutils.exceptions import (
|
|
|
13
13
|
StateNotLoadedError,
|
|
14
14
|
ProviderResponseError,
|
|
15
15
|
)
|
|
16
|
-
from tonutils.types import AddressLike,
|
|
16
|
+
from tonutils.types import AddressLike, ContractInfo, ContractState, WorkchainID
|
|
17
17
|
from tonutils.utils import to_cell
|
|
18
18
|
|
|
19
19
|
_R = t.TypeVar("_R")
|
|
@@ -61,7 +61,7 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
61
61
|
client: ClientProtocol,
|
|
62
62
|
address: Address,
|
|
63
63
|
state_init: t.Optional[StateInit] = None,
|
|
64
|
-
|
|
64
|
+
info: t.Optional[ContractInfo] = None,
|
|
65
65
|
) -> None:
|
|
66
66
|
"""
|
|
67
67
|
Initialize base contract wrapper.
|
|
@@ -69,12 +69,12 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
69
69
|
:param client: TON client for blockchain interactions
|
|
70
70
|
:param address: Contract address on the blockchain
|
|
71
71
|
:param state_init: Optional known StateInit (code and data)
|
|
72
|
-
:param
|
|
72
|
+
:param info: Optional preloaded on-chain contract state
|
|
73
73
|
"""
|
|
74
74
|
self._client = client
|
|
75
75
|
self._address = address
|
|
76
76
|
self._state_init = state_init
|
|
77
|
-
self.
|
|
77
|
+
self._info = info
|
|
78
78
|
|
|
79
79
|
@property
|
|
80
80
|
def client(self) -> ClientProtocol:
|
|
@@ -91,17 +91,6 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
91
91
|
"""Locally known StateInit for this contract, if any."""
|
|
92
92
|
return self._state_init
|
|
93
93
|
|
|
94
|
-
@property
|
|
95
|
-
def state_info(self) -> ContractStateInfo:
|
|
96
|
-
"""
|
|
97
|
-
Cached snapshot of the contract state.
|
|
98
|
-
|
|
99
|
-
:return: Contract state information
|
|
100
|
-
"""
|
|
101
|
-
if self._state_info is None:
|
|
102
|
-
raise StateNotLoadedError(self, missing="state_info")
|
|
103
|
-
return t.cast(ContractStateInfo, self._state_info)
|
|
104
|
-
|
|
105
94
|
@property
|
|
106
95
|
def state_data(self) -> _D:
|
|
107
96
|
"""
|
|
@@ -113,11 +102,22 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
113
102
|
"""
|
|
114
103
|
if not hasattr(self, "_data_model") or self._data_model is None:
|
|
115
104
|
raise ContractError(self, "No `_data_model` defined for contract class.")
|
|
116
|
-
if not (self.
|
|
105
|
+
if not (self._info and self._info.data):
|
|
117
106
|
raise StateNotLoadedError(self, missing="state_data")
|
|
118
|
-
cs = self.
|
|
107
|
+
cs = self._info.data.begin_parse()
|
|
119
108
|
return self._data_model.deserialize(cs)
|
|
120
109
|
|
|
110
|
+
@property
|
|
111
|
+
def info(self) -> ContractInfo:
|
|
112
|
+
"""
|
|
113
|
+
Cached snapshot of the contract state info.
|
|
114
|
+
|
|
115
|
+
:return: Contract state information
|
|
116
|
+
"""
|
|
117
|
+
if self._info is None:
|
|
118
|
+
raise StateNotLoadedError(self, missing="info")
|
|
119
|
+
return t.cast(ContractInfo, self._info)
|
|
120
|
+
|
|
121
121
|
@property
|
|
122
122
|
def balance(self) -> int:
|
|
123
123
|
"""
|
|
@@ -125,7 +125,7 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
125
125
|
|
|
126
126
|
:return: Balance from the latest known state
|
|
127
127
|
"""
|
|
128
|
-
return self.
|
|
128
|
+
return self.info.balance
|
|
129
129
|
|
|
130
130
|
@property
|
|
131
131
|
def state(self) -> ContractState:
|
|
@@ -134,7 +134,7 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
134
134
|
|
|
135
135
|
:return: One of ContractState enum values (ACTIVE, FROZEN, UNINIT, NONEXIST)
|
|
136
136
|
"""
|
|
137
|
-
return self.
|
|
137
|
+
return self.info.state
|
|
138
138
|
|
|
139
139
|
@property
|
|
140
140
|
def is_active(self) -> bool:
|
|
@@ -179,7 +179,7 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
179
179
|
|
|
180
180
|
:return: Transaction LT or None if unknown
|
|
181
181
|
"""
|
|
182
|
-
return self.
|
|
182
|
+
return self.info.last_transaction_lt
|
|
183
183
|
|
|
184
184
|
@property
|
|
185
185
|
def last_transaction_hash(self) -> t.Optional[str]:
|
|
@@ -188,7 +188,7 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
188
188
|
|
|
189
189
|
:return: Transaction hash as hex string or None if unknown
|
|
190
190
|
"""
|
|
191
|
-
return self.
|
|
191
|
+
return self.info.last_transaction_hash
|
|
192
192
|
|
|
193
193
|
@property
|
|
194
194
|
def code(self) -> t.Optional[Cell]:
|
|
@@ -197,7 +197,7 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
197
197
|
|
|
198
198
|
:return: Code cell or None if not available
|
|
199
199
|
"""
|
|
200
|
-
return self.
|
|
200
|
+
return self.info.code
|
|
201
201
|
|
|
202
202
|
@property
|
|
203
203
|
def data(self) -> t.Optional[Cell]:
|
|
@@ -206,36 +206,36 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
206
206
|
|
|
207
207
|
:return: Data cell or None if not available
|
|
208
208
|
"""
|
|
209
|
-
return self.
|
|
209
|
+
return self.info.data
|
|
210
210
|
|
|
211
211
|
@classmethod
|
|
212
|
-
async def
|
|
212
|
+
async def _load_info(
|
|
213
213
|
cls,
|
|
214
214
|
client: ClientProtocol,
|
|
215
215
|
address: Address,
|
|
216
|
-
) ->
|
|
216
|
+
) -> ContractInfo:
|
|
217
217
|
"""
|
|
218
218
|
Fetch contract state from the blockchain.
|
|
219
219
|
|
|
220
220
|
If the request fails (except rate limits), sets state to default empty state.
|
|
221
221
|
"""
|
|
222
222
|
try:
|
|
223
|
-
return await client.
|
|
223
|
+
return await client.get_info(address)
|
|
224
224
|
except ProviderResponseError as e:
|
|
225
225
|
if e.code in {429, 228, 5556}: # rate limit exceed
|
|
226
226
|
raise
|
|
227
|
-
return
|
|
227
|
+
return ContractInfo()
|
|
228
228
|
except (Exception,):
|
|
229
|
-
return
|
|
229
|
+
return ContractInfo()
|
|
230
230
|
|
|
231
231
|
async def refresh(self) -> None:
|
|
232
232
|
"""
|
|
233
233
|
Refresh contract state from the blockchain.
|
|
234
234
|
|
|
235
|
-
Fetches current contract information and updates the cached
|
|
235
|
+
Fetches current contract information and updates the cached info.
|
|
236
236
|
If the request fails (except rate limits), sets state to default empty state.
|
|
237
237
|
"""
|
|
238
|
-
self.
|
|
238
|
+
self._info = await self._load_info(self.client, self.address)
|
|
239
239
|
|
|
240
240
|
@classmethod
|
|
241
241
|
def from_state_init(
|
|
@@ -323,8 +323,8 @@ class BaseContract(ContractProtocol[_D]):
|
|
|
323
323
|
if not load_state:
|
|
324
324
|
return cls(client, address)
|
|
325
325
|
|
|
326
|
-
|
|
327
|
-
return cls(client, address,
|
|
326
|
+
info = await cls._load_info(client, address)
|
|
327
|
+
return cls(client, address, info=info)
|
|
328
328
|
|
|
329
329
|
def __repr__(self) -> str:
|
|
330
330
|
return f"< Contract {self.__class__.__name__} address: {self.address} >"
|
tonutils/contracts/protocol.py
CHANGED
|
@@ -5,7 +5,7 @@ import typing as t
|
|
|
5
5
|
from pytoniq_core import Address, Cell, StateInit
|
|
6
6
|
|
|
7
7
|
from tonutils.clients.protocol import ClientProtocol
|
|
8
|
-
from tonutils.types import AddressLike,
|
|
8
|
+
from tonutils.types import AddressLike, ContractInfo, ContractState, WorkchainID
|
|
9
9
|
|
|
10
10
|
if t.TYPE_CHECKING:
|
|
11
11
|
from tonutils.contracts.versions import ContractVersion
|
|
@@ -48,21 +48,21 @@ class ContractProtocol(t.Protocol[_D]):
|
|
|
48
48
|
"""Locally known StateInit for this contract, if any."""
|
|
49
49
|
|
|
50
50
|
@property
|
|
51
|
-
def
|
|
51
|
+
def state_data(self) -> _D:
|
|
52
52
|
"""
|
|
53
|
-
|
|
53
|
+
Decoded on-chain data in typed form.
|
|
54
54
|
|
|
55
|
-
Implementations
|
|
56
|
-
|
|
55
|
+
Implementations must decode the current data cell from info
|
|
56
|
+
using the associated _data_model.
|
|
57
57
|
"""
|
|
58
58
|
|
|
59
59
|
@property
|
|
60
|
-
def
|
|
60
|
+
def info(self) -> ContractInfo:
|
|
61
61
|
"""
|
|
62
|
-
|
|
62
|
+
Cached snapshot of the contract state info.
|
|
63
63
|
|
|
64
|
-
Implementations
|
|
65
|
-
|
|
64
|
+
Implementations usually update this via refresh() or in constructors
|
|
65
|
+
that read on-chain data.
|
|
66
66
|
"""
|
|
67
67
|
|
|
68
68
|
@property
|
|
@@ -22,7 +22,7 @@ from tonutils.contracts.wallet.tlb import BaseWalletData
|
|
|
22
22
|
from tonutils.exceptions import ContractError
|
|
23
23
|
from tonutils.types import (
|
|
24
24
|
AddressLike,
|
|
25
|
-
|
|
25
|
+
ContractInfo,
|
|
26
26
|
SendMode,
|
|
27
27
|
PublicKey,
|
|
28
28
|
PrivateKey,
|
|
@@ -61,7 +61,7 @@ class BaseWallet(BaseContract, WalletProtocol[_D, _C, _P], abc.ABC):
|
|
|
61
61
|
client: ClientProtocol,
|
|
62
62
|
address: Address,
|
|
63
63
|
state_init: t.Optional[StateInit] = None,
|
|
64
|
-
|
|
64
|
+
info: t.Optional[ContractInfo] = None,
|
|
65
65
|
config: t.Optional[_C] = None,
|
|
66
66
|
private_key: t.Optional[PrivateKey] = None,
|
|
67
67
|
) -> None:
|
|
@@ -71,7 +71,7 @@ class BaseWallet(BaseContract, WalletProtocol[_D, _C, _P], abc.ABC):
|
|
|
71
71
|
:param client: TON client for blockchain interactions
|
|
72
72
|
:param address: Wallet address on the blockchain
|
|
73
73
|
:param state_init: Optional StateInit (code and data)
|
|
74
|
-
:param
|
|
74
|
+
:param info: Optional preloaded contract state
|
|
75
75
|
:param config: Optional wallet configuration
|
|
76
76
|
:param private_key: Optional private key for signing transactions
|
|
77
77
|
"""
|
|
@@ -82,7 +82,7 @@ class BaseWallet(BaseContract, WalletProtocol[_D, _C, _P], abc.ABC):
|
|
|
82
82
|
if private_key is not None:
|
|
83
83
|
self._private_key = private_key
|
|
84
84
|
self._public_key = private_key.public_key
|
|
85
|
-
super().__init__(client, address, state_init,
|
|
85
|
+
super().__init__(client, address, state_init, info)
|
|
86
86
|
|
|
87
87
|
@property
|
|
88
88
|
def state_data(self) -> _D:
|
|
@@ -295,7 +295,7 @@ class BaseWallet(BaseContract, WalletProtocol[_D, _C, _P], abc.ABC):
|
|
|
295
295
|
:return: Signed external message that was sent
|
|
296
296
|
"""
|
|
297
297
|
external_msg = await self.build_external_message(messages, params)
|
|
298
|
-
await self.client.
|
|
298
|
+
await self.client.send_message(external_msg.as_hex)
|
|
299
299
|
return external_msg
|
|
300
300
|
|
|
301
301
|
async def transfer_message(
|
|
@@ -219,13 +219,13 @@ class WalletV5R1(
|
|
|
219
219
|
|
|
220
220
|
:return: Typed wallet data
|
|
221
221
|
"""
|
|
222
|
-
if not (self.
|
|
222
|
+
if not (self._info and self._info.data):
|
|
223
223
|
raise StateNotLoadedError(self, missing="state_data")
|
|
224
224
|
|
|
225
225
|
network_global_id = (
|
|
226
226
|
NetworkGlobalID.TESTNET if self.client.network else NetworkGlobalID.MAINNET
|
|
227
227
|
)
|
|
228
|
-
cs = self.
|
|
228
|
+
cs = self._info.data.begin_parse()
|
|
229
229
|
return self._data_model.deserialize(cs, network_global_id)
|
|
230
230
|
|
|
231
231
|
async def _build_msg_cell(
|
tonutils/exceptions.py
CHANGED
|
@@ -27,7 +27,7 @@ class TransportError(TonutilsError):
|
|
|
27
27
|
|
|
28
28
|
Covers: TCP connect, ADNL handshake, send/recv, crypto failures.
|
|
29
29
|
|
|
30
|
-
:param endpoint:
|
|
30
|
+
:param endpoint: Endpoint identifier (URL or "host:port").
|
|
31
31
|
:param operation: What was attempted ("connect", "handshake", "send", "recv")
|
|
32
32
|
:param reason: Why it failed ("timeout 2.0s", "connection refused", etc.)
|
|
33
33
|
"""
|
|
@@ -46,7 +46,7 @@ class TransportError(TonutilsError):
|
|
|
46
46
|
self.endpoint = endpoint
|
|
47
47
|
self.operation = operation
|
|
48
48
|
self.reason = reason
|
|
49
|
-
super().__init__(f"{operation} failed
|
|
49
|
+
super().__init__(f"{operation} failed: {reason} ({endpoint})")
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
class ProviderError(TonutilsError):
|
|
@@ -64,14 +64,28 @@ class BalancerError(TonutilsError):
|
|
|
64
64
|
class NotConnectedError(TonutilsError, RuntimeError):
|
|
65
65
|
"""Raise when an operation requires an active connection."""
|
|
66
66
|
|
|
67
|
+
component: str
|
|
67
68
|
endpoint: t.Optional[str]
|
|
69
|
+
operation: t.Optional[str]
|
|
68
70
|
|
|
69
|
-
def __init__(
|
|
71
|
+
def __init__(
|
|
72
|
+
self,
|
|
73
|
+
*,
|
|
74
|
+
component: str = "client",
|
|
75
|
+
endpoint: t.Optional[str] = None,
|
|
76
|
+
operation: t.Optional[str] = None,
|
|
77
|
+
hint: t.Optional[str] = None,
|
|
78
|
+
) -> None:
|
|
79
|
+
self.component = component
|
|
70
80
|
self.endpoint = endpoint
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
81
|
+
self.operation = operation
|
|
82
|
+
|
|
83
|
+
if hint is None:
|
|
84
|
+
hint = "Call connect() first or use an async context manager (`async with ...`)."
|
|
85
|
+
|
|
86
|
+
where = f" ({endpoint})" if endpoint else ""
|
|
87
|
+
prefix = f"cannot `{operation}`: " if operation else ""
|
|
88
|
+
super().__init__(f"{prefix}{component} is not connected{where}. {hint}")
|
|
75
89
|
|
|
76
90
|
|
|
77
91
|
class ProviderTimeoutError(ProviderError, asyncio.TimeoutError):
|
|
@@ -90,7 +104,7 @@ class ProviderTimeoutError(ProviderError, asyncio.TimeoutError):
|
|
|
90
104
|
self.timeout = timeout
|
|
91
105
|
self.endpoint = endpoint
|
|
92
106
|
self.operation = operation
|
|
93
|
-
super().__init__(f"{operation} timed out after {timeout}s
|
|
107
|
+
super().__init__(f"{operation} timed out after {timeout}s ({endpoint})")
|
|
94
108
|
|
|
95
109
|
|
|
96
110
|
class ProviderResponseError(ProviderError):
|
|
@@ -109,7 +123,7 @@ class ProviderResponseError(ProviderError):
|
|
|
109
123
|
self.code = code
|
|
110
124
|
self.message = message
|
|
111
125
|
self.endpoint = endpoint
|
|
112
|
-
super().__init__(f"request failed
|
|
126
|
+
super().__init__(f"request failed: {code} {message} ({endpoint})")
|
|
113
127
|
|
|
114
128
|
|
|
115
129
|
class RetryLimitError(ProviderError):
|
|
@@ -134,7 +148,9 @@ class RetryLimitError(ProviderError):
|
|
|
134
148
|
self.attempts = attempts
|
|
135
149
|
self.max_attempts = max_attempts
|
|
136
150
|
self.last_error = last_error
|
|
137
|
-
super().__init__(
|
|
151
|
+
super().__init__(
|
|
152
|
+
f"retry limit reached ({attempts}/{max_attempts}): {last_error}"
|
|
153
|
+
)
|
|
138
154
|
|
|
139
155
|
|
|
140
156
|
class ContractError(ClientError):
|
|
@@ -153,14 +169,14 @@ class ContractError(ClientError):
|
|
|
153
169
|
name = (
|
|
154
170
|
target.__name__ if isinstance(target, type) else target.__class__.__name__
|
|
155
171
|
)
|
|
156
|
-
super().__init__(f"{name}: {message}")
|
|
172
|
+
super().__init__(f"{name} failed: {message}")
|
|
157
173
|
|
|
158
174
|
|
|
159
175
|
class StateNotLoadedError(ContractError):
|
|
160
176
|
"""Raise when a contract wrapper requires state that is not loaded.
|
|
161
177
|
|
|
162
178
|
:param contract: Contract instance related to the failure.
|
|
163
|
-
:param missing: Missing field name (e.g. "
|
|
179
|
+
:param missing: Missing field name (e.g. "info", "state_data").
|
|
164
180
|
"""
|
|
165
181
|
|
|
166
182
|
missing: str
|
|
@@ -188,7 +204,7 @@ class RunGetMethodError(ClientError):
|
|
|
188
204
|
self.method_name = method_name
|
|
189
205
|
self.exit_code = exit_code
|
|
190
206
|
super().__init__(
|
|
191
|
-
f"get-method
|
|
207
|
+
f"get-method `{method_name}` failed: exit code {exit_code} ({address})"
|
|
192
208
|
)
|
|
193
209
|
|
|
194
210
|
|
|
@@ -237,7 +237,7 @@ class BlockScanner:
|
|
|
237
237
|
if self._on_transactions is None:
|
|
238
238
|
continue
|
|
239
239
|
|
|
240
|
-
get_block_transactions = self._client.
|
|
240
|
+
get_block_transactions = self._client.get_block_transactions
|
|
241
241
|
try:
|
|
242
242
|
transactions = await get_block_transactions(shard_block)
|
|
243
243
|
except asyncio.CancelledError:
|
|
@@ -114,7 +114,7 @@ class LiteServerMonitor:
|
|
|
114
114
|
self._tasks.append(asyncio.create_task(slow))
|
|
115
115
|
|
|
116
116
|
async def _ensure_connected(self, index: int, client: LiteClient) -> bool:
|
|
117
|
-
if client.provider.
|
|
117
|
+
if client.provider.connected:
|
|
118
118
|
return True
|
|
119
119
|
|
|
120
120
|
now = time.monotonic()
|
|
@@ -124,7 +124,7 @@ class LiteServerMonitor:
|
|
|
124
124
|
|
|
125
125
|
self._last_connect[index] = now
|
|
126
126
|
await self._connect(index, client)
|
|
127
|
-
return client.provider.
|
|
127
|
+
return client.provider.connected
|
|
128
128
|
|
|
129
129
|
async def _fast_update_loop(self, index: int, client: LiteClient) -> None:
|
|
130
130
|
while not self._stop.is_set():
|
|
@@ -141,7 +141,7 @@ class LiteServerMonitor:
|
|
|
141
141
|
|
|
142
142
|
async def _medium_update_loop(self, index: int, client: LiteClient) -> None:
|
|
143
143
|
while not self._stop.is_set():
|
|
144
|
-
if not client.
|
|
144
|
+
if not client.connected:
|
|
145
145
|
await self._sleep(1.0)
|
|
146
146
|
continue
|
|
147
147
|
|
|
@@ -154,7 +154,7 @@ class LiteServerMonitor:
|
|
|
154
154
|
|
|
155
155
|
async def _slow_update_loop(self, index: int, client: LiteClient) -> None:
|
|
156
156
|
while not self._stop.is_set():
|
|
157
|
-
if not client.
|
|
157
|
+
if not client.connected:
|
|
158
158
|
await self._sleep(1.0)
|
|
159
159
|
continue
|
|
160
160
|
|
|
@@ -223,14 +223,14 @@ class LiteServerMonitor:
|
|
|
223
223
|
return
|
|
224
224
|
|
|
225
225
|
mc_txs, shards = await asyncio.gather(
|
|
226
|
-
client.
|
|
226
|
+
client.get_block_transactions(mc_block),
|
|
227
227
|
client.get_all_shards_info(mc_block),
|
|
228
228
|
)
|
|
229
229
|
last_mc_block = BlockInfo(seqno=mc_block.seqno, txs_count=len(mc_txs))
|
|
230
230
|
|
|
231
231
|
if shards:
|
|
232
232
|
bc_block = max(shards, key=lambda b: b.seqno)
|
|
233
|
-
bc_txs = await client.
|
|
233
|
+
bc_txs = await client.get_block_transactions(bc_block)
|
|
234
234
|
last_bc_block = BlockInfo(seqno=bc_block.seqno, txs_count=len(bc_txs))
|
|
235
235
|
await self._set_status(
|
|
236
236
|
index,
|
tonutils/types.py
CHANGED
|
@@ -16,7 +16,7 @@ __all__ = [
|
|
|
16
16
|
"BinaryLike",
|
|
17
17
|
"ClientType",
|
|
18
18
|
"ContractState",
|
|
19
|
-
"
|
|
19
|
+
"ContractInfo",
|
|
20
20
|
"DNSCategory",
|
|
21
21
|
"DNSPrefix",
|
|
22
22
|
"MetadataPrefix",
|
|
@@ -189,7 +189,7 @@ class ContractState(str, Enum):
|
|
|
189
189
|
NONEXIST = "nonexist"
|
|
190
190
|
|
|
191
191
|
|
|
192
|
-
class
|
|
192
|
+
class ContractInfo:
|
|
193
193
|
"""
|
|
194
194
|
TON smart contract state information.
|
|
195
195
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tonutils
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.1b7
|
|
4
4
|
Summary: Tonutils is a high-level, object-oriented Python library designed to facilitate seamless interactions with the TON blockchain.
|
|
5
5
|
Author: nessshon
|
|
6
6
|
Maintainer: nessshon
|
|
@@ -69,27 +69,13 @@ pip install --pre tonutils
|
|
|
69
69
|
|
|
70
70
|
## Usage
|
|
71
71
|
|
|
72
|
-
Practical feature examples can be found in the **[examples](examples)** directory
|
|
73
|
-
Each script demonstrates real-world usage and can be used as a reference when integrating `tonutils` into your project.
|
|
74
|
-
|
|
75
|
-
## Contribution
|
|
76
|
-
|
|
77
|
-
We welcome your contributions! If you have ideas for improvement or have identified a bug, please create an issue or
|
|
78
|
-
submit a pull request.
|
|
72
|
+
Practical feature examples can be found in the **[examples](examples)** directory.
|
|
79
73
|
|
|
80
74
|
## Donations
|
|
81
75
|
|
|
82
76
|
Your contributions help me continue developing and improving this project!
|
|
83
77
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
- **BTC**: `1JXHbB5kE1DfkHdv5dsNygRkNC3unJdU8M`
|
|
87
|
-
|
|
88
|
-
- **USDT** (TRC-20): `TU4fCFdWufKb4rd25ihksiNDZZdyEYqro6`
|
|
89
|
-
|
|
90
|
-
- **Crypto Bot**: [Donate through Crypto Bot](https://t.me/send?start=IVW1cyG3DYqG)
|
|
91
|
-
|
|
92
|
-
- **xRocket Bot**: [Donate through xRocket](https://t.me/xrocket?start=inv_R4llrClZtPjovVe)
|
|
78
|
+
**TON**: `UQCZq3_Vd21-4y4m7Wc-ej9NFOhh_qvdfAkAYAOHoQ__Ness`
|
|
93
79
|
|
|
94
80
|
## Support
|
|
95
81
|
|
|
@@ -99,4 +85,3 @@ With special thanks to [Igroman787](https://github.com/Igroman787) for the suppo
|
|
|
99
85
|
## License
|
|
100
86
|
|
|
101
87
|
This repository is distributed under the [MIT License](LICENSE).
|
|
102
|
-
Feel free to use, modify, and distribute the code in accordance with the terms of the license.
|