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
|
@@ -14,6 +14,7 @@ from pytoniq_core import (
|
|
|
14
14
|
Transaction,
|
|
15
15
|
VmStack,
|
|
16
16
|
deserialize_shard_hashes,
|
|
17
|
+
ShardAccount,
|
|
17
18
|
)
|
|
18
19
|
from pytoniq_core.crypto.ciphers import get_random
|
|
19
20
|
from pytoniq_core.crypto.crc import crc16
|
|
@@ -41,7 +42,7 @@ from tonutils.exceptions import (
|
|
|
41
42
|
ProviderResponseError,
|
|
42
43
|
)
|
|
43
44
|
from tonutils.types import (
|
|
44
|
-
|
|
45
|
+
ContractInfo,
|
|
45
46
|
RetryPolicy,
|
|
46
47
|
WorkchainID,
|
|
47
48
|
)
|
|
@@ -95,13 +96,13 @@ class AdnlProvider:
|
|
|
95
96
|
self._connect_lock: asyncio.Lock = asyncio.Lock()
|
|
96
97
|
|
|
97
98
|
@property
|
|
98
|
-
def
|
|
99
|
+
def connected(self) -> bool:
|
|
99
100
|
"""
|
|
100
101
|
Whether the underlying transport is currently connected.
|
|
101
102
|
|
|
102
103
|
:return: True if connected, False otherwise
|
|
103
104
|
"""
|
|
104
|
-
return self.transport.
|
|
105
|
+
return self.transport.connected
|
|
105
106
|
|
|
106
107
|
@property
|
|
107
108
|
def last_mc_block(self) -> BlockIdExt:
|
|
@@ -165,7 +166,7 @@ class AdnlProvider:
|
|
|
165
166
|
|
|
166
167
|
Establishes transport, performs handshake and starts background workers.
|
|
167
168
|
"""
|
|
168
|
-
if self.
|
|
169
|
+
if self.connected:
|
|
169
170
|
return
|
|
170
171
|
|
|
171
172
|
self.loop = asyncio.get_running_loop()
|
|
@@ -215,8 +216,12 @@ class AdnlProvider:
|
|
|
215
216
|
:param priority: Whether to use priority slot in the limiter
|
|
216
217
|
:return: Lite-server response payload as a decoded dictionary
|
|
217
218
|
"""
|
|
218
|
-
if not self.
|
|
219
|
-
raise NotConnectedError(
|
|
219
|
+
if not self.connected or self.loop is None:
|
|
220
|
+
raise NotConnectedError(
|
|
221
|
+
component="AdnlProvider",
|
|
222
|
+
endpoint=self.node.endpoint,
|
|
223
|
+
operation="request",
|
|
224
|
+
)
|
|
220
225
|
|
|
221
226
|
if self._limiter is not None:
|
|
222
227
|
await self._limiter.acquire(priority=priority)
|
|
@@ -492,7 +497,7 @@ class AdnlProvider:
|
|
|
492
497
|
|
|
493
498
|
return block_id, block_obj
|
|
494
499
|
|
|
495
|
-
async def
|
|
500
|
+
async def get_block_transactions(
|
|
496
501
|
self,
|
|
497
502
|
block: BlockIdExt,
|
|
498
503
|
count: int = 1024,
|
|
@@ -591,7 +596,7 @@ class AdnlProvider:
|
|
|
591
596
|
for sh in v.list
|
|
592
597
|
]
|
|
593
598
|
|
|
594
|
-
async def
|
|
599
|
+
async def run_get_method(
|
|
595
600
|
self,
|
|
596
601
|
address: Address,
|
|
597
602
|
method_name: str,
|
|
@@ -643,7 +648,7 @@ class AdnlProvider:
|
|
|
643
648
|
cs = Slice.one_from_boc(result["result"])
|
|
644
649
|
return VmStack.deserialize(cs)
|
|
645
650
|
|
|
646
|
-
async def
|
|
651
|
+
async def get_config(
|
|
647
652
|
self,
|
|
648
653
|
*,
|
|
649
654
|
priority: bool = False,
|
|
@@ -667,18 +672,18 @@ class AdnlProvider:
|
|
|
667
672
|
config_proof = Cell.one_from_boc(result.get("config_proof"))
|
|
668
673
|
return build_config_all(config_proof)
|
|
669
674
|
|
|
670
|
-
async def
|
|
675
|
+
async def get_info(
|
|
671
676
|
self,
|
|
672
677
|
address: Address,
|
|
673
678
|
*,
|
|
674
679
|
priority: bool = False,
|
|
675
|
-
) ->
|
|
680
|
+
) -> ContractInfo:
|
|
676
681
|
"""
|
|
677
682
|
Fetch contract state at the latest masterchain block.
|
|
678
683
|
|
|
679
684
|
:param address: Contract address
|
|
680
685
|
:param priority: Whether to use priority slot in the limiter
|
|
681
|
-
:return:
|
|
686
|
+
:return: ContractInfo with balance, code, data and last tx
|
|
682
687
|
"""
|
|
683
688
|
if self.last_mc_block is None:
|
|
684
689
|
await self.updater.refresh()
|
|
@@ -693,7 +698,7 @@ class AdnlProvider:
|
|
|
693
698
|
priority=priority,
|
|
694
699
|
)
|
|
695
700
|
if not result["state"]:
|
|
696
|
-
return
|
|
701
|
+
return ContractInfo(balance=0)
|
|
697
702
|
|
|
698
703
|
account_state_root = Cell.one_from_boc(result["state"])
|
|
699
704
|
account = Account.deserialize(account_state_root.begin_parse())
|
|
@@ -755,9 +760,9 @@ class AdnlProvider:
|
|
|
755
760
|
for i, cell in enumerate(cells):
|
|
756
761
|
curr_hash = cell.get_hash(0).hex()
|
|
757
762
|
if curr_hash != prev_tr_hash:
|
|
758
|
-
raise
|
|
759
|
-
|
|
760
|
-
f"expected {prev_tr_hash}, got {curr_hash}"
|
|
763
|
+
raise ProviderError(
|
|
764
|
+
"getTransactions failed: transaction hash mismatch "
|
|
765
|
+
f"(expected {prev_tr_hash}, got {curr_hash})"
|
|
761
766
|
)
|
|
762
767
|
|
|
763
768
|
tx = Transaction.deserialize(cell.begin_parse())
|
|
@@ -765,3 +770,43 @@ class AdnlProvider:
|
|
|
765
770
|
transactions.append(tx)
|
|
766
771
|
|
|
767
772
|
return transactions
|
|
773
|
+
|
|
774
|
+
async def get_account_state(
|
|
775
|
+
self,
|
|
776
|
+
address: Address,
|
|
777
|
+
*,
|
|
778
|
+
priority: bool = False,
|
|
779
|
+
) -> t.Tuple[t.Optional[Account], t.Optional[ShardAccount]]:
|
|
780
|
+
"""
|
|
781
|
+
Fetch account state and shard account from lite-server.
|
|
782
|
+
|
|
783
|
+
:param address: Account address
|
|
784
|
+
:param priority: Whether to use priority slot in the limiter
|
|
785
|
+
:return: Tuple of (Account | None, ShardAccount | None)
|
|
786
|
+
"""
|
|
787
|
+
if self.last_mc_block is None:
|
|
788
|
+
await self.updater.refresh()
|
|
789
|
+
|
|
790
|
+
data = {
|
|
791
|
+
"id": self.last_mc_block.to_dict(),
|
|
792
|
+
"account": address.to_tl_account_id(),
|
|
793
|
+
}
|
|
794
|
+
result = await self.send_liteserver_query(
|
|
795
|
+
method="getAccountState",
|
|
796
|
+
data=data,
|
|
797
|
+
priority=priority,
|
|
798
|
+
)
|
|
799
|
+
if not result.get("state"):
|
|
800
|
+
return None, None
|
|
801
|
+
|
|
802
|
+
account_state_root = Cell.one_from_boc(result["state"])
|
|
803
|
+
account = Account.deserialize(account_state_root.begin_parse())
|
|
804
|
+
|
|
805
|
+
shrd_blk = BlockIdExt.from_dict(result["shardblk"])
|
|
806
|
+
shard_account = build_shard_account(
|
|
807
|
+
account_state_root=account_state_root,
|
|
808
|
+
shard_account_descr=result["proof"],
|
|
809
|
+
shrd_blk=shrd_blk,
|
|
810
|
+
address=address,
|
|
811
|
+
)
|
|
812
|
+
return account, shard_account
|
|
@@ -64,7 +64,7 @@ class AdnlTcpTransport:
|
|
|
64
64
|
self._closing = False
|
|
65
65
|
|
|
66
66
|
@property
|
|
67
|
-
def
|
|
67
|
+
def connected(self) -> bool:
|
|
68
68
|
"""Check if the transport is currently connected."""
|
|
69
69
|
return self._connected
|
|
70
70
|
|
|
@@ -178,7 +178,7 @@ class AdnlTcpTransport:
|
|
|
178
178
|
"connect", f"timeout after {self.connect_timeout}s"
|
|
179
179
|
) from exc
|
|
180
180
|
except OSError as exc:
|
|
181
|
-
raise self._error("connect",
|
|
181
|
+
raise self._error("connect", str(exc)) from exc
|
|
182
182
|
|
|
183
183
|
if self.writer is None or self.reader is None:
|
|
184
184
|
raise self._error("connect", "stream init failed")
|
|
@@ -218,7 +218,11 @@ class AdnlTcpTransport:
|
|
|
218
218
|
:param payload: Raw ADNL packet bytes
|
|
219
219
|
"""
|
|
220
220
|
if not self._connected or self.writer is None:
|
|
221
|
-
raise NotConnectedError(
|
|
221
|
+
raise NotConnectedError(
|
|
222
|
+
component="ADNL transport",
|
|
223
|
+
endpoint=self.node.endpoint,
|
|
224
|
+
operation="send",
|
|
225
|
+
)
|
|
222
226
|
|
|
223
227
|
packet = self._build_frame(payload)
|
|
224
228
|
encrypted = self.encrypt_frame(packet)
|
|
@@ -233,7 +237,12 @@ class AdnlTcpTransport:
|
|
|
233
237
|
Blocks until a complete packet is available from the background reader.
|
|
234
238
|
"""
|
|
235
239
|
if not self._connected:
|
|
236
|
-
raise NotConnectedError(
|
|
240
|
+
raise NotConnectedError(
|
|
241
|
+
component="ADNL transport",
|
|
242
|
+
endpoint=self.node.endpoint,
|
|
243
|
+
operation="recv",
|
|
244
|
+
)
|
|
245
|
+
|
|
237
246
|
return await self._incoming.get()
|
|
238
247
|
|
|
239
248
|
async def read_frame(self, discard: bool = False) -> t.Optional[bytes]:
|
tonutils/clients/adnl/utils.py
CHANGED
|
@@ -15,7 +15,7 @@ from pytoniq_core import (
|
|
|
15
15
|
VmTuple,
|
|
16
16
|
)
|
|
17
17
|
|
|
18
|
-
from tonutils.types import ContractState,
|
|
18
|
+
from tonutils.types import ContractState, ContractInfo, StackItems, StackItem
|
|
19
19
|
from tonutils.utils import cell_to_hex, norm_stack_num, norm_stack_cell
|
|
20
20
|
|
|
21
21
|
|
|
@@ -72,17 +72,17 @@ def build_contract_state_info(
|
|
|
72
72
|
address: Address,
|
|
73
73
|
account: Account,
|
|
74
74
|
shard_account: ShardAccount,
|
|
75
|
-
) ->
|
|
75
|
+
) -> ContractInfo:
|
|
76
76
|
"""
|
|
77
|
-
Build a high-level
|
|
77
|
+
Build a high-level ContractInfo object from raw account data.
|
|
78
78
|
|
|
79
79
|
:param address: Contract address
|
|
80
80
|
:param account: Raw Account data structure
|
|
81
81
|
:param shard_account: Parsed ShardAccount entry
|
|
82
|
-
:return: Filled
|
|
82
|
+
:return: Filled ContractInfo instance
|
|
83
83
|
"""
|
|
84
84
|
simple_account = SimpleAccount.from_raw(account, address)
|
|
85
|
-
info =
|
|
85
|
+
info = ContractInfo(balance=simple_account.balance)
|
|
86
86
|
|
|
87
87
|
if simple_account.state is not None:
|
|
88
88
|
state_init = simple_account.state.state_init
|
tonutils/clients/base.py
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import abc
|
|
4
|
+
import asyncio
|
|
4
5
|
import typing as t
|
|
6
|
+
from contextlib import suppress
|
|
5
7
|
|
|
6
8
|
from pytoniq_core import Address, Cell, Transaction, begin_cell
|
|
7
9
|
|
|
10
|
+
from tonutils.exceptions import ProviderError
|
|
8
11
|
from tonutils.types import (
|
|
9
12
|
AddressLike,
|
|
10
|
-
|
|
13
|
+
ContractInfo,
|
|
11
14
|
ClientType,
|
|
12
15
|
DNSCategory,
|
|
13
16
|
NetworkGlobalID,
|
|
@@ -36,66 +39,39 @@ class BaseClient(abc.ABC):
|
|
|
36
39
|
|
|
37
40
|
@property
|
|
38
41
|
@abc.abstractmethod
|
|
39
|
-
def
|
|
42
|
+
def connected(self) -> bool:
|
|
40
43
|
"""
|
|
41
|
-
|
|
44
|
+
Check whether provider resources are initialized and usable.
|
|
42
45
|
|
|
43
|
-
|
|
44
|
-
type (HTTP session, ADNL transport, etc.).
|
|
46
|
+
:return: True if client has an active session/connection, False otherwise
|
|
45
47
|
"""
|
|
46
|
-
raise NotImplementedError
|
|
47
48
|
|
|
49
|
+
@property
|
|
48
50
|
@abc.abstractmethod
|
|
49
|
-
|
|
51
|
+
def provider(self) -> t.Any:
|
|
50
52
|
"""
|
|
51
|
-
|
|
53
|
+
Underlying transport/provider backend used for all requests.
|
|
52
54
|
|
|
53
|
-
|
|
55
|
+
Expected to expose network I/O primitives appropriate for the client
|
|
56
|
+
type (HTTP session, ADNL transport, etc.).
|
|
54
57
|
"""
|
|
55
|
-
raise NotImplementedError
|
|
56
58
|
|
|
57
59
|
@abc.abstractmethod
|
|
58
|
-
async def
|
|
59
|
-
|
|
60
|
-
exc_type: t.Optional[t.Type[BaseException]],
|
|
61
|
-
exc_value: t.Optional[BaseException],
|
|
62
|
-
traceback: t.Optional[t.Any],
|
|
63
|
-
) -> None:
|
|
64
|
-
"""
|
|
65
|
-
Release allocated client resources.
|
|
66
|
-
|
|
67
|
-
Called automatically when the async context ends.
|
|
68
|
-
"""
|
|
69
|
-
raise NotImplementedError
|
|
60
|
+
async def connect(self) -> None:
|
|
61
|
+
"""Initialize any required provider resources (sessions, transports, etc.)."""
|
|
70
62
|
|
|
71
63
|
@abc.abstractmethod
|
|
72
|
-
async def
|
|
73
|
-
"""
|
|
74
|
-
Send an external message to the network using the underlying provider.
|
|
75
|
-
|
|
76
|
-
:param boc: Message body serialized as BoC string,
|
|
77
|
-
in a format accepted by the underlying provider
|
|
78
|
-
"""
|
|
79
|
-
raise NotImplementedError
|
|
64
|
+
async def close(self) -> None:
|
|
65
|
+
"""Close provider resources. Should be safe to call multiple times."""
|
|
80
66
|
|
|
81
67
|
@abc.abstractmethod
|
|
82
|
-
async def
|
|
83
|
-
"""
|
|
84
|
-
Fetch full blockchain configuration from the underlying provider.
|
|
85
|
-
|
|
86
|
-
:return: Mapping of configuration parameter ID to parsed value
|
|
87
|
-
"""
|
|
88
|
-
raise NotImplementedError
|
|
68
|
+
async def _send_message(self, boc: str) -> None: ...
|
|
89
69
|
|
|
90
70
|
@abc.abstractmethod
|
|
91
|
-
async def
|
|
92
|
-
"""
|
|
93
|
-
Retrieve basic contract state information from the provider.
|
|
71
|
+
async def _get_config(self) -> t.Dict[int, t.Any]: ...
|
|
94
72
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
"""
|
|
98
|
-
raise NotImplementedError
|
|
73
|
+
@abc.abstractmethod
|
|
74
|
+
async def _get_info(self, address: str) -> ContractInfo: ...
|
|
99
75
|
|
|
100
76
|
@abc.abstractmethod
|
|
101
77
|
async def _get_transactions(
|
|
@@ -104,20 +80,7 @@ class BaseClient(abc.ABC):
|
|
|
104
80
|
limit: int = 100,
|
|
105
81
|
from_lt: t.Optional[int] = None,
|
|
106
82
|
to_lt: t.Optional[int] = None,
|
|
107
|
-
) -> t.List[Transaction]:
|
|
108
|
-
"""
|
|
109
|
-
Fetch transaction history for a contract.
|
|
110
|
-
Returns transactions in the range (to_lt, from_lt), ordered from newest to oldest.
|
|
111
|
-
|
|
112
|
-
:param address: Contract address as string
|
|
113
|
-
:param limit: Maximum number of transactions to return
|
|
114
|
-
:param from_lt: Upper bound logical time (inclusive).
|
|
115
|
-
If None, starts from the most recent transaction.
|
|
116
|
-
:param to_lt: Lower bound logical time (exclusive).
|
|
117
|
-
If None or 0, no lower bound is applied.
|
|
118
|
-
:return: List of Transaction objects ordered from newest to oldest
|
|
119
|
-
"""
|
|
120
|
-
raise NotImplementedError
|
|
83
|
+
) -> t.List[Transaction]: ...
|
|
121
84
|
|
|
122
85
|
@abc.abstractmethod
|
|
123
86
|
async def _run_get_method(
|
|
@@ -125,63 +88,57 @@ class BaseClient(abc.ABC):
|
|
|
125
88
|
address: str,
|
|
126
89
|
method_name: str,
|
|
127
90
|
stack: t.Optional[t.List[t.Any]] = None,
|
|
128
|
-
) -> t.List[t.Any]:
|
|
129
|
-
"""
|
|
130
|
-
Execute a contract get-method via the provider.
|
|
91
|
+
) -> t.List[t.Any]: ...
|
|
131
92
|
|
|
132
|
-
|
|
133
|
-
:param method_name: Name of the get-method to execute
|
|
134
|
-
:param stack: Optional initial TVM stack items for the call
|
|
135
|
-
:return: Decoded TVM stack items returned by the method
|
|
93
|
+
async def __aenter__(self) -> BaseClient:
|
|
136
94
|
"""
|
|
137
|
-
|
|
95
|
+
Prepare client resources for use.
|
|
138
96
|
|
|
139
|
-
|
|
140
|
-
@abc.abstractmethod
|
|
141
|
-
def is_connected(self) -> bool:
|
|
97
|
+
Should initialize network connections or sessions as required.
|
|
142
98
|
"""
|
|
143
|
-
|
|
99
|
+
await self.connect()
|
|
100
|
+
return self
|
|
144
101
|
|
|
145
|
-
|
|
102
|
+
async def __aexit__(
|
|
103
|
+
self,
|
|
104
|
+
exc_type: t.Optional[t.Type[BaseException]],
|
|
105
|
+
exc_value: t.Optional[BaseException],
|
|
106
|
+
traceback: t.Optional[t.Any],
|
|
107
|
+
) -> None:
|
|
146
108
|
"""
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
@abc.abstractmethod
|
|
150
|
-
async def connect(self) -> None:
|
|
151
|
-
"""Initialize any required provider resources (sessions, transports, etc.)."""
|
|
152
|
-
raise NotImplementedError
|
|
109
|
+
Release allocated client resources.
|
|
153
110
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
111
|
+
Called automatically when the async context ends.
|
|
112
|
+
"""
|
|
113
|
+
with suppress(asyncio.CancelledError):
|
|
114
|
+
await self.close()
|
|
158
115
|
|
|
159
|
-
async def
|
|
116
|
+
async def send_message(self, boc: str) -> None:
|
|
160
117
|
"""
|
|
161
118
|
Send an external message to the blockchain.
|
|
162
119
|
|
|
163
120
|
:param boc: Message body serialized as BoC string, in a format accepted by the underlying provider
|
|
164
121
|
"""
|
|
165
|
-
await self.
|
|
122
|
+
await self._send_message(boc)
|
|
166
123
|
|
|
167
|
-
async def
|
|
124
|
+
async def get_config(self) -> t.Dict[int, t.Any]:
|
|
168
125
|
"""
|
|
169
126
|
Fetch and decode global blockchain configuration.
|
|
170
127
|
|
|
171
128
|
:return: Mapping of configuration parameter ID to parsed value
|
|
172
129
|
"""
|
|
173
|
-
return await self.
|
|
130
|
+
return await self._get_config()
|
|
174
131
|
|
|
175
|
-
async def
|
|
132
|
+
async def get_info(self, address: AddressLike) -> ContractInfo:
|
|
176
133
|
"""
|
|
177
134
|
Fetch basic state information for a smart contract.
|
|
178
135
|
|
|
179
136
|
:param address: Contract address as Address object or string
|
|
180
|
-
:return:
|
|
137
|
+
:return: ContractInfo with code, data, balance and last tx data
|
|
181
138
|
"""
|
|
182
139
|
if isinstance(address, Address):
|
|
183
140
|
address = Address(address).to_str(is_user_friendly=False)
|
|
184
|
-
return await self.
|
|
141
|
+
return await self._get_info(address=address)
|
|
185
142
|
|
|
186
143
|
async def get_transactions(
|
|
187
144
|
self,
|
|
@@ -192,7 +149,6 @@ class BaseClient(abc.ABC):
|
|
|
192
149
|
) -> t.List[Transaction]:
|
|
193
150
|
"""
|
|
194
151
|
Fetch transaction history for a contract.
|
|
195
|
-
Returns transactions in the range (to_lt, from_lt), ordered from newest to oldest.
|
|
196
152
|
|
|
197
153
|
:param address: Contract address as Address object or string
|
|
198
154
|
:param limit: Maximum number of transactions to return
|
|
@@ -262,7 +218,7 @@ class BaseClient(abc.ABC):
|
|
|
262
218
|
if isinstance(domain, str):
|
|
263
219
|
domain = encode_dns_name(domain)
|
|
264
220
|
if dns_root_address is None:
|
|
265
|
-
blockchain_config = await self.
|
|
221
|
+
blockchain_config = await self.get_config()
|
|
266
222
|
hash_part = blockchain_config[4].dns_root_addr
|
|
267
223
|
dns_root_address = Address((WorkchainID.MASTERCHAIN.value, hash_part))
|
|
268
224
|
|
|
@@ -274,7 +230,9 @@ class BaseClient(abc.ABC):
|
|
|
274
230
|
stack=[domain_cell.to_slice(), category.value],
|
|
275
231
|
)
|
|
276
232
|
if len(res) < 2:
|
|
277
|
-
raise
|
|
233
|
+
raise ProviderError(
|
|
234
|
+
f"dnsresolve failed: invalid response (expected 2 stack items, got {len(res)})"
|
|
235
|
+
)
|
|
278
236
|
|
|
279
237
|
blen = len(domain) * 8
|
|
280
238
|
rlen = t.cast(int, res[0])
|
|
@@ -285,7 +243,9 @@ class BaseClient(abc.ABC):
|
|
|
285
243
|
return None
|
|
286
244
|
|
|
287
245
|
if rlen % 8 != 0 or rlen > blen:
|
|
288
|
-
raise
|
|
246
|
+
raise ProviderError(
|
|
247
|
+
f"dnsresolve failed: invalid resolved length {rlen} bits (domain {blen} bits)"
|
|
248
|
+
)
|
|
289
249
|
if rlen == blen:
|
|
290
250
|
# noinspection PyProtectedMember
|
|
291
251
|
tcls = DNSRecords._DNS_RECORDS_CLASSES.get(category.name.lower())
|