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 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
@@ -325,7 +325,7 @@ normalize_topic_list = compose(
325
325
 
326
326
 
327
327
  def is_indexed(arg: Any) -> bool:
328
- if isinstance(arg, TopicArgumentFilter) is True:
328
+ if isinstance(arg, TopicArgumentFilter):
329
329
  return True
330
330
  return False
331
331
 
@@ -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
- self, response: requests.Response, start: float, timeout: float
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)
@@ -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}"
@@ -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
+ )