web3 7.0.0b2__py3-none-any.whl → 7.7.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.
Files changed (144) hide show
  1. ens/__init__.py +13 -2
  2. ens/_normalization.py +4 -4
  3. ens/async_ens.py +27 -15
  4. ens/base_ens.py +3 -1
  5. ens/contract_data.py +2 -2
  6. ens/ens.py +10 -7
  7. ens/exceptions.py +16 -29
  8. ens/specs/nf.json +1 -1
  9. ens/specs/normalization_spec.json +1 -1
  10. ens/utils.py +24 -32
  11. web3/__init__.py +23 -12
  12. web3/_utils/abi.py +157 -263
  13. web3/_utils/async_transactions.py +34 -20
  14. web3/_utils/batching.py +217 -0
  15. web3/_utils/blocks.py +6 -2
  16. web3/_utils/caching/__init__.py +12 -0
  17. web3/_utils/caching/caching_utils.py +433 -0
  18. web3/_utils/caching/request_caching_validation.py +287 -0
  19. web3/_utils/compat/__init__.py +2 -3
  20. web3/_utils/contract_sources/compile_contracts.py +1 -1
  21. web3/_utils/contract_sources/contract_data/ambiguous_function_contract.py +42 -0
  22. web3/_utils/contract_sources/contract_data/arrays_contract.py +3 -3
  23. web3/_utils/contract_sources/contract_data/bytes_contracts.py +5 -5
  24. web3/_utils/contract_sources/contract_data/constructor_contracts.py +7 -7
  25. web3/_utils/contract_sources/contract_data/contract_caller_tester.py +3 -3
  26. web3/_utils/contract_sources/contract_data/emitter_contract.py +3 -3
  27. web3/_utils/contract_sources/contract_data/event_contracts.py +50 -5
  28. web3/_utils/contract_sources/contract_data/extended_resolver.py +3 -3
  29. web3/_utils/contract_sources/contract_data/fallback_function_contract.py +3 -3
  30. web3/_utils/contract_sources/contract_data/function_name_tester_contract.py +3 -3
  31. web3/_utils/contract_sources/contract_data/math_contract.py +3 -3
  32. web3/_utils/contract_sources/contract_data/offchain_lookup.py +3 -3
  33. web3/_utils/contract_sources/contract_data/offchain_resolver.py +3 -3
  34. web3/_utils/contract_sources/contract_data/panic_errors_contract.py +3 -3
  35. web3/_utils/contract_sources/contract_data/payable_tester.py +3 -3
  36. web3/_utils/contract_sources/contract_data/receive_function_contracts.py +5 -5
  37. web3/_utils/contract_sources/contract_data/reflector_contracts.py +3 -3
  38. web3/_utils/contract_sources/contract_data/revert_contract.py +3 -3
  39. web3/_utils/contract_sources/contract_data/simple_resolver.py +3 -3
  40. web3/_utils/contract_sources/contract_data/storage_contract.py +3 -3
  41. web3/_utils/contract_sources/contract_data/string_contract.py +3 -3
  42. web3/_utils/contract_sources/contract_data/tuple_contracts.py +5 -5
  43. web3/_utils/contracts.py +172 -220
  44. web3/_utils/datatypes.py +5 -1
  45. web3/_utils/decorators.py +6 -1
  46. web3/_utils/empty.py +1 -1
  47. web3/_utils/encoding.py +16 -12
  48. web3/_utils/error_formatters_utils.py +5 -3
  49. web3/_utils/events.py +78 -72
  50. web3/_utils/fee_utils.py +1 -3
  51. web3/_utils/filters.py +24 -22
  52. web3/_utils/formatters.py +2 -2
  53. web3/_utils/http.py +8 -2
  54. web3/_utils/http_session_manager.py +314 -0
  55. web3/_utils/math.py +14 -15
  56. web3/_utils/method_formatters.py +161 -34
  57. web3/_utils/module.py +2 -1
  58. web3/_utils/module_testing/__init__.py +3 -2
  59. web3/_utils/module_testing/eth_module.py +736 -583
  60. web3/_utils/module_testing/go_ethereum_debug_module.py +128 -0
  61. web3/_utils/module_testing/module_testing_utils.py +81 -24
  62. web3/_utils/module_testing/persistent_connection_provider.py +702 -220
  63. web3/_utils/module_testing/utils.py +114 -33
  64. web3/_utils/module_testing/web3_module.py +438 -17
  65. web3/_utils/normalizers.py +13 -11
  66. web3/_utils/rpc_abi.py +10 -22
  67. web3/_utils/threads.py +8 -7
  68. web3/_utils/transactions.py +32 -25
  69. web3/_utils/type_conversion.py +5 -1
  70. web3/_utils/validation.py +20 -17
  71. web3/beacon/__init__.py +5 -0
  72. web3/beacon/api_endpoints.py +3 -0
  73. web3/beacon/async_beacon.py +29 -6
  74. web3/beacon/beacon.py +24 -6
  75. web3/contract/__init__.py +7 -0
  76. web3/contract/async_contract.py +285 -82
  77. web3/contract/base_contract.py +556 -258
  78. web3/contract/contract.py +295 -84
  79. web3/contract/utils.py +251 -55
  80. web3/datastructures.py +49 -34
  81. web3/eth/__init__.py +7 -0
  82. web3/eth/async_eth.py +89 -69
  83. web3/eth/base_eth.py +7 -3
  84. web3/eth/eth.py +43 -66
  85. web3/exceptions.py +158 -83
  86. web3/gas_strategies/time_based.py +8 -6
  87. web3/geth.py +53 -184
  88. web3/main.py +77 -17
  89. web3/manager.py +362 -95
  90. web3/method.py +43 -15
  91. web3/middleware/__init__.py +17 -0
  92. web3/middleware/attrdict.py +12 -22
  93. web3/middleware/base.py +55 -2
  94. web3/middleware/filter.py +45 -23
  95. web3/middleware/formatting.py +6 -3
  96. web3/middleware/names.py +4 -1
  97. web3/middleware/signing.py +15 -6
  98. web3/middleware/stalecheck.py +2 -1
  99. web3/module.py +61 -25
  100. web3/providers/__init__.py +21 -0
  101. web3/providers/async_base.py +87 -32
  102. web3/providers/base.py +77 -32
  103. web3/providers/eth_tester/__init__.py +5 -0
  104. web3/providers/eth_tester/defaults.py +2 -55
  105. web3/providers/eth_tester/main.py +41 -15
  106. web3/providers/eth_tester/middleware.py +16 -17
  107. web3/providers/ipc.py +41 -17
  108. web3/providers/legacy_websocket.py +26 -1
  109. web3/providers/persistent/__init__.py +7 -0
  110. web3/providers/persistent/async_ipc.py +61 -121
  111. web3/providers/persistent/persistent.py +323 -16
  112. web3/providers/persistent/persistent_connection.py +54 -5
  113. web3/providers/persistent/request_processor.py +136 -56
  114. web3/providers/persistent/subscription_container.py +56 -0
  115. web3/providers/persistent/subscription_manager.py +233 -0
  116. web3/providers/persistent/websocket.py +29 -92
  117. web3/providers/rpc/__init__.py +5 -0
  118. web3/providers/rpc/async_rpc.py +73 -18
  119. web3/providers/rpc/rpc.py +73 -30
  120. web3/providers/rpc/utils.py +1 -13
  121. web3/scripts/install_pre_releases.py +33 -0
  122. web3/scripts/parse_pygeth_version.py +16 -0
  123. web3/testing.py +4 -4
  124. web3/tracing.py +9 -5
  125. web3/types.py +141 -74
  126. web3/utils/__init__.py +64 -5
  127. web3/utils/abi.py +790 -10
  128. web3/utils/address.py +8 -0
  129. web3/utils/async_exception_handling.py +20 -11
  130. web3/utils/caching.py +34 -4
  131. web3/utils/exception_handling.py +9 -12
  132. web3/utils/subscriptions.py +285 -0
  133. {web3-7.0.0b2.dist-info → web3-7.7.0.dist-info}/LICENSE +1 -1
  134. web3-7.7.0.dist-info/METADATA +130 -0
  135. web3-7.7.0.dist-info/RECORD +171 -0
  136. {web3-7.0.0b2.dist-info → web3-7.7.0.dist-info}/WHEEL +1 -1
  137. web3/_utils/caching.py +0 -155
  138. web3/_utils/contract_sources/contract_data/address_reflector.py +0 -29
  139. web3/_utils/module_testing/go_ethereum_personal_module.py +0 -300
  140. web3/_utils/request.py +0 -265
  141. web3-7.0.0b2.dist-info/METADATA +0 -106
  142. web3-7.0.0b2.dist-info/RECORD +0 -163
  143. /web3/_utils/{function_identifiers.py → abi_element_identifiers.py} +0 -0
  144. {web3-7.0.0b2.dist-info → web3-7.7.0.dist-info}/top_level.txt +0 -0
