web3 7.7.0__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/events.py +1 -1
- web3/_utils/http_session_manager.py +19 -1
- web3/_utils/module_testing/eth_module.py +3 -0
- web3/_utils/module_testing/module_testing_utils.py +0 -42
- web3/_utils/module_testing/persistent_connection_provider.py +38 -0
- 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 +208 -12
- web3/contract/contract.py +2 -205
- web3/datastructures.py +4 -0
- web3/manager.py +62 -18
- web3/middleware/base.py +14 -6
- web3/providers/async_base.py +5 -4
- web3/providers/base.py +3 -3
- web3/providers/persistent/request_processor.py +11 -1
- web3/providers/persistent/subscription_manager.py +110 -45
- web3/providers/rpc/async_rpc.py +8 -3
- web3/providers/rpc/rpc.py +8 -3
- web3/types.py +10 -11
- web3/utils/subscriptions.py +5 -1
- {web3-7.7.0.dist-info → web3-7.8.0.dist-info}/LICENSE +1 -1
- {web3-7.7.0.dist-info → web3-7.8.0.dist-info}/METADATA +1 -1
- {web3-7.7.0.dist-info → web3-7.8.0.dist-info}/RECORD +29 -29
- {web3-7.7.0.dist-info → web3-7.8.0.dist-info}/WHEEL +0 -0
- {web3-7.7.0.dist-info → web3-7.8.0.dist-info}/top_level.txt +0 -0
ens/async_ens.py
CHANGED
|
@@ -152,12 +152,12 @@ class AsyncENS(BaseENS):
|
|
|
152
152
|
:param int coin_type: if provided, look up the address for this coin type
|
|
153
153
|
:raises InvalidName: if `name` has invalid syntax
|
|
154
154
|
"""
|
|
155
|
-
r = await self.resolver(name)
|
|
156
155
|
if coin_type is None:
|
|
157
156
|
# don't validate `addr(bytes32)` interface id since extended resolvers
|
|
158
157
|
# can implement a "resolve" function as of ENSIP-10
|
|
159
158
|
return cast(ChecksumAddress, await self._resolve(name, "addr"))
|
|
160
159
|
else:
|
|
160
|
+
r = await self.resolver(name)
|
|
161
161
|
await _async_validate_resolver_and_interface_id(
|
|
162
162
|
name, r, ENS_MULTICHAIN_ADDRESS_INTERFACE_ID, "addr(bytes32,uint256)"
|
|
163
163
|
)
|
ens/ens.py
CHANGED
|
@@ -154,12 +154,12 @@ class ENS(BaseENS):
|
|
|
154
154
|
:raises UnsupportedFunction: if the resolver does not support the ``addr()``
|
|
155
155
|
function
|
|
156
156
|
"""
|
|
157
|
-
r = self.resolver(name)
|
|
158
157
|
if coin_type is None:
|
|
159
158
|
# don't validate `addr(bytes32)` interface id since extended resolvers
|
|
160
159
|
# can implement a "resolve" function as of ENSIP-10
|
|
161
160
|
return cast(ChecksumAddress, self._resolve(name, "addr"))
|
|
162
161
|
else:
|
|
162
|
+
r = self.resolver(name)
|
|
163
163
|
_validate_resolver_and_interface_id(
|
|
164
164
|
name, r, ENS_MULTICHAIN_ADDRESS_INTERFACE_ID, "addr(bytes32,uint256)"
|
|
165
165
|
)
|
web3/_utils/events.py
CHANGED
|
@@ -120,11 +120,19 @@ class HTTPSessionManager:
|
|
|
120
120
|
def get_response_from_post_request(
|
|
121
121
|
self, endpoint_uri: URI, *args: Any, **kwargs: Any
|
|
122
122
|
) -> requests.Response:
|
|
123
|
+
kwargs.setdefault("timeout", DEFAULT_HTTP_TIMEOUT)
|
|
123
124
|
session = self.cache_and_return_session(
|
|
124
125
|
endpoint_uri, request_timeout=kwargs["timeout"]
|
|
125
126
|
)
|
|
126
127
|
return session.post(endpoint_uri, *args, **kwargs)
|
|
127
128
|
|
|
129
|
+
def json_make_post_request(
|
|
130
|
+
self, endpoint_uri: URI, *args: Any, **kwargs: Any
|
|
131
|
+
) -> Dict[str, Any]:
|
|
132
|
+
response = self.get_response_from_post_request(endpoint_uri, *args, **kwargs)
|
|
133
|
+
response.raise_for_status()
|
|
134
|
+
return response.json()
|
|
135
|
+
|
|
128
136
|
def make_post_request(
|
|
129
137
|
self, endpoint_uri: URI, data: Union[bytes, Dict[str, Any]], **kwargs: Any
|
|
130
138
|
) -> bytes:
|
|
@@ -143,8 +151,9 @@ class HTTPSessionManager:
|
|
|
143
151
|
else:
|
|
144
152
|
return response.content
|
|
145
153
|
|
|
154
|
+
@staticmethod
|
|
146
155
|
def _handle_streaming_response(
|
|
147
|
-
|
|
156
|
+
response: requests.Response, start: float, timeout: float
|
|
148
157
|
) -> bytes:
|
|
149
158
|
response_body = b""
|
|
150
159
|
for data in response.iter_content():
|
|
@@ -289,6 +298,15 @@ class HTTPSessionManager:
|
|
|
289
298
|
response = await session.post(endpoint_uri, *args, **kwargs)
|
|
290
299
|
return response
|
|
291
300
|
|
|
301
|
+
async def async_json_make_post_request(
|
|
302
|
+
self, endpoint_uri: URI, *args: Any, **kwargs: Any
|
|
303
|
+
) -> Dict[str, Any]:
|
|
304
|
+
response = await self.async_get_response_from_post_request(
|
|
305
|
+
endpoint_uri, *args, **kwargs
|
|
306
|
+
)
|
|
307
|
+
response.raise_for_status()
|
|
308
|
+
return await response.json()
|
|
309
|
+
|
|
292
310
|
async def async_make_post_request(
|
|
293
311
|
self, endpoint_uri: URI, data: Union[bytes, Dict[str, Any]], **kwargs: Any
|
|
294
312
|
) -> bytes:
|
|
@@ -2388,6 +2388,7 @@ class AsyncEthModuleTest:
|
|
|
2388
2388
|
with pytest.raises(Web3ValueError):
|
|
2389
2389
|
await async_w3.eth.replace_transaction(txn_hash, txn_params)
|
|
2390
2390
|
|
|
2391
|
+
@flaky_geth_dev_mining
|
|
2391
2392
|
@pytest.mark.asyncio
|
|
2392
2393
|
async def test_async_eth_replace_transaction_gas_price_defaulting_minimum(
|
|
2393
2394
|
self, async_w3: "AsyncWeb3", async_keyfile_account_address: ChecksumAddress
|
|
@@ -2411,6 +2412,7 @@ class AsyncEthModuleTest:
|
|
|
2411
2412
|
gas_price * 1.125
|
|
2412
2413
|
) # minimum gas price
|
|
2413
2414
|
|
|
2415
|
+
@flaky_geth_dev_mining
|
|
2414
2416
|
@pytest.mark.asyncio
|
|
2415
2417
|
async def test_async_eth_replace_transaction_gas_price_defaulting_strategy_higher(
|
|
2416
2418
|
self, async_w3: "AsyncWeb3", async_keyfile_account_address: ChecksumAddress
|
|
@@ -2439,6 +2441,7 @@ class AsyncEthModuleTest:
|
|
|
2439
2441
|
) # Strategy provides higher gas price
|
|
2440
2442
|
async_w3.eth.set_gas_price_strategy(None) # reset strategy
|
|
2441
2443
|
|
|
2444
|
+
@flaky_geth_dev_mining
|
|
2442
2445
|
@pytest.mark.asyncio
|
|
2443
2446
|
async def test_async_eth_replace_transaction_gas_price_defaulting_strategy_lower(
|
|
2444
2447
|
self, async_w3: "AsyncWeb3", async_keyfile_account_address: ChecksumAddress
|
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
import functools
|
|
3
|
-
import pytest
|
|
4
2
|
from typing import (
|
|
5
3
|
TYPE_CHECKING,
|
|
6
4
|
Any,
|
|
7
|
-
Callable,
|
|
8
5
|
Collection,
|
|
9
6
|
Dict,
|
|
10
7
|
Generator,
|
|
11
8
|
Literal,
|
|
12
9
|
Sequence,
|
|
13
|
-
Tuple,
|
|
14
|
-
Type,
|
|
15
10
|
Union,
|
|
16
11
|
)
|
|
17
12
|
|
|
@@ -63,43 +58,6 @@ due to timing of the test running as a block is mined.
|
|
|
63
58
|
flaky_geth_dev_mining = flaky(max_runs=3, min_passes=1)
|
|
64
59
|
|
|
65
60
|
|
|
66
|
-
def flaky_with_xfail_on_exception(
|
|
67
|
-
reason: str,
|
|
68
|
-
exception: Union[Type[Exception], Tuple[Type[Exception], ...]],
|
|
69
|
-
max_runs: int = 3,
|
|
70
|
-
min_passes: int = 1,
|
|
71
|
-
) -> Callable[[Any], Any]:
|
|
72
|
-
"""
|
|
73
|
-
Some tests inconsistently fail hard with a particular exception and retrying
|
|
74
|
-
these tests often times does not get them "unstuck". If we've exhausted all flaky
|
|
75
|
-
retries and this expected exception is raised, `xfail` the test with the given
|
|
76
|
-
reason.
|
|
77
|
-
"""
|
|
78
|
-
runs = max_runs
|
|
79
|
-
|
|
80
|
-
def decorator(func: Any) -> Any:
|
|
81
|
-
@flaky(max_runs=max_runs, min_passes=min_passes)
|
|
82
|
-
@functools.wraps(func)
|
|
83
|
-
async def wrapper(self: Any, *args: Any, **kwargs: Any) -> Any:
|
|
84
|
-
nonlocal runs
|
|
85
|
-
try:
|
|
86
|
-
return await func(self, *args, **kwargs)
|
|
87
|
-
except exception:
|
|
88
|
-
# xfail the test only if the exception is raised and we have exhausted
|
|
89
|
-
# all flaky retries
|
|
90
|
-
if runs == 1:
|
|
91
|
-
pytest.xfail(reason)
|
|
92
|
-
runs -= 1
|
|
93
|
-
pytest.fail(f"xfailed but {runs} run(s) remaining with flaky...")
|
|
94
|
-
except Exception as e:
|
|
95
|
-
# let flaky handle it
|
|
96
|
-
raise e
|
|
97
|
-
|
|
98
|
-
return wrapper
|
|
99
|
-
|
|
100
|
-
return decorator
|
|
101
|
-
|
|
102
|
-
|
|
103
61
|
def assert_contains_log(
|
|
104
62
|
result: Sequence[LogReceipt],
|
|
105
63
|
block_with_txn_with_log: BlockData,
|
|
@@ -876,3 +876,41 @@ class PersistentConnectionProviderTest:
|
|
|
876
876
|
|
|
877
877
|
assert_no_subscriptions_left(sub_manager._subscription_container)
|
|
878
878
|
await clean_up_task(unsubscribe_task)
|
|
879
|
+
|
|
880
|
+
@pytest.mark.asyncio
|
|
881
|
+
async def test_run_forever_starts_with_0_subs_and_runs_until_task_cancelled(
|
|
882
|
+
self, async_w3: AsyncWeb3
|
|
883
|
+
) -> None:
|
|
884
|
+
sub_manager = async_w3.subscription_manager
|
|
885
|
+
assert_no_subscriptions_left(sub_manager._subscription_container)
|
|
886
|
+
|
|
887
|
+
run_forever_task = asyncio.create_task(
|
|
888
|
+
sub_manager.handle_subscriptions(run_forever=True)
|
|
889
|
+
)
|
|
890
|
+
|
|
891
|
+
await asyncio.sleep(0.1)
|
|
892
|
+
assert run_forever_task.done() is False
|
|
893
|
+
assert sub_manager.subscriptions == []
|
|
894
|
+
|
|
895
|
+
# subscribe to newHeads and validate it
|
|
896
|
+
new_heads_handler_test = SubscriptionHandlerTest()
|
|
897
|
+
sub1 = NewHeadsSubscription(
|
|
898
|
+
label="foo",
|
|
899
|
+
handler=new_heads_handler,
|
|
900
|
+
handler_context={"new_heads_handler_test": new_heads_handler_test},
|
|
901
|
+
)
|
|
902
|
+
sub_id = await sub_manager.subscribe(sub1)
|
|
903
|
+
assert is_hexstr(sub_id)
|
|
904
|
+
assert len(sub_manager.subscriptions) == 1
|
|
905
|
+
assert sub_manager.subscriptions[0] == sub1
|
|
906
|
+
|
|
907
|
+
# wait for the handler to unsubscribe
|
|
908
|
+
while sub_manager.subscriptions:
|
|
909
|
+
await asyncio.sleep(0.1)
|
|
910
|
+
|
|
911
|
+
assert new_heads_handler_test.passed
|
|
912
|
+
assert run_forever_task.done() is False
|
|
913
|
+
assert run_forever_task.cancelled() is False
|
|
914
|
+
|
|
915
|
+
# cleanup
|
|
916
|
+
await clean_up_task(run_forever_task)
|
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
|
+
)
|