web3 7.6.1__py3-none-any.whl → 7.8.0__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.
- ens/async_ens.py +1 -1
- ens/ens.py +1 -1
- web3/_utils/caching/caching_utils.py +64 -0
- web3/_utils/caching/request_caching_validation.py +1 -0
- web3/_utils/events.py +1 -1
- web3/_utils/http_session_manager.py +32 -3
- web3/_utils/module_testing/eth_module.py +5 -18
- web3/_utils/module_testing/module_testing_utils.py +1 -43
- web3/_utils/module_testing/persistent_connection_provider.py +696 -207
- web3/_utils/module_testing/utils.py +99 -33
- web3/beacon/api_endpoints.py +10 -0
- web3/beacon/async_beacon.py +47 -0
- web3/beacon/beacon.py +45 -0
- web3/contract/async_contract.py +2 -206
- web3/contract/base_contract.py +217 -13
- web3/contract/contract.py +2 -205
- web3/datastructures.py +15 -16
- web3/eth/async_eth.py +23 -5
- web3/exceptions.py +7 -0
- web3/main.py +24 -3
- web3/manager.py +140 -48
- web3/method.py +1 -1
- web3/middleware/attrdict.py +12 -22
- web3/middleware/base.py +14 -6
- web3/module.py +17 -21
- web3/providers/async_base.py +23 -14
- web3/providers/base.py +6 -8
- web3/providers/ipc.py +7 -6
- web3/providers/legacy_websocket.py +1 -1
- web3/providers/persistent/async_ipc.py +5 -3
- web3/providers/persistent/persistent.py +121 -17
- web3/providers/persistent/persistent_connection.py +11 -4
- web3/providers/persistent/request_processor.py +49 -41
- web3/providers/persistent/subscription_container.py +56 -0
- web3/providers/persistent/subscription_manager.py +298 -0
- web3/providers/persistent/websocket.py +4 -4
- web3/providers/rpc/async_rpc.py +16 -3
- web3/providers/rpc/rpc.py +9 -5
- web3/types.py +28 -14
- web3/utils/__init__.py +4 -0
- web3/utils/subscriptions.py +289 -0
- {web3-7.6.1.dist-info → web3-7.8.0.dist-info}/LICENSE +1 -1
- {web3-7.6.1.dist-info → web3-7.8.0.dist-info}/METADATA +68 -56
- {web3-7.6.1.dist-info → web3-7.8.0.dist-info}/RECORD +46 -43
- {web3-7.6.1.dist-info → web3-7.8.0.dist-info}/WHEEL +1 -1
- {web3-7.6.1.dist-info → web3-7.8.0.dist-info}/top_level.txt +0 -0
|
@@ -10,10 +10,14 @@ from typing import (
|
|
|
10
10
|
cast,
|
|
11
11
|
)
|
|
12
12
|
|
|
13
|
-
from toolz import (
|
|
13
|
+
from eth_utils.toolz import (
|
|
14
14
|
merge,
|
|
15
15
|
)
|
|
16
16
|
|
|
17
|
+
from web3.providers.persistent import (
|
|
18
|
+
PersistentConnectionProvider,
|
|
19
|
+
)
|
|
20
|
+
|
|
17
21
|
if TYPE_CHECKING:
|
|
18
22
|
from web3 import ( # noqa: F401
|
|
19
23
|
AsyncWeb3,
|
|
@@ -26,6 +30,7 @@ if TYPE_CHECKING:
|
|
|
26
30
|
AsyncMakeRequestFn,
|
|
27
31
|
MakeRequestFn,
|
|
28
32
|
RPCEndpoint,
|
|
33
|
+
RPCRequest,
|
|
29
34
|
RPCResponse,
|
|
30
35
|
)
|
|
31
36
|
|
|
@@ -101,9 +106,21 @@ class RequestMocker:
|
|
|
101
106
|
self.mock_results = mock_results or {}
|
|
102
107
|
self.mock_errors = mock_errors or {}
|
|
103
108
|
self.mock_responses = mock_responses or {}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
109
|
+
if isinstance(w3.provider, PersistentConnectionProvider):
|
|
110
|
+
self._send_request = w3.provider.send_request
|
|
111
|
+
self._recv_for_request = w3.provider.recv_for_request
|
|
112
|
+
else:
|
|
113
|
+
self._make_request: Union[
|
|
114
|
+
"AsyncMakeRequestFn", "MakeRequestFn"
|
|
115
|
+
] = w3.provider.make_request
|
|
116
|
+
|
|
117
|
+
def _build_request_id(self) -> int:
|
|
118
|
+
request_id = (
|
|
119
|
+
next(copy.deepcopy(self.w3.provider.request_counter))
|
|
120
|
+
if hasattr(self.w3.provider, "request_counter")
|
|
121
|
+
else 1
|
|
122
|
+
)
|
|
123
|
+
return request_id
|
|
107
124
|
|
|
108
125
|
def __enter__(self) -> "Self":
|
|
109
126
|
# mypy error: Cannot assign to a method
|
|
@@ -131,11 +148,7 @@ class RequestMocker:
|
|
|
131
148
|
):
|
|
132
149
|
return self._make_request(method, params)
|
|
133
150
|
|
|
134
|
-
request_id = (
|
|
135
|
-
next(copy.deepcopy(self.w3.provider.request_counter))
|
|
136
|
-
if hasattr(self.w3.provider, "request_counter")
|
|
137
|
-
else 1
|
|
138
|
-
)
|
|
151
|
+
request_id = self._build_request_id()
|
|
139
152
|
response_dict = {"jsonrpc": "2.0", "id": request_id}
|
|
140
153
|
|
|
141
154
|
if method in self.mock_responses:
|
|
@@ -176,35 +189,34 @@ class RequestMocker:
|
|
|
176
189
|
# -- async -- #
|
|
177
190
|
|
|
178
191
|
async def __aenter__(self) -> "Self":
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
192
|
+
if not isinstance(self.w3.provider, PersistentConnectionProvider):
|
|
193
|
+
# mypy error: Cannot assign to a method
|
|
194
|
+
self.w3.provider.make_request = self._async_mock_request_handler # type: ignore[method-assign] # noqa: E501
|
|
195
|
+
# reset request func cache to re-build request_func w/ mocked make_request
|
|
196
|
+
self.w3.provider._request_func_cache = (None, None)
|
|
197
|
+
else:
|
|
198
|
+
self.w3.provider.send_request = self._async_mock_send_handler # type: ignore[method-assign] # noqa: E501
|
|
199
|
+
self.w3.provider.recv_for_request = self._async_mock_recv_handler # type: ignore[method-assign] # noqa: E501
|
|
200
|
+
self.w3.provider._send_func_cache = (None, None)
|
|
201
|
+
self.w3.provider._recv_func_cache = (None, None)
|
|
183
202
|
return self
|
|
184
203
|
|
|
185
204
|
async def __aexit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
205
|
+
if not isinstance(self.w3.provider, PersistentConnectionProvider):
|
|
206
|
+
# mypy error: Cannot assign to a method
|
|
207
|
+
self.w3.provider.make_request = self._make_request # type: ignore[assignment] # noqa: E501
|
|
208
|
+
# reset request func cache to re-build request_func w/ original make_request
|
|
209
|
+
self.w3.provider._request_func_cache = (None, None)
|
|
210
|
+
else:
|
|
211
|
+
self.w3.provider.send_request = self._send_request # type: ignore[method-assign] # noqa: E501
|
|
212
|
+
self.w3.provider.recv_for_request = self._recv_for_request # type: ignore[method-assign] # noqa: E501
|
|
213
|
+
self.w3.provider._send_func_cache = (None, None)
|
|
214
|
+
self.w3.provider._recv_func_cache = (None, None)
|
|
190
215
|
|
|
191
|
-
async def
|
|
192
|
-
self, method: "RPCEndpoint", params: Any
|
|
216
|
+
async def _async_build_mock_result(
|
|
217
|
+
self, method: "RPCEndpoint", params: Any, request_id: int = None
|
|
193
218
|
) -> "RPCResponse":
|
|
194
|
-
|
|
195
|
-
self._make_request = cast("AsyncMakeRequestFn", self._make_request)
|
|
196
|
-
|
|
197
|
-
if all(
|
|
198
|
-
method not in mock_dict
|
|
199
|
-
for mock_dict in (self.mock_errors, self.mock_results, self.mock_responses)
|
|
200
|
-
):
|
|
201
|
-
return await self._make_request(method, params)
|
|
202
|
-
|
|
203
|
-
request_id = (
|
|
204
|
-
next(copy.deepcopy(self.w3.provider.request_counter))
|
|
205
|
-
if hasattr(self.w3.provider, "request_counter")
|
|
206
|
-
else 1
|
|
207
|
-
)
|
|
219
|
+
request_id = request_id if request_id else self._build_request_id()
|
|
208
220
|
response_dict = {"jsonrpc": "2.0", "id": request_id}
|
|
209
221
|
|
|
210
222
|
if method in self.mock_responses:
|
|
@@ -244,6 +256,19 @@ class RequestMocker:
|
|
|
244
256
|
else:
|
|
245
257
|
raise Exception("Invariant: unreachable code path")
|
|
246
258
|
|
|
259
|
+
return mocked_result
|
|
260
|
+
|
|
261
|
+
async def _async_mock_request_handler(
|
|
262
|
+
self, method: "RPCEndpoint", params: Any
|
|
263
|
+
) -> "RPCResponse":
|
|
264
|
+
self.w3 = cast("AsyncWeb3", self.w3)
|
|
265
|
+
self._make_request = cast("AsyncMakeRequestFn", self._make_request)
|
|
266
|
+
if all(
|
|
267
|
+
method not in mock_dict
|
|
268
|
+
for mock_dict in (self.mock_errors, self.mock_results, self.mock_responses)
|
|
269
|
+
):
|
|
270
|
+
return await self._make_request(method, params)
|
|
271
|
+
mocked_result = await self._async_build_mock_result(method, params)
|
|
247
272
|
decorator = getattr(self._make_request, "_decorator", None)
|
|
248
273
|
if decorator is not None:
|
|
249
274
|
# If the original make_request was decorated, we need to re-apply
|
|
@@ -259,6 +284,47 @@ class RequestMocker:
|
|
|
259
284
|
else:
|
|
260
285
|
return mocked_result
|
|
261
286
|
|
|
287
|
+
async def _async_mock_send_handler(
|
|
288
|
+
self, method: "RPCEndpoint", params: Any
|
|
289
|
+
) -> "RPCRequest":
|
|
290
|
+
if all(
|
|
291
|
+
method not in mock_dict
|
|
292
|
+
for mock_dict in (self.mock_errors, self.mock_results, self.mock_responses)
|
|
293
|
+
):
|
|
294
|
+
return await self._send_request(method, params)
|
|
295
|
+
else:
|
|
296
|
+
request_id = self._build_request_id()
|
|
297
|
+
return {"id": request_id, "method": method, "params": params}
|
|
298
|
+
|
|
299
|
+
async def _async_mock_recv_handler(
|
|
300
|
+
self, rpc_request: "RPCRequest"
|
|
301
|
+
) -> "RPCResponse":
|
|
302
|
+
self.w3 = cast("AsyncWeb3", self.w3)
|
|
303
|
+
method = rpc_request["method"]
|
|
304
|
+
request_id = rpc_request["id"]
|
|
305
|
+
if all(
|
|
306
|
+
method not in mock_dict
|
|
307
|
+
for mock_dict in (self.mock_errors, self.mock_results, self.mock_responses)
|
|
308
|
+
):
|
|
309
|
+
return await self._recv_for_request(request_id)
|
|
310
|
+
mocked_result = await self._async_build_mock_result(
|
|
311
|
+
method, rpc_request["params"], request_id=int(request_id)
|
|
312
|
+
)
|
|
313
|
+
decorator = getattr(self._recv_for_request, "_decorator", None)
|
|
314
|
+
if decorator is not None:
|
|
315
|
+
# If the original recv_for_request was decorated, we need to re-apply
|
|
316
|
+
# the decorator to the mocked recv_for_request. This is necessary for
|
|
317
|
+
# the request caching decorator to work properly.
|
|
318
|
+
|
|
319
|
+
async def _coro(
|
|
320
|
+
_provider: Any, _rpc_request: "RPCRequest"
|
|
321
|
+
) -> "RPCResponse":
|
|
322
|
+
return mocked_result
|
|
323
|
+
|
|
324
|
+
return await decorator(_coro)(self.w3.provider, rpc_request)
|
|
325
|
+
else:
|
|
326
|
+
return mocked_result
|
|
327
|
+
|
|
262
328
|
@staticmethod
|
|
263
329
|
def _create_error_object(error: Dict[str, Any]) -> Dict[str, Any]:
|
|
264
330
|
code = error.get("code", -32000)
|
web3/beacon/api_endpoints.py
CHANGED
|
@@ -59,6 +59,16 @@ GET_BEACON_HEADS = "/eth/v1/debug/beacon/heads"
|
|
|
59
59
|
GET_NODE_IDENTITY = "/eth/v1/node/identity"
|
|
60
60
|
GET_PEERS = "/eth/v1/node/peers"
|
|
61
61
|
GET_PEER = "/eth/v1/node/peers/{0}"
|
|
62
|
+
GET_PEER_COUNT = "/eth/v1/node/peer_count"
|
|
62
63
|
GET_HEALTH = "/eth/v1/node/health"
|
|
63
64
|
GET_VERSION = "/eth/v1/node/version"
|
|
64
65
|
GET_SYNCING = "/eth/v1/node/syncing"
|
|
66
|
+
|
|
67
|
+
# [ VALIDATOR endpoints ]
|
|
68
|
+
|
|
69
|
+
GET_ATTESTER_DUTIES = "/eth/v1/validator/duties/attester/{0}"
|
|
70
|
+
GET_BLOCK_PROPOSERS_DUTIES = "/eth/v1/validator/duties/proposer/{0}"
|
|
71
|
+
GET_SYNC_COMMITTEE_DUTIES = "/eth/v1/validator/duties/sync/{0}"
|
|
72
|
+
|
|
73
|
+
# [ REWARDS endpoints ]
|
|
74
|
+
GET_ATTESTATIONS_REWARDS = "/eth/v1/beacon/rewards/attestations/{0}"
|
web3/beacon/async_beacon.py
CHANGED
|
@@ -3,6 +3,7 @@ from typing import (
|
|
|
3
3
|
Dict,
|
|
4
4
|
List,
|
|
5
5
|
Optional,
|
|
6
|
+
Union,
|
|
6
7
|
)
|
|
7
8
|
|
|
8
9
|
from aiohttp import (
|
|
@@ -18,6 +19,8 @@ from web3._utils.http_session_manager import (
|
|
|
18
19
|
)
|
|
19
20
|
from web3.beacon.api_endpoints import (
|
|
20
21
|
GET_ATTESTATIONS,
|
|
22
|
+
GET_ATTESTATIONS_REWARDS,
|
|
23
|
+
GET_ATTESTER_DUTIES,
|
|
21
24
|
GET_ATTESTER_SLASHINGS,
|
|
22
25
|
GET_BEACON_HEADS,
|
|
23
26
|
GET_BEACON_STATE,
|
|
@@ -27,6 +30,7 @@ from web3.beacon.api_endpoints import (
|
|
|
27
30
|
GET_BLOCK_ATTESTATIONS,
|
|
28
31
|
GET_BLOCK_HEADER,
|
|
29
32
|
GET_BLOCK_HEADERS,
|
|
33
|
+
GET_BLOCK_PROPOSERS_DUTIES,
|
|
30
34
|
GET_BLOCK_ROOT,
|
|
31
35
|
GET_BLS_TO_EXECUTION_CHANGES,
|
|
32
36
|
GET_DEPOSIT_CONTRACT,
|
|
@@ -45,10 +49,12 @@ from web3.beacon.api_endpoints import (
|
|
|
45
49
|
GET_LIGHT_CLIENT_UPDATES,
|
|
46
50
|
GET_NODE_IDENTITY,
|
|
47
51
|
GET_PEER,
|
|
52
|
+
GET_PEER_COUNT,
|
|
48
53
|
GET_PEERS,
|
|
49
54
|
GET_PROPOSER_SLASHINGS,
|
|
50
55
|
GET_REWARDS,
|
|
51
56
|
GET_SPEC,
|
|
57
|
+
GET_SYNC_COMMITTEE_DUTIES,
|
|
52
58
|
GET_SYNCING,
|
|
53
59
|
GET_VALIDATOR,
|
|
54
60
|
GET_VALIDATOR_BALANCES,
|
|
@@ -78,6 +84,14 @@ class AsyncBeacon:
|
|
|
78
84
|
uri, params=params, timeout=ClientTimeout(self.request_timeout)
|
|
79
85
|
)
|
|
80
86
|
|
|
87
|
+
async def _async_make_post_request(
|
|
88
|
+
self, endpoint_uri: str, body: Union[List[str], Dict[str, Any]]
|
|
89
|
+
) -> Dict[str, Any]:
|
|
90
|
+
uri = URI(self.base_url + endpoint_uri)
|
|
91
|
+
return await self._request_session_manager.async_json_make_post_request(
|
|
92
|
+
uri, json=body, timeout=self.request_timeout
|
|
93
|
+
)
|
|
94
|
+
|
|
81
95
|
# [ BEACON endpoints ]
|
|
82
96
|
|
|
83
97
|
# states
|
|
@@ -216,6 +230,9 @@ class AsyncBeacon:
|
|
|
216
230
|
async def get_peer(self, peer_id: str) -> Dict[str, Any]:
|
|
217
231
|
return await self._async_make_get_request(GET_PEER.format(peer_id))
|
|
218
232
|
|
|
233
|
+
async def get_peer_count(self) -> Dict[str, Any]:
|
|
234
|
+
return await self._async_make_get_request(GET_PEER_COUNT)
|
|
235
|
+
|
|
219
236
|
async def get_health(self) -> int:
|
|
220
237
|
url = URI(self.base_url + GET_HEALTH)
|
|
221
238
|
response = (
|
|
@@ -239,3 +256,33 @@ class AsyncBeacon:
|
|
|
239
256
|
GET_BLOB_SIDECARS.format(block_id),
|
|
240
257
|
params=indices_param,
|
|
241
258
|
)
|
|
259
|
+
|
|
260
|
+
# [ VALIDATOR endpoints ]
|
|
261
|
+
|
|
262
|
+
async def get_attester_duties(
|
|
263
|
+
self, epoch: str, validator_indices: List[str]
|
|
264
|
+
) -> Dict[str, Any]:
|
|
265
|
+
return await self._async_make_post_request(
|
|
266
|
+
GET_ATTESTER_DUTIES.format(epoch), validator_indices
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
async def get_block_proposer_duties(self, epoch: str) -> Dict[str, Any]:
|
|
270
|
+
return await self._async_make_get_request(
|
|
271
|
+
GET_BLOCK_PROPOSERS_DUTIES.format(epoch)
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
async def get_sync_committee_duties(
|
|
275
|
+
self, epoch: str, validator_indices: List[str]
|
|
276
|
+
) -> Dict[str, Any]:
|
|
277
|
+
return await self._async_make_post_request(
|
|
278
|
+
GET_SYNC_COMMITTEE_DUTIES.format(epoch), validator_indices
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
# [ REWARDS endpoints ]
|
|
282
|
+
|
|
283
|
+
async def get_attestations_rewards(
|
|
284
|
+
self, epoch: str, validator_indices: List[str]
|
|
285
|
+
) -> Dict[str, Any]:
|
|
286
|
+
return await self._async_make_post_request(
|
|
287
|
+
GET_ATTESTATIONS_REWARDS.format(epoch), validator_indices
|
|
288
|
+
)
|
web3/beacon/beacon.py
CHANGED
|
@@ -3,6 +3,7 @@ from typing import (
|
|
|
3
3
|
Dict,
|
|
4
4
|
List,
|
|
5
5
|
Optional,
|
|
6
|
+
Union,
|
|
6
7
|
)
|
|
7
8
|
|
|
8
9
|
from eth_typing import (
|
|
@@ -15,6 +16,8 @@ from web3._utils.http_session_manager import (
|
|
|
15
16
|
)
|
|
16
17
|
from web3.beacon.api_endpoints import (
|
|
17
18
|
GET_ATTESTATIONS,
|
|
19
|
+
GET_ATTESTATIONS_REWARDS,
|
|
20
|
+
GET_ATTESTER_DUTIES,
|
|
18
21
|
GET_ATTESTER_SLASHINGS,
|
|
19
22
|
GET_BEACON_HEADS,
|
|
20
23
|
GET_BEACON_STATE,
|
|
@@ -24,6 +27,7 @@ from web3.beacon.api_endpoints import (
|
|
|
24
27
|
GET_BLOCK_ATTESTATIONS,
|
|
25
28
|
GET_BLOCK_HEADER,
|
|
26
29
|
GET_BLOCK_HEADERS,
|
|
30
|
+
GET_BLOCK_PROPOSERS_DUTIES,
|
|
27
31
|
GET_BLOCK_ROOT,
|
|
28
32
|
GET_BLS_TO_EXECUTION_CHANGES,
|
|
29
33
|
GET_DEPOSIT_CONTRACT,
|
|
@@ -42,10 +46,12 @@ from web3.beacon.api_endpoints import (
|
|
|
42
46
|
GET_LIGHT_CLIENT_UPDATES,
|
|
43
47
|
GET_NODE_IDENTITY,
|
|
44
48
|
GET_PEER,
|
|
49
|
+
GET_PEER_COUNT,
|
|
45
50
|
GET_PEERS,
|
|
46
51
|
GET_PROPOSER_SLASHINGS,
|
|
47
52
|
GET_REWARDS,
|
|
48
53
|
GET_SPEC,
|
|
54
|
+
GET_SYNC_COMMITTEE_DUTIES,
|
|
49
55
|
GET_SYNCING,
|
|
50
56
|
GET_VALIDATOR,
|
|
51
57
|
GET_VALIDATOR_BALANCES,
|
|
@@ -73,6 +79,14 @@ class Beacon:
|
|
|
73
79
|
uri, params=params, timeout=self.request_timeout
|
|
74
80
|
)
|
|
75
81
|
|
|
82
|
+
def _make_post_request(
|
|
83
|
+
self, endpoint_url: str, body: Union[List[str], Dict[str, Any]]
|
|
84
|
+
) -> Dict[str, Any]:
|
|
85
|
+
uri = URI(self.base_url + endpoint_url)
|
|
86
|
+
return self._request_session_manager.json_make_post_request(
|
|
87
|
+
uri, json=body, timeout=self.request_timeout
|
|
88
|
+
)
|
|
89
|
+
|
|
76
90
|
# [ BEACON endpoints ]
|
|
77
91
|
|
|
78
92
|
# states
|
|
@@ -201,6 +215,9 @@ class Beacon:
|
|
|
201
215
|
def get_peer(self, peer_id: str) -> Dict[str, Any]:
|
|
202
216
|
return self._make_get_request(GET_PEER.format(peer_id))
|
|
203
217
|
|
|
218
|
+
def get_peer_count(self) -> Dict[str, Any]:
|
|
219
|
+
return self._make_get_request(GET_PEER_COUNT)
|
|
220
|
+
|
|
204
221
|
def get_health(self) -> int:
|
|
205
222
|
url = URI(self.base_url + GET_HEALTH)
|
|
206
223
|
response = self._request_session_manager.get_response_from_get_request(url)
|
|
@@ -222,3 +239,31 @@ class Beacon:
|
|
|
222
239
|
GET_BLOB_SIDECARS.format(block_id),
|
|
223
240
|
params=indices_param,
|
|
224
241
|
)
|
|
242
|
+
|
|
243
|
+
# [ VALIDATOR endpoints ]
|
|
244
|
+
|
|
245
|
+
def get_attester_duties(
|
|
246
|
+
self, epoch: str, validator_indices: List[str]
|
|
247
|
+
) -> Dict[str, Any]:
|
|
248
|
+
return self._make_post_request(
|
|
249
|
+
GET_ATTESTER_DUTIES.format(epoch), validator_indices
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
def get_block_proposer_duties(self, epoch: str) -> Dict[str, Any]:
|
|
253
|
+
return self._make_get_request(GET_BLOCK_PROPOSERS_DUTIES.format(epoch))
|
|
254
|
+
|
|
255
|
+
def get_sync_committee_duties(
|
|
256
|
+
self, epoch: str, validator_indices: List[str]
|
|
257
|
+
) -> Dict[str, Any]:
|
|
258
|
+
return self._make_post_request(
|
|
259
|
+
GET_SYNC_COMMITTEE_DUTIES.format(epoch), validator_indices
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
# [ REWARDS endpoints ]
|
|
263
|
+
|
|
264
|
+
def get_attestations_rewards(
|
|
265
|
+
self, epoch: str, validator_indices: List[str]
|
|
266
|
+
) -> Dict[str, Any]:
|
|
267
|
+
return self._make_post_request(
|
|
268
|
+
GET_ATTESTATIONS_REWARDS.format(epoch), validator_indices
|
|
269
|
+
)
|
web3/contract/async_contract.py
CHANGED
|
@@ -14,7 +14,6 @@ from typing import (
|
|
|
14
14
|
|
|
15
15
|
from eth_typing import (
|
|
16
16
|
ABI,
|
|
17
|
-
ABIFunction,
|
|
18
17
|
ChecksumAddress,
|
|
19
18
|
)
|
|
20
19
|
from eth_utils import (
|
|
@@ -22,7 +21,6 @@ from eth_utils import (
|
|
|
22
21
|
)
|
|
23
22
|
from eth_utils.abi import (
|
|
24
23
|
abi_to_signature,
|
|
25
|
-
filter_abi_by_type,
|
|
26
24
|
get_abi_input_names,
|
|
27
25
|
)
|
|
28
26
|
from eth_utils.toolz import (
|
|
@@ -34,7 +32,6 @@ from hexbytes import (
|
|
|
34
32
|
|
|
35
33
|
from web3._utils.abi import (
|
|
36
34
|
fallback_func_abi_exists,
|
|
37
|
-
get_name_from_abi_element_identifier,
|
|
38
35
|
receive_func_abi_exists,
|
|
39
36
|
)
|
|
40
37
|
from web3._utils.abi_element_identifiers import (
|
|
@@ -49,8 +46,6 @@ from web3._utils.compat import (
|
|
|
49
46
|
)
|
|
50
47
|
from web3._utils.contracts import (
|
|
51
48
|
async_parse_block_identifier,
|
|
52
|
-
copy_contract_event,
|
|
53
|
-
copy_contract_function,
|
|
54
49
|
)
|
|
55
50
|
from web3._utils.datatypes import (
|
|
56
51
|
PropertyCheckingFactory,
|
|
@@ -89,12 +84,6 @@ from web3.contract.utils import (
|
|
|
89
84
|
get_function_by_identifier,
|
|
90
85
|
)
|
|
91
86
|
from web3.exceptions import (
|
|
92
|
-
ABIEventNotFound,
|
|
93
|
-
ABIFunctionNotFound,
|
|
94
|
-
MismatchedABI,
|
|
95
|
-
NoABIEventsFound,
|
|
96
|
-
NoABIFound,
|
|
97
|
-
NoABIFunctionsFound,
|
|
98
87
|
Web3AttributeError,
|
|
99
88
|
Web3TypeError,
|
|
100
89
|
Web3ValidationError,
|
|
@@ -106,12 +95,6 @@ from web3.types import (
|
|
|
106
95
|
StateOverride,
|
|
107
96
|
TxParams,
|
|
108
97
|
)
|
|
109
|
-
from web3.utils.abi import (
|
|
110
|
-
_filter_by_argument_count,
|
|
111
|
-
_get_any_abi_signature_with_name,
|
|
112
|
-
_mismatched_abi_error_diagnosis,
|
|
113
|
-
get_abi_element,
|
|
114
|
-
)
|
|
115
98
|
|
|
116
99
|
if TYPE_CHECKING:
|
|
117
100
|
from ens import AsyncENS # noqa: F401
|
|
@@ -122,9 +105,6 @@ class AsyncContractEvent(BaseContractEvent):
|
|
|
122
105
|
# mypy types
|
|
123
106
|
w3: "AsyncWeb3"
|
|
124
107
|
|
|
125
|
-
def __call__(self, *args: Any, **kwargs: Any) -> "AsyncContractEvent":
|
|
126
|
-
return copy_contract_event(self, *args, **kwargs)
|
|
127
|
-
|
|
128
108
|
@combomethod
|
|
129
109
|
async def get_logs(
|
|
130
110
|
self,
|
|
@@ -255,162 +235,18 @@ class AsyncContractEvent(BaseContractEvent):
|
|
|
255
235
|
builder.address = self.address
|
|
256
236
|
return builder
|
|
257
237
|
|
|
258
|
-
@classmethod
|
|
259
|
-
def factory(cls, class_name: str, **kwargs: Any) -> Self:
|
|
260
|
-
return PropertyCheckingFactory(class_name, (cls,), kwargs)()
|
|
261
238
|
|
|
262
|
-
|
|
263
|
-
class AsyncContractEvents(BaseContractEvents):
|
|
239
|
+
class AsyncContractEvents(BaseContractEvents[AsyncContractEvent]):
|
|
264
240
|
def __init__(
|
|
265
241
|
self, abi: ABI, w3: "AsyncWeb3", address: Optional[ChecksumAddress] = None
|
|
266
242
|
) -> None:
|
|
267
243
|
super().__init__(abi, w3, AsyncContractEvent, address)
|
|
268
244
|
|
|
269
|
-
def __iter__(self) -> Iterable["AsyncContractEvent"]:
|
|
270
|
-
if not hasattr(self, "_events") or not self._events:
|
|
271
|
-
return
|
|
272
|
-
|
|
273
|
-
for event in self._events:
|
|
274
|
-
yield self[abi_to_signature(event)]
|
|
275
|
-
|
|
276
|
-
def __getattr__(self, event_name: str) -> "AsyncContractEvent":
|
|
277
|
-
if super().__getattribute__("abi") is None:
|
|
278
|
-
raise NoABIFound(
|
|
279
|
-
"There is no ABI found for this contract.",
|
|
280
|
-
)
|
|
281
|
-
elif "_events" not in self.__dict__ or len(self._events) == 0:
|
|
282
|
-
raise NoABIEventsFound(
|
|
283
|
-
"The abi for this contract contains no event definitions. ",
|
|
284
|
-
"Are you sure you provided the correct contract abi?",
|
|
285
|
-
)
|
|
286
|
-
elif get_name_from_abi_element_identifier(event_name) not in [
|
|
287
|
-
get_name_from_abi_element_identifier(event["name"])
|
|
288
|
-
for event in self._events
|
|
289
|
-
]:
|
|
290
|
-
raise ABIEventNotFound(
|
|
291
|
-
f"The event '{event_name}' was not found in this contract's abi. ",
|
|
292
|
-
"Are you sure you provided the correct contract abi?",
|
|
293
|
-
)
|
|
294
|
-
|
|
295
|
-
if "(" not in event_name:
|
|
296
|
-
event_name = _get_any_abi_signature_with_name(event_name, self._events)
|
|
297
|
-
else:
|
|
298
|
-
event_name = f"_{event_name}"
|
|
299
|
-
|
|
300
|
-
return super().__getattribute__(event_name)
|
|
301
|
-
|
|
302
|
-
def __getitem__(self, event_name: str) -> "AsyncContractEvent":
|
|
303
|
-
return getattr(self, event_name)
|
|
304
|
-
|
|
305
245
|
|
|
306
246
|
class AsyncContractFunction(BaseContractFunction):
|
|
307
247
|
# mypy types
|
|
308
248
|
w3: "AsyncWeb3"
|
|
309
249
|
|
|
310
|
-
def __call__(self, *args: Any, **kwargs: Any) -> "AsyncContractFunction":
|
|
311
|
-
# When a function is called, check arguments to obtain the correct function
|
|
312
|
-
# in the contract. self will be used if all args and kwargs are
|
|
313
|
-
# encodable to self.abi, otherwise the correct function is obtained from
|
|
314
|
-
# the contract.
|
|
315
|
-
if (
|
|
316
|
-
self.abi_element_identifier in [FallbackFn, ReceiveFn]
|
|
317
|
-
or self.abi_element_identifier == "constructor"
|
|
318
|
-
):
|
|
319
|
-
return copy_contract_function(self, *args, **kwargs)
|
|
320
|
-
|
|
321
|
-
all_functions = cast(
|
|
322
|
-
List[ABIFunction],
|
|
323
|
-
filter_abi_by_type(
|
|
324
|
-
"function",
|
|
325
|
-
self.contract_abi,
|
|
326
|
-
),
|
|
327
|
-
)
|
|
328
|
-
# Filter functions by name to obtain function signatures
|
|
329
|
-
function_name = get_name_from_abi_element_identifier(
|
|
330
|
-
self.abi_element_identifier
|
|
331
|
-
)
|
|
332
|
-
function_abis = [
|
|
333
|
-
function for function in all_functions if function["name"] == function_name
|
|
334
|
-
]
|
|
335
|
-
num_args = len(args) + len(kwargs)
|
|
336
|
-
function_abis_with_arg_count = cast(
|
|
337
|
-
List[ABIFunction],
|
|
338
|
-
_filter_by_argument_count(
|
|
339
|
-
num_args,
|
|
340
|
-
function_abis,
|
|
341
|
-
),
|
|
342
|
-
)
|
|
343
|
-
|
|
344
|
-
if not len(function_abis_with_arg_count):
|
|
345
|
-
# Build an ABI without arguments to determine if one exists
|
|
346
|
-
function_abis_with_arg_count = [
|
|
347
|
-
ABIFunction({"type": "function", "name": function_name})
|
|
348
|
-
]
|
|
349
|
-
|
|
350
|
-
# Check that arguments in call match a function ABI
|
|
351
|
-
num_attempts = 0
|
|
352
|
-
function_abi_matches = []
|
|
353
|
-
contract_function = None
|
|
354
|
-
for abi in function_abis_with_arg_count:
|
|
355
|
-
try:
|
|
356
|
-
num_attempts += 1
|
|
357
|
-
|
|
358
|
-
# Search for a function ABI that matches the arguments used
|
|
359
|
-
function_abi_matches.append(
|
|
360
|
-
cast(
|
|
361
|
-
ABIFunction,
|
|
362
|
-
get_abi_element(
|
|
363
|
-
function_abis,
|
|
364
|
-
abi_to_signature(abi),
|
|
365
|
-
*args,
|
|
366
|
-
abi_codec=self.w3.codec,
|
|
367
|
-
**kwargs,
|
|
368
|
-
),
|
|
369
|
-
)
|
|
370
|
-
)
|
|
371
|
-
except MismatchedABI:
|
|
372
|
-
# ignore exceptions
|
|
373
|
-
continue
|
|
374
|
-
|
|
375
|
-
if len(function_abi_matches) == 1:
|
|
376
|
-
function_abi = function_abi_matches[0]
|
|
377
|
-
if abi_to_signature(self.abi) == abi_to_signature(function_abi):
|
|
378
|
-
contract_function = self
|
|
379
|
-
else:
|
|
380
|
-
# Found a match that is not self
|
|
381
|
-
contract_function = AsyncContractFunction.factory(
|
|
382
|
-
abi_to_signature(function_abi),
|
|
383
|
-
w3=self.w3,
|
|
384
|
-
contract_abi=self.contract_abi,
|
|
385
|
-
address=self.address,
|
|
386
|
-
abi_element_identifier=abi_to_signature(function_abi),
|
|
387
|
-
abi=function_abi,
|
|
388
|
-
)
|
|
389
|
-
else:
|
|
390
|
-
for abi in function_abi_matches:
|
|
391
|
-
if abi_to_signature(self.abi) == abi_to_signature(abi):
|
|
392
|
-
contract_function = self
|
|
393
|
-
break
|
|
394
|
-
else:
|
|
395
|
-
# Raise exception if multiple found
|
|
396
|
-
raise MismatchedABI(
|
|
397
|
-
_mismatched_abi_error_diagnosis(
|
|
398
|
-
function_name,
|
|
399
|
-
self.contract_abi,
|
|
400
|
-
len(function_abi_matches),
|
|
401
|
-
num_args,
|
|
402
|
-
*args,
|
|
403
|
-
abi_codec=self.w3.codec,
|
|
404
|
-
**kwargs,
|
|
405
|
-
)
|
|
406
|
-
)
|
|
407
|
-
|
|
408
|
-
return copy_contract_function(contract_function, *args, **kwargs)
|
|
409
|
-
|
|
410
|
-
@classmethod
|
|
411
|
-
def factory(cls, class_name: str, **kwargs: Any) -> Self:
|
|
412
|
-
return PropertyCheckingFactory(class_name, (cls,), kwargs)()
|
|
413
|
-
|
|
414
250
|
async def call(
|
|
415
251
|
self,
|
|
416
252
|
transaction: Optional[TxParams] = None,
|
|
@@ -551,7 +387,7 @@ class AsyncContractFunction(BaseContractFunction):
|
|
|
551
387
|
return cast(AsyncContractFunction, NonExistentReceiveFunction())
|
|
552
388
|
|
|
553
389
|
|
|
554
|
-
class AsyncContractFunctions(BaseContractFunctions):
|
|
390
|
+
class AsyncContractFunctions(BaseContractFunctions[AsyncContractFunction]):
|
|
555
391
|
def __init__(
|
|
556
392
|
self,
|
|
557
393
|
abi: ABI,
|
|
@@ -561,46 +397,6 @@ class AsyncContractFunctions(BaseContractFunctions):
|
|
|
561
397
|
) -> None:
|
|
562
398
|
super().__init__(abi, w3, AsyncContractFunction, address, decode_tuples)
|
|
563
399
|
|
|
564
|
-
def __iter__(self) -> Iterable["AsyncContractFunction"]:
|
|
565
|
-
if not hasattr(self, "_functions") or not self._functions:
|
|
566
|
-
return
|
|
567
|
-
|
|
568
|
-
for func in self._functions:
|
|
569
|
-
yield self[abi_to_signature(func)]
|
|
570
|
-
|
|
571
|
-
def __getattr__(self, function_name: str) -> "AsyncContractFunction":
|
|
572
|
-
if super().__getattribute__("abi") is None:
|
|
573
|
-
raise NoABIFound(
|
|
574
|
-
"There is no ABI found for this contract.",
|
|
575
|
-
)
|
|
576
|
-
elif "_functions" not in self.__dict__ or len(self._functions) == 0:
|
|
577
|
-
raise NoABIFunctionsFound(
|
|
578
|
-
"The abi for this contract contains no function definitions. ",
|
|
579
|
-
"Are you sure you provided the correct contract abi?",
|
|
580
|
-
)
|
|
581
|
-
elif get_name_from_abi_element_identifier(function_name) not in [
|
|
582
|
-
get_name_from_abi_element_identifier(function["name"])
|
|
583
|
-
for function in self._functions
|
|
584
|
-
]:
|
|
585
|
-
raise ABIFunctionNotFound(
|
|
586
|
-
f"The function '{function_name}' was not found in this ",
|
|
587
|
-
"contract's abi.",
|
|
588
|
-
)
|
|
589
|
-
|
|
590
|
-
if "(" not in function_name:
|
|
591
|
-
function_name = _get_any_abi_signature_with_name(
|
|
592
|
-
function_name, self._functions
|
|
593
|
-
)
|
|
594
|
-
else:
|
|
595
|
-
function_name = f"_{function_name}"
|
|
596
|
-
|
|
597
|
-
return super().__getattribute__(
|
|
598
|
-
function_name,
|
|
599
|
-
)
|
|
600
|
-
|
|
601
|
-
def __getitem__(self, function_name: str) -> "AsyncContractFunction":
|
|
602
|
-
return getattr(self, function_name)
|
|
603
|
-
|
|
604
400
|
|
|
605
401
|
class AsyncContract(BaseContract):
|
|
606
402
|
functions: AsyncContractFunctions = None
|