web3/geth.py CHANGED
@@ -1,26 +1,17 @@
1
1
  from typing import (
2
- Any,
3
2
  Awaitable,
4
3
  Callable,
5
- Dict,
6
4
  List,
7
5
  Optional,
6
+ Protocol,
8
7
  Tuple,
8
+ Union,
9
9
  )
10
10
 
11
- from eth_typing.encoding import (
12
- HexStr,
13
- )
14
11
  from eth_typing.evm import (
15
12
  ChecksumAddress,
16
13
  )
17
- from hexbytes.main import (
18
- HexBytes,
19
- )
20
14
 
21
- from web3._utils.compat import (
22
- Protocol,
23
- )
24
15
  from web3._utils.rpc_abi import (
25
16
  RPC,
26
17
  )
@@ -32,14 +23,19 @@ from web3.module import (
32
23
  Module,
33
24
  )
34
25
  from web3.types import (
26
+ CallTrace,
27
+ DiffModeTrace,
35
28
  EnodeURI,
36
- GethWallet,
29
+ FourByteTrace,
37
30
  NodeInfo,
31
+ OpcodeTrace,
38
32
  Peer,
39
- TxParams,
33
+ PrestateTrace,
34
+ TraceConfig,
40
35
  TxPoolContent,
41
36
  TxPoolInspect,
42
37
  TxPoolStatus,
38
+ _Hash32,
43
39
  )
