web3 7.0.0b6__py3-none-any.whl → 7.0.0b8__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/__init__.py +13 -2
- web3/__init__.py +21 -5
- web3/_utils/contract_sources/contract_data/arrays_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/bytes_contracts.py +5 -5
- web3/_utils/contract_sources/contract_data/constructor_contracts.py +7 -7
- web3/_utils/contract_sources/contract_data/contract_caller_tester.py +3 -3
- web3/_utils/contract_sources/contract_data/emitter_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/event_contracts.py +5 -5
- web3/_utils/contract_sources/contract_data/extended_resolver.py +3 -3
- web3/_utils/contract_sources/contract_data/fallback_function_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/function_name_tester_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/math_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/offchain_lookup.py +3 -3
- web3/_utils/contract_sources/contract_data/offchain_resolver.py +3 -3
- web3/_utils/contract_sources/contract_data/panic_errors_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/payable_tester.py +3 -3
- web3/_utils/contract_sources/contract_data/receive_function_contracts.py +5 -5
- web3/_utils/contract_sources/contract_data/reflector_contracts.py +3 -3
- web3/_utils/contract_sources/contract_data/revert_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/simple_resolver.py +3 -3
- web3/_utils/contract_sources/contract_data/storage_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/string_contract.py +3 -3
- web3/_utils/contract_sources/contract_data/tuple_contracts.py +5 -5
- web3/_utils/http.py +3 -0
- web3/_utils/http_session_manager.py +280 -0
- web3/_utils/method_formatters.py +19 -3
- web3/_utils/module_testing/eth_module.py +84 -111
- web3/_utils/module_testing/module_testing_utils.py +22 -18
- web3/_utils/module_testing/persistent_connection_provider.py +45 -16
- web3/_utils/rpc_abi.py +0 -3
- web3/beacon/__init__.py +5 -0
- web3/beacon/async_beacon.py +9 -5
- web3/beacon/beacon.py +7 -5
- web3/contract/__init__.py +7 -0
- web3/contract/base_contract.py +10 -1
- web3/eth/__init__.py +7 -0
- web3/eth/async_eth.py +0 -33
- web3/eth/eth.py +2 -53
- web3/exceptions.py +6 -0
- web3/manager.py +34 -11
- web3/middleware/__init__.py +17 -0
- web3/module.py +1 -1
- web3/providers/__init__.py +21 -0
- web3/providers/eth_tester/__init__.py +5 -0
- web3/providers/eth_tester/defaults.py +0 -6
- web3/providers/eth_tester/middleware.py +3 -8
- web3/providers/persistent/__init__.py +7 -0
- web3/providers/persistent/async_ipc.py +34 -79
- web3/providers/persistent/persistent.py +76 -7
- web3/providers/persistent/persistent_connection.py +47 -5
- web3/providers/persistent/websocket.py +19 -59
- web3/providers/rpc/__init__.py +5 -0
- web3/providers/rpc/async_rpc.py +16 -12
- web3/providers/rpc/rpc.py +16 -12
- web3/providers/rpc/utils.py +0 -3
- web3/tools/benchmark/main.py +7 -6
- web3/tools/benchmark/node.py +1 -1
- web3/utils/__init__.py +14 -5
- web3/utils/async_exception_handling.py +19 -7
- web3/utils/caching.py +24 -0
- web3/utils/exception_handling.py +7 -5
- {web3-7.0.0b6.dist-info → web3-7.0.0b8.dist-info}/METADATA +14 -8
- {web3-7.0.0b6.dist-info → web3-7.0.0b8.dist-info}/RECORD +66 -67
- {web3-7.0.0b6.dist-info → web3-7.0.0b8.dist-info}/WHEEL +1 -1
- web3/_utils/contract_sources/contract_data/address_reflector.py +0 -29
- web3/_utils/request.py +0 -265
- {web3-7.0.0b6.dist-info → web3-7.0.0b8.dist-info}/LICENSE +0 -0
- {web3-7.0.0b6.dist-info → web3-7.0.0b8.dist-info}/top_level.txt +0 -0
|
@@ -11,11 +11,9 @@ from pathlib import (
|
|
|
11
11
|
import sys
|
|
12
12
|
from typing import (
|
|
13
13
|
Any,
|
|
14
|
-
List,
|
|
15
14
|
Optional,
|
|
16
15
|
Tuple,
|
|
17
16
|
Union,
|
|
18
|
-
cast,
|
|
19
17
|
)
|
|
20
18
|
|
|
21
19
|
from eth_utils import (
|
|
@@ -23,20 +21,12 @@ from eth_utils import (
|
|
|
23
21
|
)
|
|
24
22
|
|
|
25
23
|
from web3.types import (
|
|
26
|
-
RPCEndpoint,
|
|
27
24
|
RPCResponse,
|
|
28
25
|
)
|
|
29
26
|
|
|
30
27
|
from . import (
|
|
31
28
|
PersistentConnectionProvider,
|
|
32
29
|
)
|
|
33
|
-
from ..._utils.batching import (
|
|
34
|
-
BATCH_REQUEST_ID,
|
|
35
|
-
sort_batch_response_by_response_ids,
|
|
36
|
-
)
|
|
37
|
-
from ..._utils.caching import (
|
|
38
|
-
async_handle_request_caching,
|
|
39
|
-
)
|
|
40
30
|
from ...exceptions import (
|
|
41
31
|
ProviderConnectionError,
|
|
42
32
|
Web3TypeError,
|
|
@@ -91,12 +81,7 @@ class AsyncIPCProvider(PersistentConnectionProvider):
|
|
|
91
81
|
return False
|
|
92
82
|
|
|
93
83
|
try:
|
|
94
|
-
|
|
95
|
-
RPCEndpoint("web3_clientVersions"), []
|
|
96
|
-
)
|
|
97
|
-
self._writer.write(request_data)
|
|
98
|
-
current_request_id = json.loads(request_data)["id"]
|
|
99
|
-
await self._get_response_for_request_id(current_request_id, timeout=2)
|
|
84
|
+
await self.make_request("web3_clientVersion", [])
|
|
100
85
|
return True
|
|
101
86
|
except (OSError, ProviderConnectionError) as e:
|
|
102
87
|
if show_traceback:
|
|
@@ -105,55 +90,33 @@ class AsyncIPCProvider(PersistentConnectionProvider):
|
|
|
105
90
|
)
|
|
106
91
|
return False
|
|
107
92
|
|
|
108
|
-
async def
|
|
109
|
-
self._reader, self._writer = await async_get_ipc_socket(self.ipc_path)
|
|
110
|
-
|
|
111
|
-
async def _provider_specific_disconnect(self) -> None:
|
|
112
|
-
if self._writer and not self._writer.is_closing():
|
|
113
|
-
self._writer.close()
|
|
114
|
-
await self._writer.wait_closed()
|
|
115
|
-
self._writer = None
|
|
116
|
-
if self._reader:
|
|
117
|
-
self._reader = None
|
|
118
|
-
|
|
119
|
-
async def _reset_socket(self) -> None:
|
|
120
|
-
self._writer.close()
|
|
121
|
-
await self._writer.wait_closed()
|
|
122
|
-
self._reader, self._writer = await async_get_ipc_socket(self.ipc_path)
|
|
123
|
-
|
|
124
|
-
@async_handle_request_caching
|
|
125
|
-
async def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
|
|
93
|
+
async def socket_send(self, request_data: bytes) -> None:
|
|
126
94
|
if self._writer is None:
|
|
127
95
|
raise ProviderConnectionError(
|
|
128
96
|
"Connection to ipc socket has not been initiated for the provider."
|
|
129
97
|
)
|
|
130
98
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
await self._writer.drain()
|
|
135
|
-
except OSError as e:
|
|
136
|
-
# Broken pipe
|
|
137
|
-
if e.errno == errno.EPIPE:
|
|
138
|
-
# one extra attempt, then give up
|
|
139
|
-
await self._reset_socket()
|
|
140
|
-
self._writer.write(request_data)
|
|
141
|
-
await self._writer.drain()
|
|
99
|
+
return await asyncio.wait_for(
|
|
100
|
+
self._socket_send(request_data), timeout=self.request_timeout
|
|
101
|
+
)
|
|
142
102
|
|
|
143
|
-
|
|
144
|
-
|
|
103
|
+
async def socket_recv(self) -> RPCResponse:
|
|
104
|
+
while True:
|
|
105
|
+
# yield to the event loop to allow other tasks to run
|
|
106
|
+
await asyncio.sleep(0)
|
|
145
107
|
|
|
146
|
-
|
|
108
|
+
try:
|
|
109
|
+
response, pos = self._decoder.raw_decode(self._raw_message)
|
|
110
|
+
self._raw_message = self._raw_message[pos:].lstrip()
|
|
111
|
+
return response
|
|
112
|
+
except JSONDecodeError:
|
|
113
|
+
# read more data from the socket if the current raw message is
|
|
114
|
+
# incomplete
|
|
115
|
+
self._raw_message += to_text(await self._reader.read(4096)).lstrip()
|
|
147
116
|
|
|
148
|
-
|
|
149
|
-
self, requests: List[Tuple[RPCEndpoint, Any]]
|
|
150
|
-
) -> List[RPCResponse]:
|
|
151
|
-
if self._writer is None:
|
|
152
|
-
raise ProviderConnectionError(
|
|
153
|
-
"Connection to ipc socket has not been initiated for the provider."
|
|
154
|
-
)
|
|
117
|
+
# -- private methods -- #
|
|
155
118
|
|
|
156
|
-
|
|
119
|
+
async def _socket_send(self, request_data: bytes) -> None:
|
|
157
120
|
try:
|
|
158
121
|
self._writer.write(request_data)
|
|
159
122
|
await self._writer.drain()
|
|
@@ -165,32 +128,24 @@ class AsyncIPCProvider(PersistentConnectionProvider):
|
|
|
165
128
|
self._writer.write(request_data)
|
|
166
129
|
await self._writer.drain()
|
|
167
130
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
)
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
async def _provider_specific_message_listener(self) -> None:
|
|
174
|
-
self._raw_message += to_text(await self._reader.read(4096)).lstrip()
|
|
131
|
+
async def _reset_socket(self) -> None:
|
|
132
|
+
self._writer.close()
|
|
133
|
+
await self._writer.wait_closed()
|
|
134
|
+
self._reader, self._writer = await async_get_ipc_socket(self.ipc_path)
|
|
175
135
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
response, pos = self._decoder.raw_decode(self._raw_message)
|
|
179
|
-
except JSONDecodeError:
|
|
180
|
-
break
|
|
136
|
+
async def _provider_specific_connect(self) -> None:
|
|
137
|
+
self._reader, self._writer = await async_get_ipc_socket(self.ipc_path)
|
|
181
138
|
|
|
182
|
-
|
|
183
|
-
|
|
139
|
+
async def _provider_specific_disconnect(self) -> None:
|
|
140
|
+
if self._writer and not self._writer.is_closing():
|
|
141
|
+
self._writer.close()
|
|
142
|
+
await self._writer.wait_closed()
|
|
143
|
+
self._writer = None
|
|
144
|
+
if self._reader:
|
|
145
|
+
self._reader = None
|
|
184
146
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
if not isinstance(response, list)
|
|
188
|
-
else False
|
|
189
|
-
)
|
|
190
|
-
await self._request_processor.cache_raw_response(
|
|
191
|
-
response, subscription=is_subscription
|
|
192
|
-
)
|
|
193
|
-
self._raw_message = self._raw_message[pos:].lstrip()
|
|
147
|
+
async def _provider_specific_socket_reader(self) -> RPCResponse:
|
|
148
|
+
return await self.socket_recv()
|
|
194
149
|
|
|
195
150
|
def _error_log_listener_task_exception(self, e: Exception) -> None:
|
|
196
151
|
super()._error_log_listener_task_exception(e)
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
from abc import (
|
|
2
2
|
ABC,
|
|
3
|
+
abstractmethod,
|
|
3
4
|
)
|
|
4
5
|
import asyncio
|
|
6
|
+
import json
|
|
5
7
|
import logging
|
|
6
8
|
from typing import (
|
|
7
9
|
Any,
|
|
8
10
|
List,
|
|
9
11
|
Optional,
|
|
12
|
+
Tuple,
|
|
10
13
|
Union,
|
|
14
|
+
cast,
|
|
11
15
|
)
|
|
12
16
|
|
|
13
17
|
from websockets import (
|
|
@@ -15,13 +19,20 @@ from websockets import (
|
|
|
15
19
|
WebSocketException,
|
|
16
20
|
)
|
|
17
21
|
|
|
22
|
+
from web3._utils.batching import (
|
|
23
|
+
BATCH_REQUEST_ID,
|
|
24
|
+
sort_batch_response_by_response_ids,
|
|
25
|
+
)
|
|
18
26
|
from web3._utils.caching import (
|
|
27
|
+
async_handle_request_caching,
|
|
19
28
|
generate_cache_key,
|
|
20
29
|
)
|
|
21
30
|
from web3.exceptions import (
|
|
31
|
+
PersistentConnectionClosedOK,
|
|
22
32
|
ProviderConnectionError,
|
|
23
33
|
TaskNotRunning,
|
|
24
34
|
TimeExhausted,
|
|
35
|
+
Web3AttributeError,
|
|
25
36
|
)
|
|
26
37
|
from web3.providers.async_base import (
|
|
27
38
|
AsyncJSONBaseProvider,
|
|
@@ -30,6 +41,7 @@ from web3.providers.persistent.request_processor import (
|
|
|
30
41
|
RequestProcessor,
|
|
31
42
|
)
|
|
32
43
|
from web3.types import (
|
|
44
|
+
RPCEndpoint,
|
|
33
45
|
RPCId,
|
|
34
46
|
RPCResponse,
|
|
35
47
|
)
|
|
@@ -70,7 +82,7 @@ class PersistentConnectionProvider(AsyncJSONBaseProvider, ABC):
|
|
|
70
82
|
elif hasattr(self, "ipc_path"):
|
|
71
83
|
return str(self.ipc_path)
|
|
72
84
|
else:
|
|
73
|
-
raise
|
|
85
|
+
raise Web3AttributeError(
|
|
74
86
|
"`PersistentConnectionProvider` must have either `endpoint_uri` or "
|
|
75
87
|
"`ipc_path` attribute."
|
|
76
88
|
)
|
|
@@ -128,6 +140,44 @@ class PersistentConnectionProvider(AsyncJSONBaseProvider, ABC):
|
|
|
128
140
|
f"Successfully disconnected from: {self.get_endpoint_uri_or_ipc_path()}"
|
|
129
141
|
)
|
|
130
142
|
|
|
143
|
+
@async_handle_request_caching
|
|
144
|
+
async def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
|
|
145
|
+
request_data = self.encode_rpc_request(method, params)
|
|
146
|
+
await self.socket_send(request_data)
|
|
147
|
+
|
|
148
|
+
current_request_id = json.loads(request_data)["id"]
|
|
149
|
+
response = await self._get_response_for_request_id(current_request_id)
|
|
150
|
+
|
|
151
|
+
return response
|
|
152
|
+
|
|
153
|
+
async def make_batch_request(
|
|
154
|
+
self, requests: List[Tuple[RPCEndpoint, Any]]
|
|
155
|
+
) -> List[RPCResponse]:
|
|
156
|
+
request_data = self.encode_batch_rpc_request(requests)
|
|
157
|
+
await self.socket_send(request_data)
|
|
158
|
+
|
|
159
|
+
response = cast(
|
|
160
|
+
List[RPCResponse], await self._get_response_for_request_id(BATCH_REQUEST_ID)
|
|
161
|
+
)
|
|
162
|
+
return response
|
|
163
|
+
|
|
164
|
+
# -- abstract methods -- #
|
|
165
|
+
|
|
166
|
+
@abstractmethod
|
|
167
|
+
async def socket_send(self, request_data: bytes) -> None:
|
|
168
|
+
"""
|
|
169
|
+
Send an encoded RPC request to the provider over the persistent connection.
|
|
170
|
+
"""
|
|
171
|
+
raise NotImplementedError("Must be implemented by subclasses")
|
|
172
|
+
|
|
173
|
+
@abstractmethod
|
|
174
|
+
async def socket_recv(self) -> RPCResponse:
|
|
175
|
+
"""
|
|
176
|
+
Receive, decode, and return an RPC response from the provider over the
|
|
177
|
+
persistent connection.
|
|
178
|
+
"""
|
|
179
|
+
raise NotImplementedError("Must be implemented by subclasses")
|
|
180
|
+
|
|
131
181
|
# -- private methods -- #
|
|
132
182
|
|
|
133
183
|
async def _provider_specific_connect(self) -> None:
|
|
@@ -136,7 +186,7 @@ class PersistentConnectionProvider(AsyncJSONBaseProvider, ABC):
|
|
|
136
186
|
async def _provider_specific_disconnect(self) -> None:
|
|
137
187
|
raise NotImplementedError("Must be implemented by subclasses")
|
|
138
188
|
|
|
139
|
-
async def
|
|
189
|
+
async def _provider_specific_socket_reader(self) -> RPCResponse:
|
|
140
190
|
raise NotImplementedError("Must be implemented by subclasses")
|
|
141
191
|
|
|
142
192
|
def _message_listener_callback(
|
|
@@ -158,8 +208,28 @@ class PersistentConnectionProvider(AsyncJSONBaseProvider, ABC):
|
|
|
158
208
|
# the use of sleep(0) seems to be the most efficient way to yield control
|
|
159
209
|
# back to the event loop to share the loop with other tasks.
|
|
160
210
|
await asyncio.sleep(0)
|
|
211
|
+
|
|
161
212
|
try:
|
|
162
|
-
await self.
|
|
213
|
+
response = await self._provider_specific_socket_reader()
|
|
214
|
+
|
|
215
|
+
if isinstance(response, list):
|
|
216
|
+
response = sort_batch_response_by_response_ids(response)
|
|
217
|
+
|
|
218
|
+
subscription = (
|
|
219
|
+
response.get("method") == "eth_subscription"
|
|
220
|
+
if not isinstance(response, list)
|
|
221
|
+
else False
|
|
222
|
+
)
|
|
223
|
+
await self._request_processor.cache_raw_response(
|
|
224
|
+
response, subscription=subscription
|
|
225
|
+
)
|
|
226
|
+
except PersistentConnectionClosedOK as e:
|
|
227
|
+
self.logger.info(
|
|
228
|
+
"Message listener background task has ended gracefully: "
|
|
229
|
+
f"{e.user_message}"
|
|
230
|
+
)
|
|
231
|
+
# trigger a return to end the listener task and initiate the callback fn
|
|
232
|
+
return
|
|
163
233
|
except Exception as e:
|
|
164
234
|
if not self.silence_listener_task_exceptions:
|
|
165
235
|
raise e
|
|
@@ -202,10 +272,6 @@ class PersistentConnectionProvider(AsyncJSONBaseProvider, ABC):
|
|
|
202
272
|
request_cache_key = generate_cache_key(request_id)
|
|
203
273
|
|
|
204
274
|
while True:
|
|
205
|
-
# check if an exception was recorded in the listener task and raise it
|
|
206
|
-
# in the main loop if so
|
|
207
|
-
self._handle_listener_task_exceptions()
|
|
208
|
-
|
|
209
275
|
if request_cache_key in self._request_processor._request_response_cache:
|
|
210
276
|
self.logger.debug(
|
|
211
277
|
f"Popping response for id {request_id} from cache."
|
|
@@ -215,6 +281,9 @@ class PersistentConnectionProvider(AsyncJSONBaseProvider, ABC):
|
|
|
215
281
|
)
|
|
216
282
|
return popped_response
|
|
217
283
|
else:
|
|
284
|
+
# check if an exception was recorded in the listener task and raise
|
|
285
|
+
# it in the main loop if so
|
|
286
|
+
self._handle_listener_task_exceptions()
|
|
218
287
|
await asyncio.sleep(0)
|
|
219
288
|
|
|
220
289
|
try:
|
|
@@ -27,16 +27,58 @@ class PersistentConnection:
|
|
|
27
27
|
def __init__(self, w3: "AsyncWeb3"):
|
|
28
28
|
self._manager = w3.manager
|
|
29
29
|
|
|
30
|
-
# -- public methods -- #
|
|
31
30
|
@property
|
|
32
31
|
def subscriptions(self) -> Dict[str, Any]:
|
|
32
|
+
"""
|
|
33
|
+
Return the active subscriptions on the persistent connection.
|
|
34
|
+
|
|
35
|
+
:return: The active subscriptions on the persistent connection.
|
|
36
|
+
:rtype: Dict[str, Any]
|
|
37
|
+
"""
|
|
33
38
|
return self._manager._request_processor.active_subscriptions
|
|
34
39
|
|
|
35
|
-
async def
|
|
36
|
-
|
|
40
|
+
async def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
|
|
41
|
+
"""
|
|
42
|
+
Make a request to the persistent connection and return the response. This method
|
|
43
|
+
does not process the response as it would when invoking a method via the
|
|
44
|
+
appropriate module on the `AsyncWeb3` instance,
|
|
45
|
+
e.g. `w3.eth.get_block("latest")`.
|
|
46
|
+
|
|
47
|
+
:param method: The RPC method, e.g. `eth_getBlockByNumber`.
|
|
48
|
+
:param params: The RPC method parameters, e.g. `["0x1337", False]`.
|
|
49
|
+
|
|
50
|
+
:return: The processed response from the persistent connection.
|
|
51
|
+
:rtype: RPCResponse
|
|
52
|
+
"""
|
|
53
|
+
return await self._manager.socket_request(method, params)
|
|
54
|
+
|
|
55
|
+
async def send(self, method: RPCEndpoint, params: Any) -> None:
|
|
56
|
+
"""
|
|
57
|
+
Send a raw, unprocessed message to the persistent connection.
|
|
37
58
|
|
|
38
|
-
|
|
39
|
-
|
|
59
|
+
:param method: The RPC method, e.g. `eth_getBlockByNumber`.
|
|
60
|
+
:param params: The RPC method parameters, e.g. `["0x1337", False]`.
|
|
61
|
+
|
|
62
|
+
:return: None
|
|
63
|
+
"""
|
|
64
|
+
await self._manager.send(method, params)
|
|
65
|
+
|
|
66
|
+
async def recv(self) -> RPCResponse:
|
|
67
|
+
"""
|
|
68
|
+
Receive the next unprocessed response for a request from the persistent
|
|
69
|
+
connection.
|
|
70
|
+
|
|
71
|
+
:return: The next unprocessed response for a request from the persistent
|
|
72
|
+
connection.
|
|
73
|
+
:rtype: RPCResponse
|
|
74
|
+
"""
|
|
75
|
+
return await self._manager.recv()
|
|
40
76
|
|
|
41
77
|
def process_subscriptions(self) -> "_AsyncPersistentMessageStream":
|
|
78
|
+
"""
|
|
79
|
+
Asynchronous iterator that yields messages from the subscription message stream.
|
|
80
|
+
|
|
81
|
+
:return: The subscription message stream.
|
|
82
|
+
:rtype: _AsyncPersistentMessageStream
|
|
83
|
+
"""
|
|
42
84
|
return self._manager._persistent_message_stream()
|
|
@@ -5,11 +5,8 @@ import os
|
|
|
5
5
|
from typing import (
|
|
6
6
|
Any,
|
|
7
7
|
Dict,
|
|
8
|
-
List,
|
|
9
8
|
Optional,
|
|
10
|
-
Tuple,
|
|
11
9
|
Union,
|
|
12
|
-
cast,
|
|
13
10
|
)
|
|
14
11
|
|
|
15
12
|
from eth_typing import (
|
|
@@ -25,17 +22,12 @@ from websockets.client import (
|
|
|
25
22
|
connect,
|
|
26
23
|
)
|
|
27
24
|
from websockets.exceptions import (
|
|
25
|
+
ConnectionClosedOK,
|
|
28
26
|
WebSocketException,
|
|
29
27
|
)
|
|
30
28
|
|
|
31
|
-
from web3._utils.batching import (
|
|
32
|
-
BATCH_REQUEST_ID,
|
|
33
|
-
sort_batch_response_by_response_ids,
|
|
34
|
-
)
|
|
35
|
-
from web3._utils.caching import (
|
|
36
|
-
async_handle_request_caching,
|
|
37
|
-
)
|
|
38
29
|
from web3.exceptions import (
|
|
30
|
+
PersistentConnectionClosedOK,
|
|
39
31
|
ProviderConnectionError,
|
|
40
32
|
Web3ValidationError,
|
|
41
33
|
)
|
|
@@ -43,7 +35,6 @@ from web3.providers.persistent import (
|
|
|
43
35
|
PersistentConnectionProvider,
|
|
44
36
|
)
|
|
45
37
|
from web3.types import (
|
|
46
|
-
RPCEndpoint,
|
|
47
38
|
RPCResponse,
|
|
48
39
|
)
|
|
49
40
|
|
|
@@ -122,18 +113,7 @@ class WebSocketProvider(PersistentConnectionProvider):
|
|
|
122
113
|
) from e
|
|
123
114
|
return False
|
|
124
115
|
|
|
125
|
-
async def
|
|
126
|
-
self._ws = await connect(self.endpoint_uri, **self.websocket_kwargs)
|
|
127
|
-
|
|
128
|
-
async def _provider_specific_disconnect(self) -> None:
|
|
129
|
-
if self._ws is not None and not self._ws.closed:
|
|
130
|
-
await self._ws.close()
|
|
131
|
-
self._ws = None
|
|
132
|
-
|
|
133
|
-
@async_handle_request_caching
|
|
134
|
-
async def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
|
|
135
|
-
request_data = self.encode_rpc_request(method, params)
|
|
136
|
-
|
|
116
|
+
async def socket_send(self, request_data: bytes) -> None:
|
|
137
117
|
if self._ws is None:
|
|
138
118
|
raise ProviderConnectionError(
|
|
139
119
|
"Connection to websocket has not been initiated for the provider."
|
|
@@ -143,44 +123,24 @@ class WebSocketProvider(PersistentConnectionProvider):
|
|
|
143
123
|
self._ws.send(request_data), timeout=self.request_timeout
|
|
144
124
|
)
|
|
145
125
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
return response
|
|
126
|
+
async def socket_recv(self) -> RPCResponse:
|
|
127
|
+
raw_response = await self._ws.recv()
|
|
128
|
+
return json.loads(raw_response)
|
|
150
129
|
|
|
151
|
-
|
|
152
|
-
self, requests: List[Tuple[RPCEndpoint, Any]]
|
|
153
|
-
) -> List[RPCResponse]:
|
|
154
|
-
request_data = self.encode_batch_rpc_request(requests)
|
|
130
|
+
# -- private methods -- #
|
|
155
131
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
"Connection to websocket has not been initiated for the provider."
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
await asyncio.wait_for(
|
|
162
|
-
self._ws.send(request_data), timeout=self.request_timeout
|
|
163
|
-
)
|
|
164
|
-
|
|
165
|
-
response = cast(
|
|
166
|
-
List[RPCResponse],
|
|
167
|
-
await self._get_response_for_request_id(BATCH_REQUEST_ID),
|
|
168
|
-
)
|
|
169
|
-
return response
|
|
170
|
-
|
|
171
|
-
async def _provider_specific_message_listener(self) -> None:
|
|
172
|
-
async for raw_message in self._ws:
|
|
173
|
-
await asyncio.sleep(0)
|
|
132
|
+
async def _provider_specific_connect(self) -> None:
|
|
133
|
+
self._ws = await connect(self.endpoint_uri, **self.websocket_kwargs)
|
|
174
134
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
135
|
+
async def _provider_specific_disconnect(self) -> None:
|
|
136
|
+
if self._ws is not None and not self._ws.closed:
|
|
137
|
+
await self._ws.close()
|
|
138
|
+
self._ws = None
|
|
178
139
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
response, subscription=subscription
|
|
140
|
+
async def _provider_specific_socket_reader(self) -> RPCResponse:
|
|
141
|
+
try:
|
|
142
|
+
return await self.socket_recv()
|
|
143
|
+
except ConnectionClosedOK:
|
|
144
|
+
raise PersistentConnectionClosedOK(
|
|
145
|
+
user_message="WebSocket connection received `ConnectionClosedOK`."
|
|
186
146
|
)
|
web3/providers/rpc/__init__.py
CHANGED
web3/providers/rpc/async_rpc.py
CHANGED
|
@@ -29,11 +29,6 @@ from web3._utils.empty import (
|
|
|
29
29
|
from web3._utils.http import (
|
|
30
30
|
construct_user_agent,
|
|
31
31
|
)
|
|
32
|
-
from web3._utils.request import (
|
|
33
|
-
async_cache_and_return_session as _async_cache_and_return_session,
|
|
34
|
-
async_make_post_request,
|
|
35
|
-
get_default_http_endpoint,
|
|
36
|
-
)
|
|
37
32
|
from web3.types import (
|
|
38
33
|
RPCEndpoint,
|
|
39
34
|
RPCResponse,
|
|
@@ -45,6 +40,9 @@ from ..._utils.batching import (
|
|
|
45
40
|
from ..._utils.caching import (
|
|
46
41
|
async_handle_request_caching,
|
|
47
42
|
)
|
|
43
|
+
from ..._utils.http_session_manager import (
|
|
44
|
+
HTTPSessionManager,
|
|
45
|
+
)
|
|
48
46
|
from ..async_base import (
|
|
49
47
|
AsyncJSONBaseProvider,
|
|
50
48
|
)
|
|
@@ -63,13 +61,17 @@ class AsyncHTTPProvider(AsyncJSONBaseProvider):
|
|
|
63
61
|
self,
|
|
64
62
|
endpoint_uri: Optional[Union[URI, str]] = None,
|
|
65
63
|
request_kwargs: Optional[Any] = None,
|
|
66
|
-
exception_retry_configuration:
|
|
67
|
-
ExceptionRetryConfiguration, Empty
|
|
64
|
+
exception_retry_configuration: Optional[
|
|
65
|
+
Union[ExceptionRetryConfiguration, Empty]
|
|
68
66
|
] = empty,
|
|
69
67
|
**kwargs: Any,
|
|
70
68
|
) -> None:
|
|
69
|
+
self._request_session_manager = HTTPSessionManager()
|
|
70
|
+
|
|
71
71
|
if endpoint_uri is None:
|
|
72
|
-
self.endpoint_uri =
|
|
72
|
+
self.endpoint_uri = (
|
|
73
|
+
self._request_session_manager.get_default_http_endpoint()
|
|
74
|
+
)
|
|
73
75
|
else:
|
|
74
76
|
self.endpoint_uri = URI(endpoint_uri)
|
|
75
77
|
|
|
@@ -79,7 +81,9 @@ class AsyncHTTPProvider(AsyncJSONBaseProvider):
|
|
|
79
81
|
super().__init__(**kwargs)
|
|
80
82
|
|
|
81
83
|
async def cache_async_session(self, session: ClientSession) -> ClientSession:
|
|
82
|
-
return await
|
|
84
|
+
return await self._request_session_manager.async_cache_and_return_session(
|
|
85
|
+
self.endpoint_uri, session
|
|
86
|
+
)
|
|
83
87
|
|
|
84
88
|
def __str__(self) -> str:
|
|
85
89
|
return f"RPC connection {self.endpoint_uri}"
|
|
@@ -123,7 +127,7 @@ class AsyncHTTPProvider(AsyncJSONBaseProvider):
|
|
|
123
127
|
):
|
|
124
128
|
for i in range(self.exception_retry_configuration.retries):
|
|
125
129
|
try:
|
|
126
|
-
return await async_make_post_request(
|
|
130
|
+
return await self._request_session_manager.async_make_post_request(
|
|
127
131
|
self.endpoint_uri, request_data, **self.get_request_kwargs()
|
|
128
132
|
)
|
|
129
133
|
except tuple(self.exception_retry_configuration.errors):
|
|
@@ -136,7 +140,7 @@ class AsyncHTTPProvider(AsyncJSONBaseProvider):
|
|
|
136
140
|
raise
|
|
137
141
|
return None
|
|
138
142
|
else:
|
|
139
|
-
return await async_make_post_request(
|
|
143
|
+
return await self._request_session_manager.async_make_post_request(
|
|
140
144
|
self.endpoint_uri, request_data, **self.get_request_kwargs()
|
|
141
145
|
)
|
|
142
146
|
|
|
@@ -159,7 +163,7 @@ class AsyncHTTPProvider(AsyncJSONBaseProvider):
|
|
|
159
163
|
) -> List[RPCResponse]:
|
|
160
164
|
self.logger.debug(f"Making batch request HTTP - uri: `{self.endpoint_uri}`")
|
|
161
165
|
request_data = self.encode_batch_rpc_request(batch_requests)
|
|
162
|
-
raw_response = await async_make_post_request(
|
|
166
|
+
raw_response = await self._request_session_manager.async_make_post_request(
|
|
163
167
|
self.endpoint_uri, request_data, **self.get_request_kwargs()
|
|
164
168
|
)
|
|
165
169
|
self.logger.debug("Received batch response HTTP.")
|
web3/providers/rpc/rpc.py
CHANGED
|
@@ -27,11 +27,6 @@ from web3._utils.empty import (
|
|
|
27
27
|
from web3._utils.http import (
|
|
28
28
|
construct_user_agent,
|
|
29
29
|
)
|
|
30
|
-
from web3._utils.request import (
|
|
31
|
-
cache_and_return_session,
|
|
32
|
-
get_default_http_endpoint,
|
|
33
|
-
make_post_request,
|
|
34
|
-
)
|
|
35
30
|
from web3.types import (
|
|
36
31
|
RPCEndpoint,
|
|
37
32
|
RPCResponse,
|
|
@@ -43,6 +38,9 @@ from ..._utils.batching import (
|
|
|
43
38
|
from ..._utils.caching import (
|
|
44
39
|
handle_request_caching,
|
|
45
40
|
)
|
|
41
|
+
from ..._utils.http_session_manager import (
|
|
42
|
+
HTTPSessionManager,
|
|
43
|
+
)
|
|
46
44
|
from ..base import (
|
|
47
45
|
JSONBaseProvider,
|
|
48
46
|
)
|
|
@@ -67,13 +65,17 @@ class HTTPProvider(JSONBaseProvider):
|
|
|
67
65
|
endpoint_uri: Optional[Union[URI, str]] = None,
|
|
68
66
|
request_kwargs: Optional[Any] = None,
|
|
69
67
|
session: Optional[Any] = None,
|
|
70
|
-
exception_retry_configuration:
|
|
71
|
-
ExceptionRetryConfiguration, Empty
|
|
68
|
+
exception_retry_configuration: Optional[
|
|
69
|
+
Union[ExceptionRetryConfiguration, Empty]
|
|
72
70
|
] = empty,
|
|
73
71
|
**kwargs: Any,
|
|
74
72
|
) -> None:
|
|
73
|
+
self._request_session_manager = HTTPSessionManager()
|
|
74
|
+
|
|
75
75
|
if endpoint_uri is None:
|
|
76
|
-
self.endpoint_uri =
|
|
76
|
+
self.endpoint_uri = (
|
|
77
|
+
self._request_session_manager.get_default_http_endpoint()
|
|
78
|
+
)
|
|
77
79
|
else:
|
|
78
80
|
self.endpoint_uri = URI(endpoint_uri)
|
|
79
81
|
|
|
@@ -81,7 +83,9 @@ class HTTPProvider(JSONBaseProvider):
|
|
|
81
83
|
self._exception_retry_configuration = exception_retry_configuration
|
|
82
84
|
|
|
83
85
|
if session:
|
|
84
|
-
cache_and_return_session(
|
|
86
|
+
self._request_session_manager.cache_and_return_session(
|
|
87
|
+
self.endpoint_uri, session
|
|
88
|
+
)
|
|
85
89
|
|
|
86
90
|
super().__init__(**kwargs)
|
|
87
91
|
|
|
@@ -131,7 +135,7 @@ class HTTPProvider(JSONBaseProvider):
|
|
|
131
135
|
):
|
|
132
136
|
for i in range(self.exception_retry_configuration.retries):
|
|
133
137
|
try:
|
|
134
|
-
return make_post_request(
|
|
138
|
+
return self._request_session_manager.make_post_request(
|
|
135
139
|
self.endpoint_uri, request_data, **self.get_request_kwargs()
|
|
136
140
|
)
|
|
137
141
|
except tuple(self.exception_retry_configuration.errors) as e:
|
|
@@ -144,7 +148,7 @@ class HTTPProvider(JSONBaseProvider):
|
|
|
144
148
|
raise e
|
|
145
149
|
return None
|
|
146
150
|
else:
|
|
147
|
-
return make_post_request(
|
|
151
|
+
return self._request_session_manager.make_post_request(
|
|
148
152
|
self.endpoint_uri, request_data, **self.get_request_kwargs()
|
|
149
153
|
)
|
|
150
154
|
|
|
@@ -167,7 +171,7 @@ class HTTPProvider(JSONBaseProvider):
|
|
|
167
171
|
) -> List[RPCResponse]:
|
|
168
172
|
self.logger.debug(f"Making batch request HTTP, uri: `{self.endpoint_uri}`")
|
|
169
173
|
request_data = self.encode_batch_rpc_request(batch_requests)
|
|
170
|
-
raw_response = make_post_request(
|
|
174
|
+
raw_response = self._request_session_manager.make_post_request(
|
|
171
175
|
self.endpoint_uri, request_data, **self.get_request_kwargs()
|
|
172
176
|
)
|
|
173
177
|
self.logger.debug("Received batch response HTTP.")
|