web3 6.20.2__py3-none-any.whl → 7.0.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 (270) hide show
  1. ens/__init__.py +13 -2
  2. ens/_normalization.py +2 -17
  3. ens/async_ens.py +33 -21
  4. ens/base_ens.py +3 -1
  5. ens/ens.py +16 -11
  6. ens/exceptions.py +16 -29
  7. ens/specs/nf.json +1 -1
  8. ens/specs/normalization_spec.json +1 -1
  9. ens/utils.py +52 -63
  10. web3/__init__.py +20 -24
  11. web3/_utils/abi.py +115 -271
  12. web3/_utils/async_transactions.py +7 -4
  13. web3/_utils/batching.py +217 -0
  14. web3/_utils/blocks.py +6 -2
  15. web3/_utils/caching.py +128 -5
  16. web3/_utils/compat/__init__.py +2 -3
  17. web3/_utils/contract_sources/compile_contracts.py +1 -1
  18. web3/_utils/contract_sources/contract_data/arrays_contract.py +3 -3
  19. web3/_utils/contract_sources/contract_data/bytes_contracts.py +5 -5
  20. web3/_utils/contract_sources/contract_data/constructor_contracts.py +7 -7
  21. web3/_utils/contract_sources/contract_data/contract_caller_tester.py +3 -3
  22. web3/_utils/contract_sources/contract_data/emitter_contract.py +3 -3
  23. web3/_utils/contract_sources/contract_data/event_contracts.py +5 -5
  24. web3/_utils/contract_sources/contract_data/extended_resolver.py +3 -3
  25. web3/_utils/contract_sources/contract_data/fallback_function_contract.py +3 -3
  26. web3/_utils/contract_sources/contract_data/function_name_tester_contract.py +3 -3
  27. web3/_utils/contract_sources/contract_data/math_contract.py +3 -3
  28. web3/_utils/contract_sources/contract_data/offchain_lookup.py +3 -3
  29. web3/_utils/contract_sources/contract_data/offchain_resolver.py +3 -3
  30. web3/_utils/contract_sources/contract_data/panic_errors_contract.py +3 -3
  31. web3/_utils/contract_sources/contract_data/payable_tester.py +3 -3
  32. web3/_utils/contract_sources/contract_data/receive_function_contracts.py +5 -5
  33. web3/_utils/contract_sources/contract_data/reflector_contracts.py +3 -3
  34. web3/_utils/contract_sources/contract_data/revert_contract.py +3 -3
  35. web3/_utils/contract_sources/contract_data/simple_resolver.py +3 -3
  36. web3/_utils/contract_sources/contract_data/storage_contract.py +3 -3
  37. web3/_utils/contract_sources/contract_data/string_contract.py +3 -3
  38. web3/_utils/contract_sources/contract_data/tuple_contracts.py +5 -5
  39. web3/_utils/contracts.py +130 -236
  40. web3/_utils/datatypes.py +5 -1
  41. web3/_utils/decorators.py +13 -23
  42. web3/_utils/empty.py +1 -1
  43. web3/_utils/encoding.py +16 -12
  44. web3/_utils/ens.py +2 -1
  45. web3/_utils/error_formatters_utils.py +5 -3
  46. web3/_utils/events.py +66 -69
  47. web3/_utils/fee_utils.py +1 -3
  48. web3/_utils/filters.py +24 -22
  49. web3/_utils/formatters.py +2 -2
  50. web3/_utils/http.py +5 -3
  51. web3/_utils/http_session_manager.py +303 -0
  52. web3/_utils/math.py +14 -15
  53. web3/_utils/method_formatters.py +34 -36
  54. web3/_utils/module.py +2 -1
  55. web3/_utils/module_testing/__init__.py +0 -3
  56. web3/_utils/module_testing/eth_module.py +695 -643
  57. web3/_utils/module_testing/module_testing_utils.py +61 -34
  58. web3/_utils/module_testing/persistent_connection_provider.py +56 -25
  59. web3/_utils/module_testing/utils.py +258 -0
  60. web3/_utils/module_testing/web3_module.py +438 -17
  61. web3/_utils/normalizers.py +13 -11
  62. web3/_utils/rpc_abi.py +5 -32
  63. web3/_utils/threads.py +8 -7
  64. web3/_utils/transactions.py +14 -12
  65. web3/_utils/type_conversion.py +5 -1
  66. web3/_utils/validation.py +17 -17
  67. web3/auto/gethdev.py +7 -2
  68. web3/beacon/__init__.py +6 -1
  69. web3/beacon/async_beacon.py +9 -5
  70. web3/beacon/{main.py → beacon.py} +7 -5
  71. web3/contract/__init__.py +7 -0
  72. web3/contract/async_contract.py +47 -46
  73. web3/contract/base_contract.py +183 -158
  74. web3/contract/contract.py +49 -43
  75. web3/contract/utils.py +203 -59
  76. web3/datastructures.py +79 -31
  77. web3/eth/__init__.py +7 -0
  78. web3/eth/async_eth.py +39 -51
  79. web3/eth/base_eth.py +17 -10
  80. web3/eth/eth.py +30 -68
  81. web3/exceptions.py +108 -82
  82. web3/gas_strategies/time_based.py +8 -6
  83. web3/geth.py +1 -254
  84. web3/main.py +75 -122
  85. web3/manager.py +316 -146
  86. web3/method.py +38 -31
  87. web3/middleware/__init__.py +67 -89
  88. web3/middleware/attrdict.py +36 -49
  89. web3/middleware/base.py +174 -0
  90. web3/middleware/buffered_gas_estimate.py +20 -21
  91. web3/middleware/filter.py +157 -117
  92. web3/middleware/formatting.py +124 -108
  93. web3/middleware/gas_price_strategy.py +20 -32
  94. web3/middleware/names.py +29 -26
  95. web3/middleware/proof_of_authority.py +68 -0
  96. web3/middleware/pythonic.py +2 -2
  97. web3/middleware/signing.py +74 -89
  98. web3/middleware/stalecheck.py +52 -79
  99. web3/middleware/validation.py +5 -13
  100. web3/module.py +54 -10
  101. web3/providers/__init__.py +10 -6
  102. web3/providers/async_base.py +117 -39
  103. web3/providers/auto.py +3 -3
  104. web3/providers/base.py +89 -33
  105. web3/providers/eth_tester/__init__.py +5 -0
  106. web3/providers/eth_tester/defaults.py +1 -64
  107. web3/providers/eth_tester/main.py +99 -31
  108. web3/providers/eth_tester/middleware.py +45 -73
  109. web3/providers/ipc.py +42 -46
  110. web3/providers/{websocket/websocket.py → legacy_websocket.py} +32 -7
  111. web3/providers/persistent/__init__.py +22 -0
  112. web3/providers/persistent/async_ipc.py +153 -0
  113. web3/providers/{persistent.py → persistent/persistent.py} +106 -25
  114. web3/providers/persistent/persistent_connection.py +84 -0
  115. web3/providers/{websocket → persistent}/request_processor.py +94 -32
  116. web3/providers/persistent/utils.py +43 -0
  117. web3/providers/{websocket/websocket_v2.py → persistent/websocket.py} +29 -28
  118. web3/providers/rpc/__init__.py +11 -0
  119. web3/providers/rpc/async_rpc.py +171 -0
  120. web3/providers/rpc/rpc.py +179 -0
  121. web3/providers/rpc/utils.py +92 -0
  122. web3/testing.py +4 -4
  123. web3/tools/benchmark/main.py +22 -22
  124. web3/tools/benchmark/node.py +2 -8
  125. web3/tools/benchmark/reporting.py +2 -2
  126. web3/tools/benchmark/utils.py +1 -1
  127. web3/tracing.py +9 -5
  128. web3/types.py +30 -107
  129. web3/utils/__init__.py +58 -5
  130. web3/utils/abi.py +575 -10
  131. web3/utils/async_exception_handling.py +19 -7
  132. web3/utils/caching.py +32 -13
  133. web3/utils/exception_handling.py +7 -5
  134. {web3-6.20.2.dist-info → web3-7.0.0.dist-info}/LICENSE +1 -1
  135. web3-7.0.0.dist-info/METADATA +112 -0
  136. web3-7.0.0.dist-info/RECORD +167 -0
  137. {web3-6.20.2.dist-info → web3-7.0.0.dist-info}/WHEEL +1 -1
  138. {web3-6.20.2.dist-info → web3-7.0.0.dist-info}/top_level.txt +0 -1
  139. ethpm/__init__.py +0 -20
  140. ethpm/_utils/__init__.py +0 -0
  141. ethpm/_utils/backend.py +0 -93
  142. ethpm/_utils/cache.py +0 -44
  143. ethpm/_utils/chains.py +0 -119
  144. ethpm/_utils/contract.py +0 -35
  145. ethpm/_utils/deployments.py +0 -145
  146. ethpm/_utils/ipfs.py +0 -116
  147. ethpm/_utils/protobuf/__init__.py +0 -0
  148. ethpm/_utils/protobuf/ipfs_file_pb2.py +0 -33
  149. ethpm/_utils/registry.py +0 -29
  150. ethpm/assets/__init__.py +0 -0
  151. ethpm/assets/ens/v3.json +0 -1
  152. ethpm/assets/escrow/with_bytecode_v3.json +0 -1
  153. ethpm/assets/ipfs_file.proto +0 -32
  154. ethpm/assets/owned/output_v3.json +0 -1
  155. ethpm/assets/owned/with_contract_type_v3.json +0 -1
  156. ethpm/assets/registry/contracts/Authority.sol +0 -156
  157. ethpm/assets/registry/contracts/IndexedOrderedSetLib.sol +0 -106
  158. ethpm/assets/registry/contracts/PackageDB.sol +0 -225
  159. ethpm/assets/registry/contracts/PackageRegistry.sol +0 -361
  160. ethpm/assets/registry/contracts/PackageRegistryInterface.sol +0 -97
  161. ethpm/assets/registry/contracts/ReleaseDB.sol +0 -309
  162. ethpm/assets/registry/contracts/ReleaseValidator.sol +0 -152
  163. ethpm/assets/registry/solc_input.json +0 -1
  164. ethpm/assets/registry/solc_output.json +0 -1
  165. ethpm/assets/registry/v3.json +0 -1
  166. ethpm/assets/safe-math-lib/v3-strict-no-deployments.json +0 -1
  167. ethpm/assets/simple-registry/contracts/Ownable.sol +0 -63
  168. ethpm/assets/simple-registry/contracts/PackageRegistry.sol +0 -373
  169. ethpm/assets/simple-registry/contracts/PackageRegistryInterface.sol +0 -96
  170. ethpm/assets/simple-registry/solc_input.json +0 -33
  171. ethpm/assets/simple-registry/solc_output.json +0 -1
  172. ethpm/assets/simple-registry/v3.json +0 -1
  173. ethpm/assets/standard-token/output_v3.json +0 -1
  174. ethpm/assets/standard-token/with_bytecode_v3.json +0 -1
  175. ethpm/assets/vyper_registry/0.1.0.json +0 -1
  176. ethpm/assets/vyper_registry/registry.vy +0 -216
  177. ethpm/assets/vyper_registry/registry_with_delete.vy +0 -244
  178. ethpm/backends/__init__.py +0 -0
  179. ethpm/backends/base.py +0 -43
  180. ethpm/backends/http.py +0 -108
  181. ethpm/backends/ipfs.py +0 -219
  182. ethpm/backends/registry.py +0 -154
  183. ethpm/constants.py +0 -17
  184. ethpm/contract.py +0 -187
  185. ethpm/dependencies.py +0 -58
  186. ethpm/deployments.py +0 -80
  187. ethpm/ethpm-spec/examples/escrow/1.0.0-pretty.json +0 -146
  188. ethpm/ethpm-spec/examples/escrow/1.0.0.json +0 -1
  189. ethpm/ethpm-spec/examples/escrow/contracts/Escrow.sol +0 -32
  190. ethpm/ethpm-spec/examples/escrow/contracts/SafeSendLib.sol +0 -20
  191. ethpm/ethpm-spec/examples/escrow/v3-pretty.json +0 -171
  192. ethpm/ethpm-spec/examples/escrow/v3.json +0 -1
  193. ethpm/ethpm-spec/examples/owned/1.0.0-pretty.json +0 -21
  194. ethpm/ethpm-spec/examples/owned/1.0.0.json +0 -1
  195. ethpm/ethpm-spec/examples/owned/contracts/Owned.sol +0 -12
  196. ethpm/ethpm-spec/examples/owned/v3-pretty.json +0 -27
  197. ethpm/ethpm-spec/examples/owned/v3.json +0 -1
  198. ethpm/ethpm-spec/examples/piper-coin/1.0.0-pretty.json +0 -31
  199. ethpm/ethpm-spec/examples/piper-coin/1.0.0.json +0 -1
  200. ethpm/ethpm-spec/examples/piper-coin/v3-pretty.json +0 -21
  201. ethpm/ethpm-spec/examples/piper-coin/v3.json +0 -1
  202. ethpm/ethpm-spec/examples/safe-math-lib/1.0.0-pretty.json +0 -85
  203. ethpm/ethpm-spec/examples/safe-math-lib/1.0.0.json +0 -1
  204. ethpm/ethpm-spec/examples/safe-math-lib/contracts/SafeMathLib.sol +0 -24
  205. ethpm/ethpm-spec/examples/safe-math-lib/v3-pretty.json +0 -117
  206. ethpm/ethpm-spec/examples/safe-math-lib/v3.json +0 -1
  207. ethpm/ethpm-spec/examples/standard-token/1.0.0-pretty.json +0 -55
  208. ethpm/ethpm-spec/examples/standard-token/1.0.0.json +0 -1
  209. ethpm/ethpm-spec/examples/standard-token/contracts/AbstractToken.sol +0 -20
  210. ethpm/ethpm-spec/examples/standard-token/contracts/StandardToken.sol +0 -84
  211. ethpm/ethpm-spec/examples/standard-token/v3-pretty.json +0 -460
  212. ethpm/ethpm-spec/examples/standard-token/v3.json +0 -1
  213. ethpm/ethpm-spec/examples/transferable/1.0.0-pretty.json +0 -21
  214. ethpm/ethpm-spec/examples/transferable/1.0.0.json +0 -1
  215. ethpm/ethpm-spec/examples/transferable/contracts/Transferable.sol +0 -14
  216. ethpm/ethpm-spec/examples/transferable/v3-pretty.json +0 -27
  217. ethpm/ethpm-spec/examples/transferable/v3.json +0 -1
  218. ethpm/ethpm-spec/examples/wallet/1.0.0-pretty.json +0 -120
  219. ethpm/ethpm-spec/examples/wallet/1.0.0.json +0 -1
  220. ethpm/ethpm-spec/examples/wallet/contracts/Wallet.sol +0 -41
  221. ethpm/ethpm-spec/examples/wallet/v3-pretty.json +0 -181
  222. ethpm/ethpm-spec/examples/wallet/v3.json +0 -1
  223. ethpm/ethpm-spec/examples/wallet-with-send/1.0.0-pretty.json +0 -135
  224. ethpm/ethpm-spec/examples/wallet-with-send/1.0.0.json +0 -1
  225. ethpm/ethpm-spec/examples/wallet-with-send/contracts/WalletWithSend.sol +0 -18
  226. ethpm/ethpm-spec/examples/wallet-with-send/v3-pretty.json +0 -207
  227. ethpm/ethpm-spec/examples/wallet-with-send/v3.json +0 -1
  228. ethpm/ethpm-spec/spec/package.spec.json +0 -379
  229. ethpm/ethpm-spec/spec/v3.spec.json +0 -483
  230. ethpm/exceptions.py +0 -68
  231. ethpm/package.py +0 -438
  232. ethpm/tools/__init__.py +0 -4
  233. ethpm/tools/builder.py +0 -930
  234. ethpm/tools/checker.py +0 -312
  235. ethpm/tools/get_manifest.py +0 -19
  236. ethpm/uri.py +0 -141
  237. ethpm/validation/__init__.py +0 -0
  238. ethpm/validation/manifest.py +0 -146
  239. ethpm/validation/misc.py +0 -39
  240. ethpm/validation/package.py +0 -80
  241. ethpm/validation/uri.py +0 -163
  242. web3/_utils/contract_sources/contract_data/address_reflector.py +0 -29
  243. web3/_utils/miner.py +0 -88
  244. web3/_utils/module_testing/go_ethereum_personal_module.py +0 -323
  245. web3/_utils/request.py +0 -265
  246. web3/middleware/abi.py +0 -11
  247. web3/middleware/async_cache.py +0 -99
  248. web3/middleware/cache.py +0 -374
  249. web3/middleware/exception_handling.py +0 -49
  250. web3/middleware/exception_retry_request.py +0 -188
  251. web3/middleware/fixture.py +0 -190
  252. web3/middleware/geth_poa.py +0 -81
  253. web3/middleware/normalize_request_parameters.py +0 -11
  254. web3/middleware/simulate_unmined_transaction.py +0 -43
  255. web3/pm.py +0 -602
  256. web3/providers/async_rpc.py +0 -99
  257. web3/providers/rpc.py +0 -98
  258. web3/providers/websocket/__init__.py +0 -11
  259. web3/providers/websocket/websocket_connection.py +0 -42
  260. web3/tools/__init__.py +0 -4
  261. web3/tools/pytest_ethereum/__init__.py +0 -0
  262. web3/tools/pytest_ethereum/_utils.py +0 -145
  263. web3/tools/pytest_ethereum/deployer.py +0 -48
  264. web3/tools/pytest_ethereum/exceptions.py +0 -22
  265. web3/tools/pytest_ethereum/linker.py +0 -128
  266. web3/tools/pytest_ethereum/plugins.py +0 -33
  267. web3-6.20.2.dist-info/METADATA +0 -103
  268. web3-6.20.2.dist-info/RECORD +0 -283
  269. web3-6.20.2.dist-info/entry_points.txt +0 -2
  270. /web3/_utils/{function_identifiers.py → abi_element_identifiers.py} +0 -0