44
40
 
45
41
 
@@ -53,66 +49,6 @@ class UnlockAccountWrapper(Protocol):
53
49
  pass
54
50
 
55
51
 
56
- class GethPersonal(Module):
57
- """
58
- https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-personal
59
- """
60
-
61
- is_async = False
62
-
63
- ec_recover: Method[Callable[[str, HexStr], ChecksumAddress]] = Method(
64
- RPC.personal_ecRecover,
65
- mungers=[default_root_munger],
66
- )
67
-
68
- import_raw_key: Method[Callable[[str, str], ChecksumAddress]] = Method(
69
- RPC.personal_importRawKey,
70
- mungers=[default_root_munger],
71
- )
72
-
73
- list_accounts: Method[Callable[[], List[ChecksumAddress]]] = Method(
74
- RPC.personal_listAccounts,
75
- is_property=True,
76
- )
77
-
78
- list_wallets: Method[Callable[[], List[GethWallet]]] = Method(
79
- RPC.personal_listWallets,
80
- is_property=True,
81
- )
82
-
83
- send_transaction: Method[Callable[[TxParams, str], HexBytes]] = Method(
84
- RPC.personal_sendTransaction,
85
- mungers=[default_root_munger],
86
- )
87
-
88
- sign: Method[Callable[[str, ChecksumAddress, Optional[str]], HexStr]] = Method(
89
- RPC.personal_sign,
90
- mungers=[default_root_munger],
91
- )
92
-
93
- sign_typed_data: Method[
94
- Callable[[Dict[str, Any], ChecksumAddress, str], HexStr]
95
- ] = Method(
96
- RPC.personal_signTypedData,
97
- mungers=[default_root_munger],
98
- )
99
-
100
- new_account: Method[Callable[[str], ChecksumAddress]] = Method(
101
- RPC.personal_newAccount,
102
- mungers=[default_root_munger],
103
- )
104
-
105
- lock_account: Method[Callable[[ChecksumAddress], bool]] = Method(
106
- RPC.personal_lockAccount,
107
- mungers=[default_root_munger],
108
- )
109
-
110
- unlock_account: Method[UnlockAccountWrapper] = Method(
111
- RPC.personal_unlockAccount,
112
- mungers=[default_root_munger],
113
- )
114
-
115
-
116
52
  class GethTxPool(Module):
