web3 7.0.0b5__py3-none-any.whl → 7.0.0b7__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/batching.py +217 -0
- web3/_utils/caching.py +26 -2
- web3/_utils/compat/__init__.py +1 -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 +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/events.py +2 -2
- web3/_utils/http.py +3 -0
- web3/_utils/http_session_manager.py +280 -0
- web3/_utils/method_formatters.py +0 -2
- web3/_utils/module_testing/eth_module.py +92 -119
- web3/_utils/module_testing/module_testing_utils.py +27 -9
- web3/_utils/module_testing/persistent_connection_provider.py +1 -0
- web3/_utils/module_testing/web3_module.py +438 -17
- 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/contract/utils.py +112 -4
- web3/eth/__init__.py +7 -0
- web3/eth/async_eth.py +5 -37
- web3/eth/eth.py +7 -57
- web3/exceptions.py +20 -0
- web3/gas_strategies/time_based.py +2 -2
- web3/main.py +21 -9
- web3/manager.py +113 -8
- web3/method.py +29 -9
- web3/middleware/__init__.py +17 -0
- web3/middleware/base.py +43 -0
- web3/module.py +47 -7
- web3/providers/__init__.py +21 -0
- web3/providers/async_base.py +55 -23
- web3/providers/base.py +59 -26
- 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/ipc.py +23 -8
- web3/providers/legacy_websocket.py +26 -1
- web3/providers/persistent/__init__.py +7 -0
- web3/providers/persistent/async_ipc.py +60 -76
- web3/providers/persistent/persistent.py +134 -10
- web3/providers/persistent/request_processor.py +98 -14
- web3/providers/persistent/websocket.py +43 -66
- web3/providers/rpc/__init__.py +5 -0
- web3/providers/rpc/async_rpc.py +34 -12
- web3/providers/rpc/rpc.py +34 -12
- web3/providers/rpc/utils.py +0 -3
- web3/tools/benchmark/main.py +7 -6
- web3/tools/benchmark/node.py +1 -1
- web3/types.py +7 -1
- web3/utils/__init__.py +14 -5
- web3/utils/async_exception_handling.py +19 -7
- web3/utils/exception_handling.py +7 -5
- {web3-7.0.0b5.dist-info → web3-7.0.0b7.dist-info}/LICENSE +1 -1
- {web3-7.0.0b5.dist-info → web3-7.0.0b7.dist-info}/METADATA +33 -20
- {web3-7.0.0b5.dist-info → web3-7.0.0b7.dist-info}/RECORD +80 -80
- {web3-7.0.0b5.dist-info → web3-7.0.0b7.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.0b5.dist-info → web3-7.0.0b7.dist-info}/top_level.txt +0 -0
web3/method.py
CHANGED
|
@@ -10,7 +10,6 @@ from typing import (
|
|
|
10
10
|
Sequence,
|
|
11
11
|
Tuple,
|
|
12
12
|
Type,
|
|
13
|
-
TypeVar,
|
|
14
13
|
Union,
|
|
15
14
|
)
|
|
16
15
|
import warnings
|
|
@@ -22,6 +21,9 @@ from eth_utils.toolz import (
|
|
|
22
21
|
pipe,
|
|
23
22
|
)
|
|
24
23
|
|
|
24
|
+
from web3._utils.batching import (
|
|
25
|
+
RPC_METHODS_UNSUPPORTED_DURING_BATCH,
|
|
26
|
+
)
|
|
25
27
|
from web3._utils.method_formatters import (
|
|
26
28
|
get_error_formatters,
|
|
27
29
|
get_null_result_formatters,
|
|
@@ -32,17 +34,22 @@ from web3._utils.rpc_abi import (
|
|
|
32
34
|
RPC,
|
|
33
35
|
)
|
|
34
36
|
from web3.exceptions import (
|
|
37
|
+
MethodNotSupported,
|
|
35
38
|
Web3TypeError,
|
|
36
39
|
Web3ValidationError,
|
|
37
40
|
Web3ValueError,
|
|
38
41
|
)
|
|
39
42
|
from web3.types import (
|
|
40
43
|
RPCEndpoint,
|
|
44
|
+
TFunc,
|
|
41
45
|
TReturn,
|
|
42
46
|
)
|
|
43
47
|
|
|
44
48
|
if TYPE_CHECKING:
|
|
45
|
-
from web3 import
|
|
49
|
+
from web3 import ( # noqa: F401
|
|
50
|
+
PersistentConnectionProvider,
|
|
51
|
+
Web3,
|
|
52
|
+
)
|
|
46
53
|
from web3.module import Module # noqa: F401
|
|
47
54
|
|
|
48
55
|
|
|
@@ -84,9 +91,6 @@ def default_root_munger(_module: "Module", *args: Any) -> List[Any]:
|
|
|
84
91
|
return [*args]
|
|
85
92
|
|
|
86
93
|
|
|
87
|
-
TFunc = TypeVar("TFunc", bound=Callable[..., Any])
|
|
88
|
-
|
|
89
|
-
|
|
90
94
|
class Method(Generic[TFunc]):
|
|
91
95
|
"""
|
|
92
96
|
Method object for web3 module methods
|
|
@@ -149,15 +153,31 @@ class Method(Generic[TFunc]):
|
|
|
149
153
|
self.is_property = is_property
|
|
150
154
|
|
|
151
155
|
def __get__(
|
|
152
|
-
self,
|
|
156
|
+
self,
|
|
157
|
+
module: Optional["Module"] = None,
|
|
158
|
+
_type: Optional[Type["Module"]] = None,
|
|
153
159
|
) -> TFunc:
|
|
154
|
-
|
|
160
|
+
self._module = module
|
|
161
|
+
if module is None:
|
|
155
162
|
raise Web3TypeError(
|
|
156
163
|
"Direct calls to methods are not supported. "
|
|
157
|
-
"Methods must be called from
|
|
164
|
+
"Methods must be called from a module instance, "
|
|
158
165
|
"usually attached to a web3 instance."
|
|
159
166
|
)
|
|
160
|
-
|
|
167
|
+
|
|
168
|
+
provider = module.w3.provider
|
|
169
|
+
if hasattr(provider, "_is_batching") and provider._is_batching:
|
|
170
|
+
if self.json_rpc_method in RPC_METHODS_UNSUPPORTED_DURING_BATCH:
|
|
171
|
+
raise MethodNotSupported(
|
|
172
|
+
f"Method `{self.json_rpc_method}` is not supported within a batch "
|
|
173
|
+
"request."
|
|
174
|
+
)
|
|
175
|
+
return module.retrieve_request_information(self)
|
|
176
|
+
else:
|
|
177
|
+
return module.retrieve_caller_fn(self)
|
|
178
|
+
|
|
179
|
+
def __call__(self, *args: Any, **kwargs: Any) -> Any:
|
|
180
|
+
return self.__get__(self._module)(*args, **kwargs)
|
|
161
181
|
|
|
162
182
|
@property
|
|
163
183
|
def method_selector_fn(
|
web3/middleware/__init__.py
CHANGED
|
@@ -92,3 +92,20 @@ async def async_combine_middleware(
|
|
|
92
92
|
initialized = mw(async_w3)
|
|
93
93
|
accumulator_fn = await initialized.async_wrap_make_request(accumulator_fn)
|
|
94
94
|
return accumulator_fn
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
__all__ = [
|
|
98
|
+
"AttributeDictMiddleware",
|
|
99
|
+
"Middleware",
|
|
100
|
+
"Web3Middleware",
|
|
101
|
+
"BufferedGasEstimateMiddleware",
|
|
102
|
+
"LocalFilterMiddleware",
|
|
103
|
+
"FormattingMiddlewareBuilder",
|
|
104
|
+
"GasPriceStrategyMiddleware",
|
|
105
|
+
"ENSNameToAddressMiddleware",
|
|
106
|
+
"ExtraDataToPOAMiddleware",
|
|
107
|
+
"PythonicMiddleware",
|
|
108
|
+
"SignAndSendRawMiddlewareBuilder",
|
|
109
|
+
"StalecheckMiddlewareBuilder",
|
|
110
|
+
"ValidationMiddleware",
|
|
111
|
+
]
|
web3/middleware/base.py
CHANGED
|
@@ -4,6 +4,8 @@ from abc import (
|
|
|
4
4
|
from typing import (
|
|
5
5
|
TYPE_CHECKING,
|
|
6
6
|
Any,
|
|
7
|
+
List,
|
|
8
|
+
Tuple,
|
|
7
9
|
Type,
|
|
8
10
|
Union,
|
|
9
11
|
)
|
|
@@ -18,7 +20,9 @@ if TYPE_CHECKING:
|
|
|
18
20
|
Web3,
|
|
19
21
|
)
|
|
20
22
|
from web3.types import ( # noqa: F401
|
|
23
|
+
AsyncMakeBatchRequestFn,
|
|
21
24
|
AsyncMakeRequestFn,
|
|
25
|
+
MakeBatchRequestFn,
|
|
22
26
|
MakeRequestFn,
|
|
23
27
|
RPCEndpoint,
|
|
24
28
|
RPCResponse,
|
|
@@ -45,6 +49,25 @@ class Web3Middleware:
|
|
|
45
49
|
|
|
46
50
|
return middleware
|
|
47
51
|
|
|
52
|
+
def wrap_make_batch_request(
|
|
53
|
+
self, make_batch_request: "MakeBatchRequestFn"
|
|
54
|
+
) -> "MakeBatchRequestFn":
|
|
55
|
+
def middleware(
|
|
56
|
+
requests_info: List[Tuple["RPCEndpoint", Any]]
|
|
57
|
+
) -> List["RPCResponse"]:
|
|
58
|
+
req_processed = [
|
|
59
|
+
self.request_processor(method, params)
|
|
60
|
+
for (method, params) in requests_info
|
|
61
|
+
]
|
|
62
|
+
responses = make_batch_request(req_processed)
|
|
63
|
+
methods, _params = zip(*req_processed)
|
|
64
|
+
formatted_responses = [
|
|
65
|
+
self.response_processor(m, r) for m, r in zip(methods, responses)
|
|
66
|
+
]
|
|
67
|
+
return formatted_responses
|
|
68
|
+
|
|
69
|
+
return middleware
|
|
70
|
+
|
|
48
71
|
def request_processor(self, method: "RPCEndpoint", params: Any) -> Any:
|
|
49
72
|
return method, params
|
|
50
73
|
|
|
@@ -67,6 +90,26 @@ class Web3Middleware:
|
|
|
67
90
|
|
|
68
91
|
return middleware
|
|
69
92
|
|
|
93
|
+
async def async_wrap_make_batch_request(
|
|
94
|
+
self, make_batch_request: "AsyncMakeBatchRequestFn"
|
|
95
|
+
) -> "AsyncMakeBatchRequestFn":
|
|
96
|
+
async def middleware(
|
|
97
|
+
requests_info: List[Tuple["RPCEndpoint", Any]]
|
|
98
|
+
) -> List["RPCResponse"]:
|
|
99
|
+
req_processed = [
|
|
100
|
+
await self.async_request_processor(method, params)
|
|
101
|
+
for (method, params) in requests_info
|
|
102
|
+
]
|
|
103
|
+
responses = await make_batch_request(req_processed)
|
|
104
|
+
methods, _params = zip(*req_processed)
|
|
105
|
+
formatted_responses = [
|
|
106
|
+
await self.async_response_processor(m, r)
|
|
107
|
+
for m, r in zip(methods, responses)
|
|
108
|
+
]
|
|
109
|
+
return formatted_responses
|
|
110
|
+
|
|
111
|
+
return middleware
|
|
112
|
+
|
|
70
113
|
async def async_request_processor(
|
|
71
114
|
self,
|
|
72
115
|
method: "RPCEndpoint",
|
web3/module.py
CHANGED
|
@@ -5,6 +5,8 @@ from typing import (
|
|
|
5
5
|
Coroutine,
|
|
6
6
|
Dict,
|
|
7
7
|
Optional,
|
|
8
|
+
Sequence,
|
|
9
|
+
Tuple,
|
|
8
10
|
TypeVar,
|
|
9
11
|
Union,
|
|
10
12
|
cast,
|
|
@@ -55,9 +57,43 @@ def apply_result_formatters(
|
|
|
55
57
|
TReturn = TypeVar("TReturn")
|
|
56
58
|
|
|
57
59
|
|
|
60
|
+
@curry
|
|
61
|
+
def retrieve_request_information_for_batching(
|
|
62
|
+
w3: Union["AsyncWeb3", "Web3"],
|
|
63
|
+
module: "Module",
|
|
64
|
+
method: Method[Callable[..., Any]],
|
|
65
|
+
) -> Union[
|
|
66
|
+
Callable[..., Tuple[Tuple[RPCEndpoint, Any], Sequence[Any]]],
|
|
67
|
+
Callable[..., Coroutine[Any, Any, Tuple[Tuple[RPCEndpoint, Any], Sequence[Any]]]],
|
|
68
|
+
]:
|
|
69
|
+
async def async_inner(
|
|
70
|
+
*args: Any, **kwargs: Any
|
|
71
|
+
) -> Tuple[Tuple[RPCEndpoint, Any], Sequence[Any]]:
|
|
72
|
+
(method_str, params), response_formatters = method.process_params(
|
|
73
|
+
module, *args, **kwargs
|
|
74
|
+
)
|
|
75
|
+
if isinstance(w3.provider, PersistentConnectionProvider):
|
|
76
|
+
w3.provider._request_processor.cache_request_information(
|
|
77
|
+
cast(RPCEndpoint, method_str), params, response_formatters
|
|
78
|
+
)
|
|
79
|
+
return (cast(RPCEndpoint, method_str), params), response_formatters
|
|
80
|
+
|
|
81
|
+
def inner(
|
|
82
|
+
*args: Any, **kwargs: Any
|
|
83
|
+
) -> Tuple[Tuple[RPCEndpoint, Any], Sequence[Any]]:
|
|
84
|
+
(method_str, params), response_formatters = method.process_params(
|
|
85
|
+
module, *args, **kwargs
|
|
86
|
+
)
|
|
87
|
+
return (cast(RPCEndpoint, method_str), params), response_formatters
|
|
88
|
+
|
|
89
|
+
return async_inner if module.is_async else inner
|
|
90
|
+
|
|
91
|
+
|
|
58
92
|
@curry
|
|
59
93
|
def retrieve_blocking_method_call_fn(
|
|
60
|
-
w3: "Web3",
|
|
94
|
+
w3: "Web3",
|
|
95
|
+
module: "Module",
|
|
96
|
+
method: Method[Callable[..., TReturn]],
|
|
61
97
|
) -> Callable[..., Union[TReturn, LogFilter]]:
|
|
62
98
|
def caller(*args: Any, **kwargs: Any) -> Union[TReturn, LogFilter]:
|
|
63
99
|
try:
|
|
@@ -82,7 +118,9 @@ def retrieve_blocking_method_call_fn(
|
|
|
82
118
|
|
|
83
119
|
@curry
|
|
84
120
|
def retrieve_async_method_call_fn(
|
|
85
|
-
async_w3: "AsyncWeb3",
|
|
121
|
+
async_w3: "AsyncWeb3",
|
|
122
|
+
module: "Module",
|
|
123
|
+
method: Method[Callable[..., Any]],
|
|
86
124
|
) -> Callable[..., Coroutine[Any, Any, Optional[Union[RPCResponse, AsyncLogFilter]]]]:
|
|
87
125
|
async def caller(*args: Any, **kwargs: Any) -> Union[RPCResponse, AsyncLogFilter]:
|
|
88
126
|
try:
|
|
@@ -93,12 +131,11 @@ def retrieve_async_method_call_fn(
|
|
|
93
131
|
return AsyncLogFilter(eth_module=module, filter_id=err.filter_id)
|
|
94
132
|
|
|
95
133
|
if isinstance(async_w3.provider, PersistentConnectionProvider):
|
|
96
|
-
# TODO: The typing does not seem to be correct for response_formatters.
|
|
97
|
-
# For now, keep the expected typing but ignore it here.
|
|
98
134
|
provider = async_w3.provider
|
|
99
135
|
cache_key = provider._request_processor.cache_request_information(
|
|
100
|
-
cast(RPCEndpoint, method_str), params, response_formatters
|
|
136
|
+
cast(RPCEndpoint, method_str), params, response_formatters
|
|
101
137
|
)
|
|
138
|
+
|
|
102
139
|
try:
|
|
103
140
|
method_str = cast(RPCEndpoint, method_str)
|
|
104
141
|
return await async_w3.manager.send(method_str, params)
|
|
@@ -139,6 +176,9 @@ class Module:
|
|
|
139
176
|
self.retrieve_caller_fn = retrieve_async_method_call_fn(w3, self)
|
|
140
177
|
else:
|
|
141
178
|
self.retrieve_caller_fn = retrieve_blocking_method_call_fn(w3, self)
|
|
179
|
+
self.retrieve_request_information = retrieve_request_information_for_batching(
|
|
180
|
+
w3, self
|
|
181
|
+
)
|
|
142
182
|
self.w3 = w3
|
|
143
183
|
|
|
144
184
|
@property
|
|
@@ -152,8 +192,8 @@ class Module:
|
|
|
152
192
|
) -> None:
|
|
153
193
|
for method_name, method_class in methods.items():
|
|
154
194
|
klass = (
|
|
155
|
-
method_class.__get__(
|
|
195
|
+
method_class.__get__(module=self)()
|
|
156
196
|
if method_class.is_property
|
|
157
|
-
else method_class.__get__(
|
|
197
|
+
else method_class.__get__(module=self)
|
|
158
198
|
)
|
|
159
199
|
setattr(self, method_name, klass)
|
web3/providers/__init__.py
CHANGED
|
@@ -8,6 +8,10 @@ from .base import (
|
|
|
8
8
|
BaseProvider,
|
|
9
9
|
JSONBaseProvider,
|
|
10
10
|
)
|
|
11
|
+
from .eth_tester import (
|
|
12
|
+
AsyncEthereumTesterProvider,
|
|
13
|
+
EthereumTesterProvider,
|
|
14
|
+
)
|
|
11
15
|
from .ipc import (
|
|
12
16
|
IPCProvider,
|
|
13
17
|
)
|
|
@@ -26,3 +30,20 @@ from .persistent import (
|
|
|
26
30
|
from .auto import (
|
|
27
31
|
AutoProvider,
|
|
28
32
|
)
|
|
33
|
+
|
|
34
|
+
__all__ = [
|
|
35
|
+
"AsyncBaseProvider",
|
|
36
|
+
"AsyncEthereumTesterProvider",
|
|
37
|
+
"AsyncHTTPProvider",
|
|
38
|
+
"AsyncIPCProvider",
|
|
39
|
+
"AutoProvider",
|
|
40
|
+
"BaseProvider",
|
|
41
|
+
"EthereumTesterProvider",
|
|
42
|
+
"HTTPProvider",
|
|
43
|
+
"IPCProvider",
|
|
44
|
+
"JSONBaseProvider",
|
|
45
|
+
"LegacyWebSocketProvider",
|
|
46
|
+
"PersistentConnection",
|
|
47
|
+
"PersistentConnectionProvider",
|
|
48
|
+
"WebSocketProvider",
|
|
49
|
+
]
|
web3/providers/async_base.py
CHANGED
|
@@ -5,6 +5,7 @@ from typing import (
|
|
|
5
5
|
Any,
|
|
6
6
|
Callable,
|
|
7
7
|
Coroutine,
|
|
8
|
+
List,
|
|
8
9
|
Optional,
|
|
9
10
|
Set,
|
|
10
11
|
Tuple,
|
|
@@ -18,6 +19,7 @@ from eth_utils import (
|
|
|
18
19
|
)
|
|
19
20
|
|
|
20
21
|
from web3._utils.caching import (
|
|
22
|
+
CACHEABLE_REQUESTS,
|
|
21
23
|
async_handle_request_caching,
|
|
22
24
|
)
|
|
23
25
|
from web3._utils.encoding import (
|
|
@@ -56,41 +58,33 @@ if TYPE_CHECKING:
|
|
|
56
58
|
)
|
|
57
59
|
|
|
58
60
|
|
|
59
|
-
CACHEABLE_REQUESTS = cast(
|
|
60
|
-
Set[RPCEndpoint],
|
|
61
|
-
(
|
|
62
|
-
"eth_chainId",
|
|
63
|
-
"eth_getBlockByHash",
|
|
64
|
-
"eth_getBlockTransactionCountByHash",
|
|
65
|
-
"eth_getRawTransactionByHash",
|
|
66
|
-
"eth_getTransactionByBlockHashAndIndex",
|
|
67
|
-
"eth_getTransactionByHash",
|
|
68
|
-
"eth_getUncleByBlockHashAndIndex",
|
|
69
|
-
"eth_getUncleCountByBlockHash",
|
|
70
|
-
"net_version",
|
|
71
|
-
"web3_clientVersion",
|
|
72
|
-
),
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
|
|
76
61
|
class AsyncBaseProvider:
|
|
77
62
|
_request_func_cache: Tuple[
|
|
78
63
|
Tuple[Middleware, ...], Callable[..., Coroutine[Any, Any, RPCResponse]]
|
|
79
64
|
] = (None, None)
|
|
80
65
|
|
|
66
|
+
_is_batching: bool = False
|
|
67
|
+
_batch_request_func_cache: Tuple[
|
|
68
|
+
Tuple[Middleware, ...], Callable[..., Coroutine[Any, Any, List[RPCResponse]]]
|
|
69
|
+
] = (None, None)
|
|
70
|
+
|
|
81
71
|
is_async = True
|
|
82
72
|
has_persistent_connection = False
|
|
83
73
|
global_ccip_read_enabled: bool = True
|
|
84
74
|
ccip_read_max_redirects: int = 4
|
|
85
75
|
|
|
86
76
|
# request caching
|
|
87
|
-
cache_allowed_requests: bool = False
|
|
88
|
-
cacheable_requests: Set[RPCEndpoint] = CACHEABLE_REQUESTS
|
|
89
77
|
_request_cache: SimpleCache
|
|
90
78
|
_request_cache_lock: asyncio.Lock = asyncio.Lock()
|
|
91
79
|
|
|
92
|
-
def __init__(
|
|
80
|
+
def __init__(
|
|
81
|
+
self,
|
|
82
|
+
cache_allowed_requests: bool = False,
|
|
83
|
+
cacheable_requests: Set[RPCEndpoint] = None,
|
|
84
|
+
) -> None:
|
|
93
85
|
self._request_cache = SimpleCache(1000)
|
|
86
|
+
self.cache_allowed_requests = cache_allowed_requests
|
|
87
|
+
self.cacheable_requests = cacheable_requests or CACHEABLE_REQUESTS
|
|
94
88
|
|
|
95
89
|
async def request_func(
|
|
96
90
|
self, async_w3: "AsyncWeb3", middleware_onion: MiddlewareOnion
|
|
@@ -109,10 +103,34 @@ class AsyncBaseProvider:
|
|
|
109
103
|
)
|
|
110
104
|
return self._request_func_cache[-1]
|
|
111
105
|
|
|
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]
|
|
124
|
+
|
|
112
125
|
@async_handle_request_caching
|
|
113
126
|
async def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
|
|
114
127
|
raise NotImplementedError("Providers must implement this method")
|
|
115
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
|
+
|
|
116
134
|
async def is_connected(self, show_traceback: bool = False) -> bool:
|
|
117
135
|
raise NotImplementedError("Providers must implement this method")
|
|
118
136
|
|
|
@@ -141,9 +159,9 @@ class AsyncBaseProvider:
|
|
|
141
159
|
|
|
142
160
|
|
|
143
161
|
class AsyncJSONBaseProvider(AsyncBaseProvider):
|
|
144
|
-
def __init__(self) -> None:
|
|
145
|
-
super().__init__()
|
|
162
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
146
163
|
self.request_counter = itertools.count()
|
|
164
|
+
super().__init__(**kwargs)
|
|
147
165
|
|
|
148
166
|
def encode_rpc_request(self, method: RPCEndpoint, params: Any) -> bytes:
|
|
149
167
|
request_id = next(self.request_counter)
|
|
@@ -156,7 +174,8 @@ class AsyncJSONBaseProvider(AsyncBaseProvider):
|
|
|
156
174
|
encoded = FriendlyJsonSerde().json_encode(rpc_dict, cls=Web3JsonEncoder)
|
|
157
175
|
return to_bytes(text=encoded)
|
|
158
176
|
|
|
159
|
-
|
|
177
|
+
@staticmethod
|
|
178
|
+
def decode_rpc_response(raw_response: bytes) -> RPCResponse:
|
|
160
179
|
text_response = str(
|
|
161
180
|
to_text(raw_response) if not is_text(raw_response) else raw_response
|
|
162
181
|
)
|
|
@@ -185,3 +204,16 @@ class AsyncJSONBaseProvider(AsyncBaseProvider):
|
|
|
185
204
|
if show_traceback:
|
|
186
205
|
raise ProviderConnectionError(f"Bad jsonrpc version: {response}")
|
|
187
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/base.py
CHANGED
|
@@ -4,6 +4,7 @@ from typing import (
|
|
|
4
4
|
TYPE_CHECKING,
|
|
5
5
|
Any,
|
|
6
6
|
Callable,
|
|
7
|
+
List,
|
|
7
8
|
Set,
|
|
8
9
|
Tuple,
|
|
9
10
|
cast,
|
|
@@ -15,6 +16,7 @@ from eth_utils import (
|
|
|
15
16
|
)
|
|
16
17
|
|
|
17
18
|
from web3._utils.caching import (
|
|
19
|
+
CACHEABLE_REQUESTS,
|
|
18
20
|
handle_request_caching,
|
|
19
21
|
)
|
|
20
22
|
from web3._utils.encoding import (
|
|
@@ -43,23 +45,6 @@ if TYPE_CHECKING:
|
|
|
43
45
|
from web3 import Web3 # noqa: F401
|
|
44
46
|
|
|
45
47
|
|
|
46
|
-
CACHEABLE_REQUESTS = cast(
|
|
47
|
-
Set[RPCEndpoint],
|
|
48
|
-
(
|
|
49
|
-
"eth_chainId",
|
|
50
|
-
"eth_getBlockByHash",
|
|
51
|
-
"eth_getBlockTransactionCountByHash",
|
|
52
|
-
"eth_getRawTransactionByHash",
|
|
53
|
-
"eth_getTransactionByBlockHashAndIndex",
|
|
54
|
-
"eth_getTransactionByHash",
|
|
55
|
-
"eth_getUncleByBlockHashAndIndex",
|
|
56
|
-
"eth_getUncleCountByBlockHash",
|
|
57
|
-
"net_version",
|
|
58
|
-
"web3_clientVersion",
|
|
59
|
-
),
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
|
|
63
48
|
class BaseProvider:
|
|
64
49
|
# a tuple of (middleware, request_func)
|
|
65
50
|
_request_func_cache: Tuple[Tuple[Middleware, ...], Callable[..., RPCResponse]] = (
|
|
@@ -73,13 +58,17 @@ class BaseProvider:
|
|
|
73
58
|
ccip_read_max_redirects: int = 4
|
|
74
59
|
|
|
75
60
|
# request caching
|
|
76
|
-
cache_allowed_requests: bool = False
|
|
77
|
-
cacheable_requests: Set[RPCEndpoint] = CACHEABLE_REQUESTS
|
|
78
61
|
_request_cache: SimpleCache
|
|
79
62
|
_request_cache_lock: threading.Lock = threading.Lock()
|
|
80
63
|
|
|
81
|
-
def __init__(
|
|
64
|
+
def __init__(
|
|
65
|
+
self,
|
|
66
|
+
cache_allowed_requests: bool = False,
|
|
67
|
+
cacheable_requests: Set[RPCEndpoint] = None,
|
|
68
|
+
) -> None:
|
|
82
69
|
self._request_cache = SimpleCache(1000)
|
|
70
|
+
self.cache_allowed_requests = cache_allowed_requests
|
|
71
|
+
self.cacheable_requests = cacheable_requests or CACHEABLE_REQUESTS
|
|
83
72
|
|
|
84
73
|
def request_func(
|
|
85
74
|
self, w3: "Web3", middleware_onion: MiddlewareOnion
|
|
@@ -115,13 +104,14 @@ class BaseProvider:
|
|
|
115
104
|
|
|
116
105
|
|
|
117
106
|
class JSONBaseProvider(BaseProvider):
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
107
|
+
_is_batching: bool = False
|
|
108
|
+
_batch_request_func_cache: Tuple[
|
|
109
|
+
Tuple[Middleware, ...], Callable[..., List[RPCResponse]]
|
|
110
|
+
] = (None, None)
|
|
121
111
|
|
|
122
|
-
def
|
|
123
|
-
|
|
124
|
-
|
|
112
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
113
|
+
self.request_counter = itertools.count()
|
|
114
|
+
super().__init__(**kwargs)
|
|
125
115
|
|
|
126
116
|
def encode_rpc_request(self, method: RPCEndpoint, params: Any) -> bytes:
|
|
127
117
|
rpc_dict = {
|
|
@@ -133,6 +123,11 @@ class JSONBaseProvider(BaseProvider):
|
|
|
133
123
|
encoded = FriendlyJsonSerde().json_encode(rpc_dict, Web3JsonEncoder)
|
|
134
124
|
return to_bytes(text=encoded)
|
|
135
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
|
+
|
|
136
131
|
def is_connected(self, show_traceback: bool = False) -> bool:
|
|
137
132
|
try:
|
|
138
133
|
response = self.make_request(RPCEndpoint("web3_clientVersion"), [])
|
|
@@ -156,3 +151,41 @@ class JSONBaseProvider(BaseProvider):
|
|
|
156
151
|
if show_traceback:
|
|
157
152
|
raise ProviderConnectionError(f"Bad jsonrpc version: {response}")
|
|
158
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")
|
|
@@ -243,12 +243,6 @@ API_ENDPOINTS = {
|
|
|
243
243
|
"eth": {
|
|
244
244
|
"protocolVersion": static_return(63),
|
|
245
245
|
"syncing": static_return(False),
|
|
246
|
-
"coinbase": compose(
|
|
247
|
-
operator.itemgetter(0),
|
|
248
|
-
call_eth_tester("get_accounts"),
|
|
249
|
-
),
|
|
250
|
-
"mining": static_return(False),
|
|
251
|
-
"hashrate": static_return(0),
|
|
252
246
|
"chainId": static_return(131277322940537), # from fixture generation file
|
|
253
247
|
"feeHistory": call_eth_tester("get_fee_history"),
|
|
254
248
|
"maxPriorityFeePerGas": static_return(10**9),
|
|
@@ -59,7 +59,7 @@ if TYPE_CHECKING:
|
|
|
59
59
|
|
|
60
60
|
|
|
61
61
|
def is_named_block(value: Any) -> bool:
|
|
62
|
-
return value in {"latest", "earliest", "
|
|
62
|
+
return value in {"latest", "earliest", "safe", "finalized"}
|
|
63
63
|
|
|
64
64
|
|
|
65
65
|
def is_hexstr(value: Any) -> bool:
|
|
@@ -334,9 +334,7 @@ result_formatters: Optional[Dict[RPCEndpoint, Callable[..., Any]]] = {
|
|
|
334
334
|
|
|
335
335
|
|
|
336
336
|
def guess_from(w3: "Web3", _: TxParams) -> ChecksumAddress:
|
|
337
|
-
if w3.eth.
|
|
338
|
-
return w3.eth.coinbase
|
|
339
|
-
elif w3.eth.accounts and len(w3.eth.accounts) > 0:
|
|
337
|
+
if w3.eth.accounts and len(w3.eth.accounts) > 0:
|
|
340
338
|
return w3.eth.accounts[0]
|
|
341
339
|
|
|
342
340
|
return None
|
|
@@ -360,11 +358,8 @@ def fill_default(
|
|
|
360
358
|
async def async_guess_from(
|
|
361
359
|
async_w3: "AsyncWeb3", _: TxParams
|
|
362
360
|
) -> Optional[ChecksumAddress]:
|
|
363
|
-
coinbase = await async_w3.eth.coinbase
|
|
364
361
|
accounts = await async_w3.eth.accounts
|
|
365
|
-
if
|
|
366
|
-
return coinbase
|
|
367
|
-
elif accounts is not None and len(accounts) > 0:
|
|
362
|
+
if accounts is not None and len(accounts) > 0:
|
|
368
363
|
return accounts[0]
|
|
369
364
|
return None
|
|
370
365
|
|