@@ -1,10 +1,13 @@
1
+ import asyncio
1
2
  import itertools
2
3
  from typing import (
3
4
  TYPE_CHECKING,
4
5
  Any,
5
6
  Callable,
6
7
  Coroutine,
7
- Sequence,
8
+ List,
9
+ Optional,
10
+ Set,
8
11
  Tuple,
9
12
  cast,
10
13
  )
@@ -15,6 +18,10 @@ from eth_utils import (
15
18
  to_text,
16
19
  )
17
20
 
21
+ from web3._utils.caching import (
22
+ CACHEABLE_REQUESTS,
23
+ async_handle_request_caching,
24
+ )
18
25
  from web3._utils.encoding import (
19
26
  FriendlyJsonSerde,
20
27
  Web3JsonEncoder,
@@ -23,81 +30,138 @@ from web3.exceptions import (
23
30
  ProviderConnectionError,
24
31
  )
25
32
  from web3.middleware import (
26
- async_combine_middlewares,
33
+ async_combine_middleware,
27
34
  )
28
- from web3.types import (
29
- AsyncMiddleware,
30
- AsyncMiddlewareOnion,
35
+ from web3.middleware.base import (
36
+ Middleware,
31
37
  MiddlewareOnion,
38
+ )
39
+ from web3.types import (
32
40
  RPCEndpoint,
33
41
  RPCResponse,
34
42
  )
43
+ from web3.utils import (
44
+ SimpleCache,
45
+ )
35
46
 
36
47
  if TYPE_CHECKING:
48
+ from websockets import (
49
+ WebSocketClientProtocol,
50
+ )
51
+
37
52
  from web3 import ( # noqa: F401
38
53
  AsyncWeb3,
39
- WebsocketProviderV2,
54
+ WebSocketProvider,
55
+ )
56
+ from web3.providers.persistent import ( # noqa: F401
57
+ RequestProcessor,
40
58
  )
41
59
 
42
60
 
43
61
  class AsyncBaseProvider:
44
- _middlewares: Tuple[AsyncMiddleware, ...] = ()
45
- # a tuple of (all_middlewares, request_func)
46
62
  _request_func_cache: Tuple[
47
- Tuple[AsyncMiddleware, ...], Callable[..., Coroutine[Any, Any, RPCResponse]]
48
- ] = (
49
- None,
50
- None,
51
- )
63
+ Tuple[Middleware, ...], Callable[..., Coroutine[Any, Any, RPCResponse]]
64
+ ] = (None, None)
65
+
66
+ _is_batching: bool = False
67
+ _batch_request_func_cache: Tuple[
68
+ Tuple[Middleware, ...], Callable[..., Coroutine[Any, Any, List[RPCResponse]]]
69
+ ] = (None, None)
52
70
 
53
71
  is_async = True
54
72
  has_persistent_connection = False
55
73
  global_ccip_read_enabled: bool = True
56
74
  ccip_read_max_redirects: int = 4
57
75
 
58
- @property
59
- def middlewares(self) -> Tuple[AsyncMiddleware, ...]:
60
- return self._middlewares
76
+ # request caching
77
+ _request_cache: SimpleCache
78
+ _request_cache_lock: asyncio.Lock = asyncio.Lock()
61
79
 
62
- @middlewares.setter
63
- def middlewares(self, values: MiddlewareOnion) -> None:
64
- # tuple(values) converts to MiddlewareOnion -> Tuple[Middleware, ...]
65
- self._middlewares = tuple(values) # type: ignore
80
+ def __init__(
81
+ self,
82
+ cache_allowed_requests: bool = False,
83
+ cacheable_requests: Set[RPCEndpoint] = None,
84
+ ) -> None:
85
+ self._request_cache = SimpleCache(1000)
86
+ self.cache_allowed_requests = cache_allowed_requests
87
+ self.cacheable_requests = cacheable_requests or CACHEABLE_REQUESTS
66
88
 
67
89
  async def request_func(
68
- self, async_w3: "AsyncWeb3", outer_middlewares: AsyncMiddlewareOnion
90
+ self, async_w3: "AsyncWeb3", middleware_onion: MiddlewareOnion
69
91
  ) -> Callable[..., Coroutine[Any, Any, RPCResponse]]:
70
- # type ignored b/c tuple(MiddlewareOnion) converts to tuple of middlewares
71
- all_middlewares: Tuple[AsyncMiddleware] = tuple(outer_middlewares) + tuple(self.middlewares) # type: ignore # noqa: E501
92
+ middleware: Tuple[Middleware, ...] = middleware_onion.as_tuple_of_middleware()
72
93
 
73
94
  cache_key = self._request_func_cache[0]
74
- if cache_key is None or cache_key != all_middlewares:
95
+ if cache_key != middleware:
75
96
  self._request_func_cache = (
76
- all_middlewares,
77
- await self._generate_request_func(async_w3, all_middlewares),
97
+ middleware,
98
+ await async_combine_middleware(
99
+ middleware=middleware,
100
+ async_w3=async_w3,
101
+ provider_request_fn=self.make_request,
102
+ ),
78
103
  )
79
104
  return self._request_func_cache[-1]
80
105
 
81
- async def _generate_request_func(
82
- self, async_w3: "AsyncWeb3", middlewares: Sequence[AsyncMiddleware]
83
- ) -> Callable[..., Coroutine[Any, Any, RPCResponse]]:
84
- return await async_combine_middlewares(
85
- middlewares=middlewares,
86
- async_w3=async_w3,
87
- provider_request_fn=self.make_request,
88
- )
106
+ async def batch_request_func(
107
+ self, async_w3: "AsyncWeb3", middleware_onion: MiddlewareOnion
108
+ ) -> Callable[..., Coroutine[Any, Any, List[RPCResponse]]]:
109
+ middleware: Tuple[Middleware, ...] = middleware_onion.as_tuple_of_middleware()
110
+
111
+ cache_key = self._batch_request_func_cache[0]
112
+ if cache_key != middleware:
113
+ accumulator_fn = self.make_batch_request
114
+ for mw in reversed(middleware):
115
+ initialized = mw(async_w3)
116
+ # type ignore bc in order to wrap the method, we have to call
117
+ # `async_wrap_make_batch_request` with the accumulator_fn as the
118
+ # argument which breaks the type hinting for this particular case.
119
+ accumulator_fn = await initialized.async_wrap_make_batch_request( # type: ignore # noqa: E501
120
+ accumulator_fn
121
+ )
122
+ self._batch_request_func_cache = (middleware, accumulator_fn)
123
+ return self._batch_request_func_cache[-1]
89
124
 
125
+ @async_handle_request_caching
90
126
  async def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
91
127
  raise NotImplementedError("Providers must implement this method")
92
128
 
129
+ async def make_batch_request(
130
+ self, requests: List[Tuple[RPCEndpoint, Any]]
131
+ ) -> List[RPCResponse]:
132
+ raise NotImplementedError("Only AsyncHTTPProvider supports this method")
133
+
93
134
  async def is_connected(self, show_traceback: bool = False) -> bool:
94
135
  raise NotImplementedError("Providers must implement this method")
95
136
 
137
+ # -- persistent connection providers -- #
138
+
139
+ _request_processor: "RequestProcessor"
140
+ _message_listener_task: "asyncio.Task[None]"
141
+ _listen_event: "asyncio.Event"
142
+
143
+ async def connect(self) -> None:
144
+ raise NotImplementedError(
145
+ "Persistent connection providers must implement this method"
146
+ )
147
+
148
+ async def disconnect(self) -> None:
149
+ raise NotImplementedError(
150
+ "Persistent connection providers must implement this method"
151
+ )
152
+
153
+ # WebSocket typing
154
+ _ws: "WebSocketClientProtocol"
155
+
156
+ # IPC typing
157
+ _reader: Optional[asyncio.StreamReader]
158
+ _writer: Optional[asyncio.StreamWriter]
159
+
96
160
 
97
161
  class AsyncJSONBaseProvider(AsyncBaseProvider):
98
- def __init__(self) -> None:
99
- super().__init__()
162
+ def __init__(self, **kwargs: Any) -> None:
100
163
  self.request_counter = itertools.count()
164
+ super().__init__(**kwargs)
101
165
 
102
166
  def encode_rpc_request(self, method: RPCEndpoint, params: Any) -> bytes:
103
167
  request_id = next(self.request_counter)
@@ -110,7 +174,8 @@ class AsyncJSONBaseProvider(AsyncBaseProvider):
110
174
  encoded = FriendlyJsonSerde().json_encode(rpc_dict, cls=Web3JsonEncoder)
111
175
  return to_bytes(text=encoded)
112
176
 
113
- def decode_rpc_response(self, raw_response: bytes) -> RPCResponse:
177
+ @staticmethod
178
+ def decode_rpc_response(raw_response: bytes) -> RPCResponse:
114
179
  text_response = str(
115
180
  to_text(raw_response) if not is_text(raw_response) else raw_response
116
181
  )
@@ -119,7 +184,7 @@ class AsyncJSONBaseProvider(AsyncBaseProvider):
119
184
  async def is_connected(self, show_traceback: bool = False) -> bool:
120
185
  try:
121
186
  response = await self.make_request(RPCEndpoint("web3_clientVersion"), [])
122
- except OSError as e:
187
+ except (OSError, ProviderConnectionError) as e:
123
188
  if show_traceback:
124
189
  raise ProviderConnectionError(
125
190
  f"Problem connecting to provider with error: {type(e)}: {e}"
@@ -133,9 +198,22 @@ class AsyncJSONBaseProvider(AsyncBaseProvider):
133
198
  )
134
199
  return False
135
200
 
136
- if response["jsonrpc"] == "2.0":
201
+ if response.get("jsonrpc") == "2.0":
137
202
  return True
138
203
  else:
139
204
  if show_traceback:
140
205
  raise ProviderConnectionError(f"Bad jsonrpc version: {response}")
141
206
  return False
207
+
208
+ # -- batch requests -- #
209
+
210
+ def encode_batch_rpc_request(
211
+ self, requests: List[Tuple[RPCEndpoint, Any]]
212
+ ) -> bytes:
213
+ return (
214
+ b"["
215
+ + b", ".join(
216
+ self.encode_rpc_request(method, params) for method, params in requests
217
+ )
218
+ + b"]"
219
+ )
web3/providers/auto.py CHANGED
@@ -24,7 +24,7 @@ from web3.providers import (
24
24
  BaseProvider,
25
25
  HTTPProvider,
26
26
  IPCProvider,
27
- WebsocketProvider,
27
+ LegacyWebSocketProvider,
28
28
  )
29
29
  from web3.types import (
30
30
  RPCEndpoint,
@@ -52,7 +52,7 @@ def load_provider_from_uri(
52
52
  elif uri.scheme in HTTP_SCHEMES:
53
53
  return HTTPProvider(uri_string, headers)
54
54
  elif uri.scheme in WS_SCHEMES:
55
- return WebsocketProvider(uri_string)
55
+ return LegacyWebSocketProvider(uri_string)
56
56
  else:
57
57
  raise NotImplementedError(
58
58
  "Web3 does not know how to connect to scheme "
@@ -65,7 +65,7 @@ class AutoProvider(BaseProvider):
65
65
  load_provider_from_environment,
66
66
  IPCProvider,
67
67
  HTTPProvider,
68
- WebsocketProvider,
68
+ LegacyWebSocketProvider,
69
69
  )
70
70
  _active_provider = None
71
71
 
web3/providers/base.py CHANGED
@@ -1,9 +1,11 @@
1
1
  import itertools
2
+ import threading
2
3
  from typing import (
3
4
  TYPE_CHECKING,
4
5
  Any,
5
6
  Callable,
6
- Sequence,
7
+ List,
8
+ Set,
7
9
  Tuple,
8
10
  cast,
9
11
  )
@@ -13,6 +15,10 @@ from eth_utils import (
13
15
  to_text,
14
16
  )
15
17
 
18
+ from web3._utils.caching import (
19
+ CACHEABLE_REQUESTS,
20
+ handle_request_caching,
21
+ )
16
22
  from web3._utils.encoding import (
17
23
  FriendlyJsonSerde,
18
24
  Web3JsonEncoder,
@@ -21,22 +27,26 @@ from web3.exceptions import (
21
27
  ProviderConnectionError,
22
28
  )
23
29
  from web3.middleware import (
24
- combine_middlewares,
30
+ combine_middleware,
25
31
  )
26
- from web3.types import (
32
+ from web3.middleware.base import (
27
33
  Middleware,
28
34
  MiddlewareOnion,
35
+ )
36
+ from web3.types import (
29
37
  RPCEndpoint,
30
38
  RPCResponse,
31
39
  )
40
+ from web3.utils import (
41
+ SimpleCache,
42
+ )
32
43
 
33
44
  if TYPE_CHECKING:
34
45
  from web3 import Web3 # noqa: F401
35
46
 
36
47
 
37
48
  class BaseProvider:
38
- _middlewares: Tuple[Middleware, ...] = ()
39
- # a tuple of (all_middlewares, request_func)
49
+ # a tuple of (middleware, request_func)
40
50
  _request_func_cache: Tuple[Tuple[Middleware, ...], Callable[..., RPCResponse]] = (
41
51
  None,
42
52
  None,
@@ -47,44 +57,45 @@ class BaseProvider:
47
57
  global_ccip_read_enabled: bool = True
48
58
  ccip_read_max_redirects: int = 4
49
59
 
50
- @property
51
- def middlewares(self) -> Tuple[Middleware, ...]:
52
- return self._middlewares
60
+ # request caching
61
+ _request_cache: SimpleCache
62
+ _request_cache_lock: threading.Lock = threading.Lock()
53
63
 
54
- @middlewares.setter
55
- def middlewares(self, values: MiddlewareOnion) -> None:
56
- # tuple(values) converts to MiddlewareOnion -> Tuple[Middleware, ...]
57
- self._middlewares = tuple(values) # type: ignore
64
+ def __init__(
65
+ self,
66
+ cache_allowed_requests: bool = False,
67
+ cacheable_requests: Set[RPCEndpoint] = None,
68
+ ) -> None:
69
+ self._request_cache = SimpleCache(1000)
70
+ self.cache_allowed_requests = cache_allowed_requests
71
+ self.cacheable_requests = cacheable_requests or CACHEABLE_REQUESTS
58
72
 
59
73
  def request_func(
60
- self, w3: "Web3", outer_middlewares: MiddlewareOnion
74
+ self, w3: "Web3", middleware_onion: MiddlewareOnion
61
75
  ) -> Callable[..., RPCResponse]:
62
76
  """
63
- @param outer_middlewares is an iterable of middlewares,
77
+ @param w3 is the web3 instance
78
+ @param middleware_onion is an iterable of middleware,
64
79
  ordered by first to execute
65
80
  @returns a function that calls all the middleware and
66
81
  eventually self.make_request()
67
82
  """
68
- # type ignored b/c tuple(MiddlewareOnion) converts to tuple of middlewares
69
- all_middlewares: Tuple[Middleware] = tuple(outer_middlewares) + tuple(self.middlewares) # type: ignore # noqa: E501
83
+ middleware: Tuple[Middleware, ...] = middleware_onion.as_tuple_of_middleware()
70
84
 
71
85
  cache_key = self._request_func_cache[0]
72
- if cache_key is None or cache_key != all_middlewares:
86
+ if cache_key != middleware:
73
87
  self._request_func_cache = (
74
- all_middlewares,
75
- self._generate_request_func(w3, all_middlewares),
88
+ middleware,
89
+ combine_middleware(
90
+ middleware=middleware,
91
+ w3=w3,
92
+ provider_request_fn=self.make_request,
93
+ ),
76
94
  )
77
- return self._request_func_cache[-1]
78
95
 
79
- def _generate_request_func(
80
- self, w3: "Web3", middlewares: Sequence[Middleware]
81
- ) -> Callable[..., RPCResponse]:
82
- return combine_middlewares(
83
- middlewares=middlewares,
84
- w3=w3,
85
- provider_request_fn=self.make_request,
86
- )
96
+ return self._request_func_cache[-1]
87
97
 
98
+ @handle_request_caching
88
99
  def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
89
100
  raise NotImplementedError("Providers must implement this method")
90
101
 
@@ -93,12 +104,14 @@ class BaseProvider:
93
104
 
94
105
 
95
106
  class JSONBaseProvider(BaseProvider):
96
- def __init__(self) -> None:
97
- self.request_counter = itertools.count()
107
+ _is_batching: bool = False
108
+ _batch_request_func_cache: Tuple[
109
+ Tuple[Middleware, ...], Callable[..., List[RPCResponse]]
110
+ ] = (None, None)
98
111
 
99
- def decode_rpc_response(self, raw_response: bytes) -> RPCResponse:
100
- text_response = to_text(raw_response)
101
- return cast(RPCResponse, FriendlyJsonSerde().json_decode(text_response))
112
+ def __init__(self, **kwargs: Any) -> None:
113
+ self.request_counter = itertools.count()
114
+ super().__init__(**kwargs)
102
115
 
103
116
  def encode_rpc_request(self, method: RPCEndpoint, params: Any) -> bytes:
104
117
  rpc_dict = {
@@ -110,6 +123,11 @@ class JSONBaseProvider(BaseProvider):
110
123
  encoded = FriendlyJsonSerde().json_encode(rpc_dict, Web3JsonEncoder)
111
124
  return to_bytes(text=encoded)
112
125
 
126
+ @staticmethod
127
+ def decode_rpc_response(raw_response: bytes) -> RPCResponse:
128
+ text_response = to_text(raw_response)
129
+ return cast(RPCResponse, FriendlyJsonSerde().json_decode(text_response))
130
+
113
131
  def is_connected(self, show_traceback: bool = False) -> bool:
114
132
  try:
115
133
  response = self.make_request(RPCEndpoint("web3_clientVersion"), [])
@@ -133,3 +151,41 @@ class JSONBaseProvider(BaseProvider):
133
151
  if show_traceback:
134
152
  raise ProviderConnectionError(f"Bad jsonrpc version: {response}")
135
153
  return False
154
+
155
+ # -- batch requests -- #
156
+
157
+ def batch_request_func(
158
+ self, w3: "Web3", middleware_onion: MiddlewareOnion
159
+ ) -> Callable[..., List[RPCResponse]]:
160
+ middleware: Tuple[Middleware, ...] = middleware_onion.as_tuple_of_middleware()
161
+
162
+ cache_key = self._batch_request_func_cache[0]
163
+ if cache_key != middleware:
164
+ accumulator_fn = self.make_batch_request
165
+ for mw in reversed(middleware):
166
+ initialized = mw(w3)
167
+ # type ignore bc in order to wrap the method, we have to call
168
+ # `wrap_make_batch_request` with the accumulator_fn as the argument
169
+ # which breaks the type hinting for this particular case.
170
+ accumulator_fn = initialized.wrap_make_batch_request(
171
+ accumulator_fn
172
+ ) # type: ignore # noqa: E501
173
+ self._batch_request_func_cache = (middleware, accumulator_fn)
174
+
175
+ return self._batch_request_func_cache[-1]
176
+
177
+ def encode_batch_rpc_request(
178
+ self, requests: List[Tuple[RPCEndpoint, Any]]
179
+ ) -> bytes:
180
+ return (
181
+ b"["
182
+ + b", ".join(
183
+ self.encode_rpc_request(method, params) for method, params in requests
184
+ )
185
+ + b"]"
186
+ )
187
+
188
+ def make_batch_request(
189
+ self, requests: List[Tuple[RPCEndpoint, Any]]
190
+ ) -> List[RPCResponse]:
191
+ raise NotImplementedError("Providers must implement this method")
@@ -2,3 +2,8 @@ from .main import (
2
2
  AsyncEthereumTesterProvider,
3
3
  EthereumTesterProvider,
4
4
  )
5
+
6
+ __all__ = [
7
+ "AsyncEthereumTesterProvider",
8
+ "EthereumTesterProvider",
9
+ ]
@@ -21,7 +21,6 @@ from eth_tester.exceptions import (
21
21
  FilterNotFound,
22
22
  TransactionFailed,
23
23
  TransactionNotFound,
24
- ValidationError,
25
24
  )
26
25
  from eth_typing import (
27
26
  HexAddress,
@@ -218,7 +217,7 @@ def _generate_random_private_key() -> HexStr:
218
217
  WARNING: This is not a secure way to generate private keys and should only
219
218
  be used for testing purposes.
220
219
  """
221
- return encode_hex(bytes(bytearray((random.randint(0, 255) for _ in range(32)))))
220
+ return encode_hex(bytes(bytearray(random.randint(0, 255) for _ in range(32))))
222
221
 
223
222
 
224
223
  @without_params
@@ -226,18 +225,6 @@ def create_new_account(eth_tester: "EthereumTester") -> HexAddress:
226
225
  return eth_tester.add_account(_generate_random_private_key())
227
226
 
228
227
 
229
- def personal_send_transaction(eth_tester: "EthereumTester", params: Any) -> HexStr:
230
- transaction, password = params
231
-
232
- try:
233
- eth_tester.unlock_account(transaction["from"], password)
234
- transaction_hash = eth_tester.send_transaction(transaction)
235
- finally:
236
- eth_tester.lock_account(transaction["from"])
237
-
238
- return transaction_hash
239
-
240
-
241
228
  API_ENDPOINTS = {
242
229
  "web3": {
243
230
  "clientVersion": client_version,
@@ -256,12 +243,6 @@ API_ENDPOINTS = {
256
243
  "eth": {
257
244
  "protocolVersion": static_return(63),
258
245
  "syncing": static_return(False),
259
- "coinbase": compose(
260
- operator.itemgetter(0),
261
- call_eth_tester("get_accounts"),
262
- ),
263
- "mining": static_return(False),
264
- "hashrate": static_return(0),
265
246
  "chainId": static_return(131277322940537), # from fixture generation file
266
247
  "feeHistory": call_eth_tester("get_fee_history"),
267
248
  "maxPriorityFeePerGas": static_return(10**9),
@@ -404,50 +385,6 @@ API_ENDPOINTS = {
404
385
  "writeBlockProfile": not_implemented,
405
386
  "writeMemProfile": not_implemented,
406
387
  },
407
- "miner": {
408
- "make_dag": not_implemented,
409
- "set_extra": not_implemented,
410
- "set_gas_price": not_implemented,
411
- "start": not_implemented,
412
- "stop": not_implemented,
413
- "start_auto_dag": not_implemented,
414
- "stop_auto_dag": not_implemented,
415
- },
416
- "personal": {
417
- "ec_recover": not_implemented,
418
- "import_raw_key": call_eth_tester("add_account"),
419
- "list_accounts": call_eth_tester("get_accounts"),
420
- "list_wallets": not_implemented,
421
- "lock_account": excepts(
422
- ValidationError,
423
- compose(static_return(True), call_eth_tester("lock_account")),
424
- static_return(False),
425
- ),
426
- "new_account": create_new_account,
427
- "unlock_account": excepts(
428
- ValidationError,
429
- compose(static_return(True), call_eth_tester("unlock_account")),
430
- static_return(False),
431
- ),
432
- "send_transaction": personal_send_transaction,
433
- "sign": not_implemented,
434
- # deprecated
435
- "ecRecover": not_implemented,
436
- "importRawKey": call_eth_tester("add_account"),
437
- "listAccounts": call_eth_tester("get_accounts"),
438
- "lockAccount": excepts(
439
- ValidationError,
440
- compose(static_return(True), call_eth_tester("lock_account")),
441
- static_return(False),
442
- ),
443
- "newAccount": create_new_account,
444
- "unlockAccount": excepts(
445
- ValidationError,
446
- compose(static_return(True), call_eth_tester("unlock_account")),
447
- static_return(False),
448
- ),
449
- "sendTransaction": personal_send_transaction,
450
- },
451
388
  "testing": {
452
389
  "timeTravel": call_eth_tester("time_travel"),
453
390
  },