117
53
  """
118
54
  https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-txpool
@@ -205,10 +141,33 @@ class GethAdmin(Module):
205
141
  )
206
142
 
207
143
 
144
+ class GethDebug(Module):
145
+ """
146
+ https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-debug
147
+ """
148
+
149
+ def trace_transaction_munger(
150
+ self,
151
+ transaction_hash: _Hash32,
152
+ trace_config: Optional[TraceConfig] = None,
153
+ ) -> Tuple[_Hash32, TraceConfig]:
154
+ return (transaction_hash, trace_config)
155
+
156
+ trace_transaction: Method[
157
+ Callable[
158
+ ...,
159
+ Union[CallTrace, PrestateTrace, OpcodeTrace, DiffModeTrace, FourByteTrace],
160
+ ]
161
+ ] = Method(
162
+ RPC.debug_traceTransaction,
163
+ mungers=[trace_transaction_munger],
164
+ )
165
+
166
+
208
167
  class Geth(Module):
209
- personal: GethPersonal
210
168
  admin: GethAdmin
211
169
  txpool: GethTxPool
170
+ debug: GethDebug
212
171
 
213
172
 
214
173
  # --- async --- #
@@ -334,125 +293,35 @@ class AsyncGethAdmin(Module):
334
293
  return await self._stop_ws()
335
294
 
336
295
 
337
- class AsyncGethPersonal(Module):
296
+ class AsyncGethDebug(Module):
338
297
  """
