web3 7.0.0b1__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.
- ens/__init__.py +13 -2
- ens/_normalization.py +4 -4
- ens/async_ens.py +31 -21
- ens/base_ens.py +3 -1
- ens/contract_data.py +2 -2
- ens/ens.py +14 -11
- ens/exceptions.py +16 -29
- ens/specs/nf.json +1 -1
- ens/specs/normalization_spec.json +1 -1
- ens/utils.py +33 -41
- web3/__init__.py +23 -12
- web3/_utils/abi.py +162 -274
- web3/_utils/async_transactions.py +34 -20
- web3/_utils/batching.py +217 -0
- web3/_utils/blocks.py +6 -2
- web3/_utils/caching/__init__.py +12 -0
- web3/_utils/caching/caching_utils.py +433 -0
- web3/_utils/caching/request_caching_validation.py +287 -0
- web3/_utils/compat/__init__.py +2 -3
- web3/_utils/contract_sources/compile_contracts.py +1 -1
- web3/_utils/contract_sources/contract_data/ambiguous_function_contract.py +42 -0
- 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 +50 -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/contracts.py +172 -220
- web3/_utils/datatypes.py +5 -1
- web3/_utils/decorators.py +6 -1
- web3/_utils/empty.py +1 -1
- web3/_utils/encoding.py +16 -12
- web3/_utils/error_formatters_utils.py +5 -3
- web3/_utils/events.py +78 -72
- web3/_utils/fee_utils.py +1 -3
- web3/_utils/filters.py +24 -22
- web3/_utils/formatters.py +2 -2
- web3/_utils/http.py +8 -2
- web3/_utils/http_session_manager.py +314 -0
- web3/_utils/math.py +14 -15
- web3/_utils/method_formatters.py +161 -34
- web3/_utils/module.py +2 -1
- web3/_utils/module_testing/__init__.py +3 -2
- web3/_utils/module_testing/eth_module.py +736 -583
- web3/_utils/module_testing/go_ethereum_debug_module.py +128 -0
- web3/_utils/module_testing/module_testing_utils.py +81 -24
- web3/_utils/module_testing/persistent_connection_provider.py +702 -220
- web3/_utils/module_testing/utils.py +114 -33
- web3/_utils/module_testing/web3_module.py +438 -17
- web3/_utils/normalizers.py +13 -11
- web3/_utils/rpc_abi.py +10 -22
- web3/_utils/threads.py +8 -7
- web3/_utils/transactions.py +32 -25
- web3/_utils/type_conversion.py +5 -1
- web3/_utils/validation.py +20 -17
- web3/beacon/__init__.py +5 -0
- web3/beacon/api_endpoints.py +3 -0
- web3/beacon/async_beacon.py +29 -6
- web3/beacon/beacon.py +24 -6
- web3/contract/__init__.py +7 -0
- web3/contract/async_contract.py +285 -82
- web3/contract/base_contract.py +556 -258
- web3/contract/contract.py +295 -84
- web3/contract/utils.py +251 -55
- web3/datastructures.py +56 -41
- web3/eth/__init__.py +7 -0
- web3/eth/async_eth.py +89 -69
- web3/eth/base_eth.py +7 -3
- web3/eth/eth.py +43 -66
- web3/exceptions.py +158 -83
- web3/gas_strategies/time_based.py +8 -6
- web3/geth.py +53 -184
- web3/main.py +77 -43
- web3/manager.py +368 -101
- web3/method.py +43 -15
- web3/middleware/__init__.py +26 -8
- web3/middleware/attrdict.py +12 -22
- web3/middleware/base.py +55 -2
- web3/middleware/filter.py +45 -23
- web3/middleware/formatting.py +6 -3
- web3/middleware/names.py +4 -1
- web3/middleware/signing.py +15 -6
- web3/middleware/stalecheck.py +2 -1
- web3/module.py +62 -26
- web3/providers/__init__.py +21 -0
- web3/providers/async_base.py +93 -38
- web3/providers/base.py +85 -40
- web3/providers/eth_tester/__init__.py +5 -0
- web3/providers/eth_tester/defaults.py +2 -55
- web3/providers/eth_tester/main.py +57 -35
- web3/providers/eth_tester/middleware.py +16 -17
- web3/providers/ipc.py +42 -18
- web3/providers/legacy_websocket.py +27 -2
- web3/providers/persistent/__init__.py +7 -0
- web3/providers/persistent/async_ipc.py +61 -121
- web3/providers/persistent/persistent.py +324 -17
- web3/providers/persistent/persistent_connection.py +54 -5
- web3/providers/persistent/request_processor.py +136 -56
- web3/providers/persistent/subscription_container.py +56 -0
- web3/providers/persistent/subscription_manager.py +233 -0
- web3/providers/persistent/websocket.py +29 -92
- web3/providers/rpc/__init__.py +5 -0
- web3/providers/rpc/async_rpc.py +73 -18
- web3/providers/rpc/rpc.py +73 -30
- web3/providers/rpc/utils.py +1 -13
- web3/scripts/install_pre_releases.py +33 -0
- web3/scripts/parse_pygeth_version.py +16 -0
- web3/testing.py +4 -4
- web3/tracing.py +9 -5
- web3/types.py +141 -74
- web3/utils/__init__.py +64 -5
- web3/utils/abi.py +790 -10
- web3/utils/address.py +8 -0
- web3/utils/async_exception_handling.py +20 -11
- web3/utils/caching.py +34 -4
- web3/utils/exception_handling.py +9 -12
- web3/utils/subscriptions.py +285 -0
- {web3-7.0.0b1.dist-info → web3-7.7.0.dist-info}/LICENSE +1 -1
- web3-7.7.0.dist-info/METADATA +130 -0
- web3-7.7.0.dist-info/RECORD +171 -0
- {web3-7.0.0b1.dist-info → web3-7.7.0.dist-info}/WHEEL +1 -1
- {web3-7.0.0b1.dist-info → web3-7.7.0.dist-info}/top_level.txt +0 -1
- ethpm/__init__.py +0 -20
- ethpm/_utils/__init__.py +0 -0
- ethpm/_utils/backend.py +0 -93
- ethpm/_utils/cache.py +0 -44
- ethpm/_utils/chains.py +0 -119
- ethpm/_utils/contract.py +0 -35
- ethpm/_utils/deployments.py +0 -145
- ethpm/_utils/ipfs.py +0 -116
- ethpm/_utils/protobuf/__init__.py +0 -0
- ethpm/_utils/protobuf/ipfs_file_pb2.py +0 -33
- ethpm/_utils/registry.py +0 -29
- ethpm/assets/__init__.py +0 -0
- ethpm/assets/ens/v3.json +0 -1
- ethpm/assets/escrow/with_bytecode_v3.json +0 -1
- ethpm/assets/ipfs_file.proto +0 -32
- ethpm/assets/owned/output_v3.json +0 -1
- ethpm/assets/owned/with_contract_type_v3.json +0 -1
- ethpm/assets/registry/contracts/Authority.sol +0 -156
- ethpm/assets/registry/contracts/IndexedOrderedSetLib.sol +0 -106
- ethpm/assets/registry/contracts/PackageDB.sol +0 -225
- ethpm/assets/registry/contracts/PackageRegistry.sol +0 -361
- ethpm/assets/registry/contracts/PackageRegistryInterface.sol +0 -97
- ethpm/assets/registry/contracts/ReleaseDB.sol +0 -309
- ethpm/assets/registry/contracts/ReleaseValidator.sol +0 -152
- ethpm/assets/registry/solc_input.json +0 -1
- ethpm/assets/registry/solc_output.json +0 -1
- ethpm/assets/registry/v3.json +0 -1
- ethpm/assets/safe-math-lib/v3-strict-no-deployments.json +0 -1
- ethpm/assets/simple-registry/contracts/Ownable.sol +0 -63
- ethpm/assets/simple-registry/contracts/PackageRegistry.sol +0 -373
- ethpm/assets/simple-registry/contracts/PackageRegistryInterface.sol +0 -96
- ethpm/assets/simple-registry/solc_input.json +0 -33
- ethpm/assets/simple-registry/solc_output.json +0 -1
- ethpm/assets/simple-registry/v3.json +0 -1
- ethpm/assets/standard-token/output_v3.json +0 -1
- ethpm/assets/standard-token/with_bytecode_v3.json +0 -1
- ethpm/assets/vyper_registry/0.1.0.json +0 -1
- ethpm/assets/vyper_registry/registry.vy +0 -216
- ethpm/assets/vyper_registry/registry_with_delete.vy +0 -244
- ethpm/backends/__init__.py +0 -0
- ethpm/backends/base.py +0 -43
- ethpm/backends/http.py +0 -108
- ethpm/backends/ipfs.py +0 -219
- ethpm/backends/registry.py +0 -154
- ethpm/constants.py +0 -17
- ethpm/contract.py +0 -187
- ethpm/dependencies.py +0 -58
- ethpm/deployments.py +0 -80
- ethpm/ethpm-spec/examples/escrow/1.0.0-pretty.json +0 -146
- ethpm/ethpm-spec/examples/escrow/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/escrow/contracts/Escrow.sol +0 -32
- ethpm/ethpm-spec/examples/escrow/contracts/SafeSendLib.sol +0 -20
- ethpm/ethpm-spec/examples/escrow/v3-pretty.json +0 -171
- ethpm/ethpm-spec/examples/escrow/v3.json +0 -1
- ethpm/ethpm-spec/examples/owned/1.0.0-pretty.json +0 -21
- ethpm/ethpm-spec/examples/owned/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/owned/contracts/Owned.sol +0 -12
- ethpm/ethpm-spec/examples/owned/v3-pretty.json +0 -27
- ethpm/ethpm-spec/examples/owned/v3.json +0 -1
- ethpm/ethpm-spec/examples/piper-coin/1.0.0-pretty.json +0 -31
- ethpm/ethpm-spec/examples/piper-coin/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/piper-coin/v3-pretty.json +0 -21
- ethpm/ethpm-spec/examples/piper-coin/v3.json +0 -1
- ethpm/ethpm-spec/examples/safe-math-lib/1.0.0-pretty.json +0 -85
- ethpm/ethpm-spec/examples/safe-math-lib/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/safe-math-lib/contracts/SafeMathLib.sol +0 -24
- ethpm/ethpm-spec/examples/safe-math-lib/v3-pretty.json +0 -117
- ethpm/ethpm-spec/examples/safe-math-lib/v3.json +0 -1
- ethpm/ethpm-spec/examples/standard-token/1.0.0-pretty.json +0 -55
- ethpm/ethpm-spec/examples/standard-token/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/standard-token/contracts/AbstractToken.sol +0 -20
- ethpm/ethpm-spec/examples/standard-token/contracts/StandardToken.sol +0 -84
- ethpm/ethpm-spec/examples/standard-token/v3-pretty.json +0 -460
- ethpm/ethpm-spec/examples/standard-token/v3.json +0 -1
- ethpm/ethpm-spec/examples/transferable/1.0.0-pretty.json +0 -21
- ethpm/ethpm-spec/examples/transferable/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/transferable/contracts/Transferable.sol +0 -14
- ethpm/ethpm-spec/examples/transferable/v3-pretty.json +0 -27
- ethpm/ethpm-spec/examples/transferable/v3.json +0 -1
- ethpm/ethpm-spec/examples/wallet/1.0.0-pretty.json +0 -120
- ethpm/ethpm-spec/examples/wallet/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/wallet/contracts/Wallet.sol +0 -41
- ethpm/ethpm-spec/examples/wallet/v3-pretty.json +0 -181
- ethpm/ethpm-spec/examples/wallet/v3.json +0 -1
- ethpm/ethpm-spec/examples/wallet-with-send/1.0.0-pretty.json +0 -135
- ethpm/ethpm-spec/examples/wallet-with-send/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/wallet-with-send/contracts/WalletWithSend.sol +0 -18
- ethpm/ethpm-spec/examples/wallet-with-send/v3-pretty.json +0 -207
- ethpm/ethpm-spec/examples/wallet-with-send/v3.json +0 -1
- ethpm/ethpm-spec/spec/package.spec.json +0 -379
- ethpm/ethpm-spec/spec/v3.spec.json +0 -483
- ethpm/exceptions.py +0 -68
- ethpm/package.py +0 -438
- ethpm/tools/__init__.py +0 -4
- ethpm/tools/builder.py +0 -930
- ethpm/tools/checker.py +0 -312
- ethpm/tools/get_manifest.py +0 -19
- ethpm/uri.py +0 -141
- ethpm/validation/__init__.py +0 -0
- ethpm/validation/manifest.py +0 -146
- ethpm/validation/misc.py +0 -39
- ethpm/validation/package.py +0 -80
- ethpm/validation/uri.py +0 -163
- web3/_utils/caching.py +0 -155
- web3/_utils/contract_sources/contract_data/address_reflector.py +0 -29
- web3/_utils/module_testing/go_ethereum_personal_module.py +0 -300
- web3/_utils/request.py +0 -265
- web3/pm.py +0 -602
- web3/tools/__init__.py +0 -4
- web3/tools/benchmark/__init__.py +0 -0
- web3/tools/benchmark/main.py +0 -185
- web3/tools/benchmark/node.py +0 -126
- web3/tools/benchmark/reporting.py +0 -39
- web3/tools/benchmark/utils.py +0 -69
- web3/tools/pytest_ethereum/__init__.py +0 -0
- web3/tools/pytest_ethereum/_utils.py +0 -145
- web3/tools/pytest_ethereum/deployer.py +0 -48
- web3/tools/pytest_ethereum/exceptions.py +0 -22
- web3/tools/pytest_ethereum/linker.py +0 -128
- web3/tools/pytest_ethereum/plugins.py +0 -33
- web3-7.0.0b1.dist-info/METADATA +0 -114
- web3-7.0.0b1.dist-info/RECORD +0 -280
- web3-7.0.0b1.dist-info/entry_points.txt +0 -2
- /web3/_utils/{function_identifiers.py → abi_element_identifiers.py} +0 -0
web3/providers/ipc.py
CHANGED
|
@@ -14,8 +14,11 @@ from types import (
|
|
|
14
14
|
)
|
|
15
15
|
from typing import (
|
|
16
16
|
Any,
|
|
17
|
+
List,
|
|
18
|
+
Tuple,
|
|
17
19
|
Type,
|
|
18
20
|
Union,
|
|
21
|
+
cast,
|
|
19
22
|
)
|
|
20
23
|
|
|
21
24
|
from web3._utils.threads import (
|
|
@@ -26,6 +29,16 @@ from web3.types import (
|
|
|
26
29
|
RPCResponse,
|
|
27
30
|
)
|
|
28
31
|
|
|
32
|
+
from .._utils.batching import (
|
|
33
|
+
sort_batch_response_by_response_ids,
|
|
34
|
+
)
|
|
35
|
+
from .._utils.caching import (
|
|
36
|
+
handle_request_caching,
|
|
37
|
+
)
|
|
38
|
+
from ..exceptions import (
|
|
39
|
+
Web3TypeError,
|
|
40
|
+
Web3ValueError,
|
|
41
|
+
)
|
|
29
42
|
from .base import (
|
|
30
43
|
JSONBaseProvider,
|
|
31
44
|
)
|
|
@@ -96,28 +109,29 @@ def get_default_ipc_path() -> str:
|
|
|
96
109
|
return r"\\.\pipe\geth.ipc"
|
|
97
110
|
|
|
98
111
|
else:
|
|
99
|
-
raise
|
|
112
|
+
raise Web3ValueError(
|
|
100
113
|
f"Unsupported platform '{sys.platform}'. Only darwin/linux/win32/"
|
|
101
114
|
"freebsd are supported. You must specify the ipc_path"
|
|
102
115
|
)
|
|
103
116
|
|
|
104
117
|
|
|
105
118
|
def get_dev_ipc_path() -> str:
|
|
106
|
-
|
|
107
|
-
|
|
119
|
+
web3_provider_uri = os.environ.get("WEB3_PROVIDER_URI", "")
|
|
120
|
+
if web3_provider_uri and "geth.ipc" in web3_provider_uri:
|
|
121
|
+
return web3_provider_uri
|
|
108
122
|
|
|
109
|
-
elif sys.platform == "darwin":
|
|
110
|
-
tmpdir = os.environ.get("TMPDIR", "")
|
|
123
|
+
elif sys.platform == "darwin" or sys.platform.startswith("linux"):
|
|
124
|
+
tmpdir = os.environ.get("TMPDIR", "/tmp")
|
|
111
125
|
return os.path.expanduser(os.path.join(tmpdir, "geth.ipc"))
|
|
112
126
|
|
|
113
|
-
elif sys.platform.
|
|
127
|
+
elif sys.platform.endswith("freebsd"):
|
|
114
128
|
return os.path.expanduser(os.path.join("/tmp", "geth.ipc"))
|
|
115
129
|
|
|
116
130
|
elif sys.platform == "win32":
|
|
117
131
|
return r"\\.\pipe\geth.ipc"
|
|
118
132
|
|
|
119
133
|
else:
|
|
120
|
-
raise
|
|
134
|
+
raise Web3ValueError(
|
|
121
135
|
f"Unsupported platform '{sys.platform}'. Only darwin/linux/win32/"
|
|
122
136
|
"freebsd are supported. You must specify the ipc_path"
|
|
123
137
|
)
|
|
@@ -130,34 +144,28 @@ class IPCProvider(JSONBaseProvider):
|
|
|
130
144
|
def __init__(
|
|
131
145
|
self,
|
|
132
146
|
ipc_path: Union[str, Path] = None,
|
|
133
|
-
timeout: int =
|
|
134
|
-
*args: Any,
|
|
147
|
+
timeout: int = 30,
|
|
135
148
|
**kwargs: Any,
|
|
136
149
|
) -> None:
|
|
150
|
+
super().__init__(**kwargs)
|
|
137
151
|
if ipc_path is None:
|
|
138
152
|
self.ipc_path = get_default_ipc_path()
|
|
139
153
|
elif isinstance(ipc_path, str) or isinstance(ipc_path, Path):
|
|
140
154
|
self.ipc_path = str(Path(ipc_path).expanduser().resolve())
|
|
141
155
|
else:
|
|
142
|
-
raise
|
|
156
|
+
raise Web3TypeError("ipc_path must be of type string or pathlib.Path")
|
|
143
157
|
|
|
144
158
|
self.timeout = timeout
|
|
145
159
|
self._lock = threading.Lock()
|
|
146
160
|
self._socket = PersistantSocket(self.ipc_path)
|
|
147
|
-
super().__init__()
|
|
148
161
|
|
|
149
162
|
def __str__(self) -> str:
|
|
150
163
|
return f"<{self.__class__.__name__} {self.ipc_path}>"
|
|
151
164
|
|
|
152
|
-
def
|
|
153
|
-
self.logger.debug(
|
|
154
|
-
f"Making request IPC. Path: {self.ipc_path}, Method: {method}"
|
|
155
|
-
)
|
|
156
|
-
request = self.encode_rpc_request(method, params)
|
|
157
|
-
|
|
165
|
+
def _make_request(self, request: bytes) -> RPCResponse:
|
|
158
166
|
with self._lock, self._socket as sock:
|
|
159
167
|
try:
|
|
160
|
-
sock.sendall(request)
|
|
168
|
+
sock.sendall(request + b"\n")
|
|
161
169
|
except BrokenPipeError:
|
|
162
170
|
# one extra attempt, then give up
|
|
163
171
|
sock = self._socket.reset()
|
|
@@ -185,6 +193,22 @@ class IPCProvider(JSONBaseProvider):
|
|
|
185
193
|
timeout.sleep(0)
|
|
186
194
|
continue
|
|
187
195
|
|
|
196
|
+
@handle_request_caching
|
|
197
|
+
def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
|
|
198
|
+
self.logger.debug(
|
|
199
|
+
f"Making request IPC. Path: {self.ipc_path}, Method: {method}"
|
|
200
|
+
)
|
|
201
|
+
request = self.encode_rpc_request(method, params)
|
|
202
|
+
return self._make_request(request)
|
|
203
|
+
|
|
204
|
+
def make_batch_request(
|
|
205
|
+
self, requests: List[Tuple[RPCEndpoint, Any]]
|
|
206
|
+
) -> List[RPCResponse]:
|
|
207
|
+
self.logger.debug(f"Making batch request IPC. Path: {self.ipc_path}")
|
|
208
|
+
request_data = self.encode_batch_rpc_request(requests)
|
|
209
|
+
response = cast(List[RPCResponse], self._make_request(request_data))
|
|
210
|
+
return sort_batch_response_by_response_ids(response)
|
|
211
|
+
|
|
188
212
|
|
|
189
213
|
# A valid JSON RPC response can only end in } or ] http://www.jsonrpc.org/specification
|
|
190
214
|
def has_valid_json_rpc_ending(raw_response: bytes) -> bool:
|
|
@@ -10,9 +10,12 @@ from types import (
|
|
|
10
10
|
)
|
|
11
11
|
from typing import (
|
|
12
12
|
Any,
|
|
13
|
+
List,
|
|
13
14
|
Optional,
|
|
15
|
+
Tuple,
|
|
14
16
|
Type,
|
|
15
17
|
Union,
|
|
18
|
+
cast,
|
|
16
19
|
)
|
|
17
20
|
|
|
18
21
|
from eth_typing import (
|
|
@@ -25,6 +28,12 @@ from websockets.legacy.client import (
|
|
|
25
28
|
WebSocketClientProtocol,
|
|
26
29
|
)
|
|
27
30
|
|
|
31
|
+
from web3._utils.batching import (
|
|
32
|
+
sort_batch_response_by_response_ids,
|
|
33
|
+
)
|
|
34
|
+
from web3._utils.caching import (
|
|
35
|
+
handle_request_caching,
|
|
36
|
+
)
|
|
28
37
|
from web3.exceptions import (
|
|
29
38
|
Web3ValidationError,
|
|
30
39
|
)
|
|
@@ -37,7 +46,7 @@ from web3.types import (
|
|
|
37
46
|
)
|
|
38
47
|
|
|
39
48
|
RESTRICTED_WEBSOCKET_KWARGS = {"uri", "loop"}
|
|
40
|
-
DEFAULT_WEBSOCKET_TIMEOUT =
|
|
49
|
+
DEFAULT_WEBSOCKET_TIMEOUT = 30
|
|
41
50
|
|
|
42
51
|
|
|
43
52
|
def _start_event_loop(loop: asyncio.AbstractEventLoop) -> None:
|
|
@@ -91,7 +100,9 @@ class LegacyWebSocketProvider(JSONBaseProvider):
|
|
|
91
100
|
endpoint_uri: Optional[Union[URI, str]] = None,
|
|
92
101
|
websocket_kwargs: Optional[Any] = None,
|
|
93
102
|
websocket_timeout: int = DEFAULT_WEBSOCKET_TIMEOUT,
|
|
103
|
+
**kwargs: Any,
|
|
94
104
|
) -> None:
|
|
105
|
+
super().__init__(**kwargs)
|
|
95
106
|
self.endpoint_uri = URI(endpoint_uri)
|
|
96
107
|
self.websocket_timeout = websocket_timeout
|
|
97
108
|
if self.endpoint_uri is None:
|
|
@@ -110,7 +121,6 @@ class LegacyWebSocketProvider(JSONBaseProvider):
|
|
|
110
121
|
f"in websocket_kwargs, found: {found_restricted_keys}"
|
|
111
122
|
)
|
|
112
123
|
self.conn = PersistentWebSocket(self.endpoint_uri, websocket_kwargs)
|
|
113
|
-
super().__init__()
|
|
114
124
|
|
|
115
125
|
def __str__(self) -> str:
|
|
116
126
|
return f"WS connection {self.endpoint_uri}"
|
|
@@ -124,6 +134,7 @@ class LegacyWebSocketProvider(JSONBaseProvider):
|
|
|
124
134
|
await asyncio.wait_for(conn.recv(), timeout=self.websocket_timeout)
|
|
125
135
|
)
|
|
126
136
|
|
|
137
|
+
@handle_request_caching
|
|
127
138
|
def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
|
|
128
139
|
self.logger.debug(
|
|
129
140
|
f"Making request WebSocket. URI: {self.endpoint_uri}, " f"Method: {method}"
|
|
@@ -133,3 +144,17 @@ class LegacyWebSocketProvider(JSONBaseProvider):
|
|
|
133
144
|
self.coro_make_request(request_data), LegacyWebSocketProvider._loop
|
|
134
145
|
)
|
|
135
146
|
return future.result()
|
|
147
|
+
|
|
148
|
+
def make_batch_request(
|
|
149
|
+
self, requests: List[Tuple[RPCEndpoint, Any]]
|
|
150
|
+
) -> List[RPCResponse]:
|
|
151
|
+
self.logger.debug(
|
|
152
|
+
f"Making batch request WebSocket. URI: {self.endpoint_uri}, "
|
|
153
|
+
f"Methods: {requests}"
|
|
154
|
+
)
|
|
155
|
+
request_data = self.encode_batch_rpc_request(requests)
|
|
156
|
+
future = asyncio.run_coroutine_threadsafe(
|
|
157
|
+
self.coro_make_request(request_data), LegacyWebSocketProvider._loop
|
|
158
|
+
)
|
|
159
|
+
response = cast(List[RPCResponse], future.result())
|
|
160
|
+
return sort_batch_response_by_response_ids(response)
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import errno
|
|
3
3
|
import json
|
|
4
|
-
from json import (
|
|
5
|
-
JSONDecodeError,
|
|
6
|
-
)
|
|
7
4
|
import logging
|
|
8
5
|
from pathlib import (
|
|
9
6
|
Path,
|
|
@@ -16,10 +13,6 @@ from typing import (
|
|
|
16
13
|
Union,
|
|
17
14
|
)
|
|
18
15
|
|
|
19
|
-
from eth_utils import (
|
|
20
|
-
to_text,
|
|
21
|
-
)
|
|
22
|
-
|
|
23
16
|
from web3.types import (
|
|
24
17
|
RPCEndpoint,
|
|
25
18
|
RPCResponse,
|
|
@@ -28,11 +21,11 @@ from web3.types import (
|
|
|
28
21
|
from . import (
|
|
29
22
|
PersistentConnectionProvider,
|
|
30
23
|
)
|
|
31
|
-
from ..._utils.caching import (
|
|
32
|
-
async_handle_request_caching,
|
|
33
|
-
)
|
|
34
24
|
from ...exceptions import (
|
|
25
|
+
PersistentConnectionClosedOK,
|
|
35
26
|
ProviderConnectionError,
|
|
27
|
+
ReadBufferLimitReached,
|
|
28
|
+
Web3TypeError,
|
|
36
29
|
)
|
|
37
30
|
from ..ipc import (
|
|
38
31
|
get_default_ipc_path,
|
|
@@ -40,7 +33,7 @@ from ..ipc import (
|
|
|
40
33
|
|
|
41
34
|
|
|
42
35
|
async def async_get_ipc_socket(
|
|
43
|
-
ipc_path: str,
|
|
36
|
+
ipc_path: str, read_buffer_limit: int
|
|
44
37
|
) -> Tuple[asyncio.StreamReader, asyncio.StreamWriter]:
|
|
45
38
|
if sys.platform == "win32":
|
|
46
39
|
# On Windows named pipe is used. Simulate socket with it.
|
|
@@ -50,7 +43,7 @@ async def async_get_ipc_socket(
|
|
|
50
43
|
|
|
51
44
|
return NamedPipe(ipc_path)
|
|
52
45
|
else:
|
|
53
|
-
return await asyncio.open_unix_connection(ipc_path)
|
|
46
|
+
return await asyncio.open_unix_connection(ipc_path, limit=read_buffer_limit)
|
|
54
47
|
|
|
55
48
|
|
|
56
49
|
class AsyncIPCProvider(PersistentConnectionProvider):
|
|
@@ -58,23 +51,24 @@ class AsyncIPCProvider(PersistentConnectionProvider):
|
|
|
58
51
|
|
|
59
52
|
_reader: Optional[asyncio.StreamReader] = None
|
|
60
53
|
_writer: Optional[asyncio.StreamWriter] = None
|
|
54
|
+
_decoder: json.JSONDecoder = json.JSONDecoder()
|
|
61
55
|
|
|
62
56
|
def __init__(
|
|
63
57
|
self,
|
|
64
58
|
ipc_path: Optional[Union[str, Path]] = None,
|
|
65
|
-
|
|
59
|
+
read_buffer_limit: int = 20 * 1024 * 1024, # 20 MB
|
|
66
60
|
# `PersistentConnectionProvider` kwargs can be passed through
|
|
67
61
|
**kwargs: Any,
|
|
68
62
|
) -> None:
|
|
63
|
+
# initialize the ipc_path before calling the super constructor
|
|
69
64
|
if ipc_path is None:
|
|
70
65
|
self.ipc_path = get_default_ipc_path()
|
|
71
66
|
elif isinstance(ipc_path, str) or isinstance(ipc_path, Path):
|
|
72
67
|
self.ipc_path = str(Path(ipc_path).expanduser().resolve())
|
|
73
68
|
else:
|
|
74
|
-
raise
|
|
75
|
-
|
|
76
|
-
self._max_connection_retries = max_connection_retries
|
|
69
|
+
raise Web3TypeError("ipc_path must be of type string or pathlib.Path")
|
|
77
70
|
super().__init__(**kwargs)
|
|
71
|
+
self.read_buffer_limit = read_buffer_limit
|
|
78
72
|
|
|
79
73
|
def __str__(self) -> str:
|
|
80
74
|
return f"<{self.__class__.__name__} {self.ipc_path}>"
|
|
@@ -84,81 +78,46 @@ class AsyncIPCProvider(PersistentConnectionProvider):
|
|
|
84
78
|
return False
|
|
85
79
|
|
|
86
80
|
try:
|
|
87
|
-
|
|
88
|
-
RPCEndpoint("web3_clientVersions"), []
|
|
89
|
-
)
|
|
90
|
-
self._writer.write(request_data)
|
|
91
|
-
current_request_id = json.loads(request_data)["id"]
|
|
92
|
-
await self._get_response_for_request_id(current_request_id, timeout=2)
|
|
81
|
+
await self.make_request(RPCEndpoint("web3_clientVersion"), [])
|
|
93
82
|
return True
|
|
94
|
-
except (OSError,
|
|
83
|
+
except (OSError, ProviderConnectionError) as e:
|
|
95
84
|
if show_traceback:
|
|
96
85
|
raise ProviderConnectionError(
|
|
97
86
|
f"Problem connecting to provider with error: {type(e)}: {e}"
|
|
98
87
|
)
|
|
99
88
|
return False
|
|
100
89
|
|
|
101
|
-
async def
|
|
102
|
-
_connection_attempts = 0
|
|
103
|
-
_backoff_rate_change = 1.75
|
|
104
|
-
_backoff_time = 1.75
|
|
105
|
-
|
|
106
|
-
while _connection_attempts != self._max_connection_retries:
|
|
107
|
-
try:
|
|
108
|
-
_connection_attempts += 1
|
|
109
|
-
self._reader, self._writer = await async_get_ipc_socket(self.ipc_path)
|
|
110
|
-
self._message_listener_task = asyncio.create_task(
|
|
111
|
-
self._message_listener()
|
|
112
|
-
)
|
|
113
|
-
break
|
|
114
|
-
except OSError as e:
|
|
115
|
-
if _connection_attempts == self._max_connection_retries:
|
|
116
|
-
raise ProviderConnectionError(
|
|
117
|
-
f"Could not connect to endpoint: {self.endpoint_uri}. "
|
|
118
|
-
f"Retries exceeded max of {self._max_connection_retries}."
|
|
119
|
-
) from e
|
|
120
|
-
self.logger.info(
|
|
121
|
-
f"Could not connect to endpoint: {self.endpoint_uri}. Retrying in "
|
|
122
|
-
f"{round(_backoff_time, 1)} seconds.",
|
|
123
|
-
exc_info=True,
|
|
124
|
-
)
|
|
125
|
-
await asyncio.sleep(_backoff_time)
|
|
126
|
-
_backoff_time *= _backoff_rate_change
|
|
127
|
-
|
|
128
|
-
async def disconnect(self) -> None:
|
|
129
|
-
if self._writer and not self._writer.is_closing():
|
|
130
|
-
self._writer.close()
|
|
131
|
-
await self._writer.wait_closed()
|
|
132
|
-
self._writer = None
|
|
133
|
-
self.logger.debug(
|
|
134
|
-
f'Successfully disconnected from endpoint: "{self.endpoint_uri}'
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
try:
|
|
138
|
-
self._message_listener_task.cancel()
|
|
139
|
-
await self._message_listener_task
|
|
140
|
-
self._reader = None
|
|
141
|
-
except (asyncio.CancelledError, StopAsyncIteration):
|
|
142
|
-
pass
|
|
143
|
-
|
|
144
|
-
self._request_processor.clear_caches()
|
|
145
|
-
|
|
146
|
-
async def _reset_socket(self) -> None:
|
|
147
|
-
self._writer.close()
|
|
148
|
-
await self._writer.wait_closed()
|
|
149
|
-
self._reader, self._writer = await async_get_ipc_socket(self.ipc_path)
|
|
150
|
-
|
|
151
|
-
@async_handle_request_caching
|
|
152
|
-
async def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
|
|
153
|
-
request_data = self.encode_rpc_request(method, params)
|
|
154
|
-
|
|
90
|
+
async def socket_send(self, request_data: bytes) -> None:
|
|
155
91
|
if self._writer is None:
|
|
156
92
|
raise ProviderConnectionError(
|
|
157
93
|
"Connection to ipc socket has not been initiated for the provider."
|
|
158
94
|
)
|
|
159
95
|
|
|
96
|
+
return await asyncio.wait_for(
|
|
97
|
+
self._socket_send(request_data), timeout=self.request_timeout
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
async def socket_recv(self) -> RPCResponse:
|
|
160
101
|
try:
|
|
161
|
-
self.
|
|
102
|
+
data = await self._reader.readline()
|
|
103
|
+
except ValueError as e:
|
|
104
|
+
if all(kw in str(e) for kw in ("limit", "chunk")):
|
|
105
|
+
raise ReadBufferLimitReached(
|
|
106
|
+
f"Read buffer limit of `{self.read_buffer_limit}` bytes was "
|
|
107
|
+
"reached. Consider increasing the ``read_buffer_limit`` on the "
|
|
108
|
+
"AsyncIPCProvider."
|
|
109
|
+
) from e
|
|
110
|
+
raise
|
|
111
|
+
|
|
112
|
+
if not data:
|
|
113
|
+
raise PersistentConnectionClosedOK("Socket reader received end of stream.")
|
|
114
|
+
return self.decode_rpc_response(data)
|
|
115
|
+
|
|
116
|
+
# -- private methods -- #
|
|
117
|
+
|
|
118
|
+
async def _socket_send(self, request_data: bytes) -> None:
|
|
119
|
+
try:
|
|
120
|
+
self._writer.write(request_data + b"\n")
|
|
162
121
|
await self._writer.drain()
|
|
163
122
|
except OSError as e:
|
|
164
123
|
# Broken pipe
|
|
@@ -168,48 +127,29 @@ class AsyncIPCProvider(PersistentConnectionProvider):
|
|
|
168
127
|
self._writer.write(request_data)
|
|
169
128
|
await self._writer.drain()
|
|
170
129
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
130
|
+
async def _reset_socket(self) -> None:
|
|
131
|
+
self._writer.close()
|
|
132
|
+
await self._writer.wait_closed()
|
|
133
|
+
self._reader, self._writer = await async_get_ipc_socket(
|
|
134
|
+
self.ipc_path, self.read_buffer_limit
|
|
135
|
+
)
|
|
175
136
|
|
|
176
|
-
async def
|
|
177
|
-
self.
|
|
178
|
-
|
|
179
|
-
"appropriate request processor queues / caches to be processed."
|
|
137
|
+
async def _provider_specific_connect(self) -> None:
|
|
138
|
+
self._reader, self._writer = await async_get_ipc_socket(
|
|
139
|
+
self.ipc_path, self.read_buffer_limit
|
|
180
140
|
)
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
break
|
|
197
|
-
|
|
198
|
-
is_subscription = response.get("method") == "eth_subscription"
|
|
199
|
-
await self._request_processor.cache_raw_response(
|
|
200
|
-
response, subscription=is_subscription
|
|
201
|
-
)
|
|
202
|
-
raw_message = raw_message[pos:].lstrip()
|
|
203
|
-
except Exception as e:
|
|
204
|
-
if not self.silence_listener_task_exceptions:
|
|
205
|
-
loop = asyncio.get_event_loop()
|
|
206
|
-
for task in asyncio.all_tasks(loop=loop):
|
|
207
|
-
task.cancel()
|
|
208
|
-
raise e
|
|
209
|
-
|
|
210
|
-
self.logger.error(
|
|
211
|
-
"Exception caught in listener, error logging and keeping listener "
|
|
212
|
-
f"background task alive.\n error={e}"
|
|
213
|
-
)
|
|
214
|
-
# if only error logging, reset the ``raw_message`` buffer and continue
|
|
215
|
-
raw_message = ""
|
|
141
|
+
|
|
142
|
+
async def _provider_specific_disconnect(self) -> None:
|
|
143
|
+
# this should remain idempotent
|
|
144
|
+
if self._writer and not self._writer.is_closing():
|
|
145
|
+
self._writer.close()
|
|
146
|
+
await self._writer.wait_closed()
|
|
147
|
+
self._writer = None
|
|
148
|
+
if self._reader:
|
|
149
|
+
self._reader = None
|
|
150
|
+
|
|
151
|
+
async def _provider_specific_socket_reader(self) -> RPCResponse:
|
|
152
|
+
return await self.socket_recv()
|
|
153
|
+
|
|
154
|
+
def _error_log_listener_task_exception(self, e: Exception) -> None:
|
|
155
|
+
super()._error_log_listener_task_exception(e)
|