339
- https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-personal
298
+ https://geth.ethereum.org/docs/interacting-with-geth/rpc/ns-debug
340
299
  """
341
300
 
342
301
  is_async = True
343
302
 
344
- # ec_recover
345
-
346
- _ec_recover: Method[Callable[[str, HexStr], Awaitable[ChecksumAddress]]] = Method(
347
- RPC.personal_ecRecover,
348
- mungers=[default_root_munger],
349
- )
350
-
351
- async def ec_recover(self, message: str, signature: HexStr) -> ChecksumAddress:
352
- return await self._ec_recover(message, signature)
353
-
354
- # import_raw_key
355
-
356
- _import_raw_key: Method[Callable[[str, str], Awaitable[ChecksumAddress]]] = Method(
357
- RPC.personal_importRawKey,
358
- mungers=[default_root_munger],
359
- )
360
-
361
- async def import_raw_key(
362
- self, private_key: str, passphrase: str
363
- ) -> ChecksumAddress:
364
- return await self._import_raw_key(private_key, passphrase)
365
-
366
- # list_accounts and list_wallets
367
-
368
- _list_accounts: Method[Callable[[], Awaitable[List[ChecksumAddress]]]] = Method(
369
- RPC.personal_listAccounts,
370
- is_property=True,
371
- )
372
-
373
- _list_wallets: Method[Callable[[], Awaitable[List[GethWallet]]]] = Method(
374
- RPC.personal_listWallets,
375
- is_property=True,
376
- )
377
-
378
- async def list_accounts(self) -> List[ChecksumAddress]:
379
- return await self._list_accounts()
380
-
381
- async def list_wallets(self) -> List[GethWallet]:
382
- return await self._list_wallets()
383
-
384
- # send_transaction
385
-
386
- _send_transaction: Method[Callable[[TxParams, str], Awaitable[HexBytes]]] = Method(
387
- RPC.personal_sendTransaction,
388
- mungers=[default_root_munger],
389
- )
390
-
391
- async def send_transaction(
392
- self, transaction: TxParams, passphrase: str
393
- ) -> HexBytes:
394
- return await self._send_transaction(transaction, passphrase)
395
-
396
- # sign and sign_typed_data
397
-
398
- _sign: Method[
399
- Callable[[str, ChecksumAddress, Optional[str]], Awaitable[HexStr]]
400
- ] = Method(
401
- RPC.personal_sign,
402
- mungers=[default_root_munger],
403
- )
404
-
405
- _sign_typed_data: Method[
406
- Callable[[Dict[str, Any], ChecksumAddress, str], Awaitable[HexStr]]
407
- ] = Method(
408
- RPC.personal_signTypedData,
409
- mungers=[default_root_munger],
410
- )
411
-
412
- async def sign(
413
- self, message: str, account: ChecksumAddress, passphrase: str
414
- ) -> HexStr:
415
- return await self._sign(message, account, passphrase)
416
-
417
- async def sign_typed_data(
418
- self, message: Dict[str, Any], account: ChecksumAddress, passphrase: str
419
- ) -> HexStr:
420
- return await self._sign_typed_data(message, account, passphrase)
421
-
422
- # new_account, lock_account, and unlock_account
423
-
424
- _new_account: Method[Callable[[str], Awaitable[ChecksumAddress]]] = Method(
425
- RPC.personal_newAccount,
426
- mungers=[default_root_munger],
427
- )
428
-
429
- _lock_account: Method[Callable[[ChecksumAddress], Awaitable[bool]]] = Method(
430
- RPC.personal_lockAccount,
431
- mungers=[default_root_munger],
432
- )
433
-
434
- _unlock_account: Method[
435
- Callable[[ChecksumAddress, str, Optional[int]], Awaitable[bool]]
436
- ] = Method(
437
- RPC.personal_unlockAccount,
438
- mungers=[default_root_munger],
439
- )
440
-
441
- async def new_account(self, passphrase: str) -> ChecksumAddress:
442
- return await self._new_account(passphrase)
443
-
444
- async def lock_account(self, account: ChecksumAddress) -> bool:
445
- return await self._lock_account(account)
446
-
447
- async def unlock_account(
448
- self, account: ChecksumAddress, passphrase: str, duration: Optional[int] = None
449
- ) -> bool:
450
- return await self._unlock_account(account, passphrase, duration)
303
+ _trace_transaction: Method[
304
+ Callable[
305
+ ...,
306
+ Awaitable[
307
+ Union[
308
+ CallTrace, PrestateTrace, OpcodeTrace, FourByteTrace, DiffModeTrace
309
+ ]
310
+ ],
311
+ ]
312
+ ] = Method(RPC.debug_traceTransaction)
313
+
314
+ async def trace_transaction(
315
+ self,
316
+ transaction_hash: _Hash32,
317
+ trace_config: Optional[TraceConfig] = None,
318
+ ) -> Union[CallTrace, PrestateTrace, OpcodeTrace, FourByteTrace, DiffModeTrace]:
319
+ return await self._trace_transaction(transaction_hash, trace_config)
451
320
 
452
321
 
453
322
  class AsyncGeth(Module):
454
323
  is_async = True
455
324
 
456
- personal: AsyncGethPersonal
457
325
  admin: AsyncGethAdmin
458
326
  txpool: AsyncGethTxPool
327
+ debug: AsyncGethDebug
web3/main.py CHANGED
@@ -34,6 +34,7 @@ from typing import (
34
34
  TYPE_CHECKING,
35
35
  Any,
36
36
  AsyncIterator,
37
+ Callable,
37
38
  Dict,
38
39
  Generator,
39
40
  List,
@@ -84,20 +85,28 @@ from web3.eth import (
84
85
  AsyncEth,
85
86
  Eth,
86
87
  )
88
+ from web3.exceptions import (
89
+ Web3TypeError,
90
+ Web3ValidationError,
91
+ Web3ValueError,
92
+ )
87
93
  from web3.geth import (
88
94
  AsyncGeth,
89
95
  AsyncGethAdmin,
90
- AsyncGethPersonal,
96
+ AsyncGethDebug,
91
97
  AsyncGethTxPool,
92
98
  Geth,
93
99
  GethAdmin,
94
- GethPersonal,
100
+ GethDebug,
95
101
  GethTxPool,
96
102
  )
97
103
  from web3.manager import (
98
104
  RequestManager as DefaultRequestManager,
99
105
  )
100
106
  from web3.middleware.base import MiddlewareOnion
107
+ from web3.method import (
108
+ Method,
109
+ )
101
110
  from web3.module import (
102
111
  Module,
103
112
  )
@@ -139,9 +148,14 @@ from web3.tracing import (
139
148
  from web3.types import (
140
149
  Wei,
141
150
  )
151
+ from web3.providers.persistent.subscription_manager import (
152
+ SubscriptionManager,
153
+ )
142
154
 
143
155
  if TYPE_CHECKING:
156
+ from web3._utils.batching import RequestBatcher # noqa: F401
144
157
  from web3._utils.empty import Empty # noqa: F401
158
+ from web3.providers.persistent import PersistentConnectionProvider # noqa: F401
145
159
 
146
160
 
147
161
  def get_async_default_modules() -> Dict[str, Union[Type[Module], Sequence[Any]]]:
@@ -152,8 +166,8 @@ def get_async_default_modules() -> Dict[str, Union[Type[Module], Sequence[Any]]]
152
166
  AsyncGeth,
153
167
  {
154
168
  "admin": AsyncGethAdmin,
155
- "personal": AsyncGethPersonal,
156
169
  "txpool": AsyncGethTxPool,
170
+ "debug": AsyncGethDebug,
157
171
  },
158
172
  ),
159
173
  }
@@ -167,8 +181,8 @@ def get_default_modules() -> Dict[str, Union[Type[Module], Sequence[Any]]]:
167
181
  Geth,
168
182
  {
169
183
  "admin": GethAdmin,
170
- "personal": GethPersonal,
171
184
  "txpool": GethTxPool,
185
+ "debug": GethDebug,
172
186
  },
173
187
  ),
174
188
  "tracing": Tracing,
@@ -283,7 +297,7 @@ class BaseWeb3:
283
297
  input_bytes = to_bytes(primitive, hexstr=hexstr, text=text)
284
298
  return eth_utils_keccak(input_bytes)
285
299
 
286
- raise TypeError(
300
+ raise Web3TypeError(
287
301
  f"You called keccak with first arg {primitive!r} and keywords "
288
302
  f"{{'text': {text!r}, 'hexstr': {hexstr!r}}}. You must call it with "
289
303
  "one of these approaches: keccak(text='txt'), keccak(hexstr='0x747874'), "
@@ -304,7 +318,7 @@ class BaseWeb3:
304
318
  and list of corresponding values -- `[20, [-1, 5, 0], True]`
305
319
  """
306
320
  if len(abi_types) != len(values):
307
- raise ValueError(
321
+ raise Web3ValueError(
308
322
  "Length mismatch between provided abi types and values. Got "
309
323
  f"{len(abi_types)} types and {len(values)} values."
310
324
  )
@@ -336,6 +350,31 @@ class BaseWeb3:
336
350
  def is_encodable(self, _type: TypeStr, value: Any) -> bool:
337
351
  return self.codec.is_encodable(_type, value)
338
352
 
353
+ # -- APIs for high-level requests -- #
354
+
355
+ def batch_requests(
356
+ self,
357
+ ) -> "RequestBatcher[Method[Callable[..., Any]]]":
358
+ return self.manager._batch_requests()
359
+
360
+
361
+ def _validate_provider(
362
+ w3: Union["Web3", "AsyncWeb3"],
363
+ provider: Optional[Union[BaseProvider, AsyncBaseProvider]],
364
+ ) -> None:
365
+ if provider is not None:
366
+ if isinstance(w3, AsyncWeb3) and not isinstance(provider, AsyncBaseProvider):
367
+ raise Web3ValidationError(
368
+ "Provider must be an instance of `AsyncBaseProvider` for "
369
+ f"`AsyncWeb3`, got {type(provider)}."
370
+ )
371
+
372
+ if isinstance(w3, Web3) and not isinstance(provider, BaseProvider):
373
+ raise Web3ValidationError(
374
+ "Provider must be an instance of `BaseProvider` for `Web3`, "
375
+ f"got {type(provider)}."
376
+ )
377
+
339
378
 
340
379
  class Web3(BaseWeb3):
341
380
  # mypy types
@@ -359,6 +398,8 @@ class Web3(BaseWeb3):
359
398
  ] = None,
360
399
  ens: Union[ENS, "Empty"] = empty,
361
400
  ) -> None:
401
+ _validate_provider(self, provider)
402
+
362
403
  self.manager = self.RequestManager(self, provider, middleware)
363
404
  self.codec = ABICodec(build_strict_registry())
364
405
 
@@ -427,6 +468,8 @@ class AsyncWeb3(BaseWeb3):
427
468
  ] = None,
428
469
  ens: Union[AsyncENS, "Empty"] = empty,
429
470
  ) -> None:
471
+ _validate_provider(self, provider)
472
+
430
473
  self.manager = self.RequestManager(self, provider, middleware)
431
474
  self.codec = ABICodec(build_strict_registry())
432
475
 
@@ -468,12 +511,27 @@ class AsyncWeb3(BaseWeb3):
468
511
  new_ens.w3 = self # set self object reference for ``AsyncENS.w3``
469
512
  self._ens = new_ens
470
513
 
471
- # -- persistent connection methods -- #
514
+ # -- persistent connection settings -- #
515
+
516
+ _subscription_manager: Optional[SubscriptionManager] = None
517
+ _persistent_connection: Optional["PersistentConnection"] = None
518
+
519
+ @property
520
+ @persistent_connection_provider_method()
521
+ def subscription_manager(self) -> SubscriptionManager:
522
+ """
523
+ Access the subscription manager for the current PersistentConnectionProvider.
524
+ """
525
+ if not self._subscription_manager:
526
+ self._subscription_manager = SubscriptionManager(self)
527
+ return self._subscription_manager
472
528
 
473
529
  @property
474
530
  @persistent_connection_provider_method()
475
531
  def socket(self) -> PersistentConnection:
476
- return PersistentConnection(self)
532
+ if self._persistent_connection is None:
533
+ self._persistent_connection = PersistentConnection(self)
534
+ return self._persistent_connection
477
535
 
478
536
  # w3 = await AsyncWeb3(PersistentConnectionProvider(...))
479
537
  @persistent_connection_provider_method(
@@ -482,7 +540,10 @@ class AsyncWeb3(BaseWeb3):
482
540
  )
483
541
  def __await__(self) -> Generator[Any, None, Self]:
484
542
  async def __async_init__() -> Self:
485
- await self.provider.connect()
543
+ provider = cast("PersistentConnectionProvider", self.provider)
544
+ await provider.connect()
545
+ # set signal handlers since not within a context manager
546
+ provider._set_signal_handlers()
486
547
  return self
487
548
 
488
549
  return __async_init__().__await__()
@@ -511,12 +572,11 @@ class AsyncWeb3(BaseWeb3):
511
572
  "when instantiating via ``async for``."
512
573
  )
513
574
  async def __aiter__(self) -> AsyncIterator[Self]:
514
- if not await self.provider.is_connected():
515
- await self.provider.connect()
516
-
575
+ provider = self.provider
517
576
  while True:
518
- try:
519
- yield self
520
- except Exception:
521
- # provider should handle connection / reconnection
522
- continue
577
+ await provider.connect()
578
+ yield self
579
+ cast("PersistentConnectionProvider", provider).logger.error(
580
+ "Connection interrupted, attempting to reconnect..."
581
+ )
582
+ await provider.disconnect()