web3 7.0.0b2__py3-none-any.whl → 7.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ens/__init__.py +13 -2
- ens/_normalization.py +4 -4
- ens/async_ens.py +27 -15
- ens/base_ens.py +3 -1
- ens/contract_data.py +2 -2
- ens/ens.py +10 -7
- ens/exceptions.py +16 -29
- ens/specs/nf.json +1 -1
- ens/specs/normalization_spec.json +1 -1
- ens/utils.py +24 -32
- web3/__init__.py +23 -12
- web3/_utils/abi.py +157 -263
- 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 +49 -34
- 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 -17
- web3/manager.py +362 -95
- web3/method.py +43 -15
- web3/middleware/__init__.py +17 -0
- 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 +61 -25
- web3/providers/__init__.py +21 -0
- web3/providers/async_base.py +87 -32
- web3/providers/base.py +77 -32
- web3/providers/eth_tester/__init__.py +5 -0
- web3/providers/eth_tester/defaults.py +2 -55
- web3/providers/eth_tester/main.py +41 -15
- web3/providers/eth_tester/middleware.py +16 -17
- web3/providers/ipc.py +41 -17
- web3/providers/legacy_websocket.py +26 -1
- web3/providers/persistent/__init__.py +7 -0
- web3/providers/persistent/async_ipc.py +61 -121
- web3/providers/persistent/persistent.py +323 -16
- 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.0b2.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.0b2.dist-info → web3-7.7.0.dist-info}/WHEEL +1 -1
- 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-7.0.0b2.dist-info/METADATA +0 -106
- web3-7.0.0b2.dist-info/RECORD +0 -163
- /web3/_utils/{function_identifiers.py → abi_element_identifiers.py} +0 -0
- {web3-7.0.0b2.dist-info → web3-7.7.0.dist-info}/top_level.txt +0 -0
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,
|
|
@@ -30,6 +32,7 @@ from web3.providers.persistent import (
|
|
|
30
32
|
PersistentConnectionProvider,
|
|
31
33
|
)
|
|
32
34
|
from web3.types import (
|
|
35
|
+
FormattedEthSubscriptionResponse,
|
|
33
36
|
RPCEndpoint,
|
|
34
37
|
RPCResponse,
|
|
35
38
|
)
|
|
@@ -55,9 +58,43 @@ def apply_result_formatters(
|
|
|
55
58
|
TReturn = TypeVar("TReturn")
|
|
56
59
|
|
|
57
60
|
|
|
61
|
+
@curry
|
|
62
|
+
def retrieve_request_information_for_batching(
|
|
63
|
+
w3: Union["AsyncWeb3", "Web3"],
|
|
64
|
+
module: "Module",
|
|
65
|
+
method: Method[Callable[..., Any]],
|
|
66
|
+
) -> Union[
|
|
67
|
+
Callable[..., Tuple[Tuple[RPCEndpoint, Any], Sequence[Any]]],
|
|
68
|
+
Callable[..., Coroutine[Any, Any, Tuple[Tuple[RPCEndpoint, Any], Sequence[Any]]]],
|
|
69
|
+
]:
|
|
70
|
+
async def async_inner(
|
|
71
|
+
*args: Any, **kwargs: Any
|
|
72
|
+
) -> Tuple[Tuple[RPCEndpoint, Any], Sequence[Any]]:
|
|
73
|
+
(method_str, params), response_formatters = method.process_params(
|
|
74
|
+
module, *args, **kwargs
|
|
75
|
+
)
|
|
76
|
+
if isinstance(w3.provider, PersistentConnectionProvider):
|
|
77
|
+
w3.provider._request_processor.cache_request_information(
|
|
78
|
+
None, cast(RPCEndpoint, method_str), params, response_formatters
|
|
79
|
+
)
|
|
80
|
+
return (cast(RPCEndpoint, method_str), params), response_formatters
|
|
81
|
+
|
|
82
|
+
def inner(
|
|
83
|
+
*args: Any, **kwargs: Any
|
|
84
|
+
) -> Tuple[Tuple[RPCEndpoint, Any], Sequence[Any]]:
|
|
85
|
+
(method_str, params), response_formatters = method.process_params(
|
|
86
|
+
module, *args, **kwargs
|
|
87
|
+
)
|
|
88
|
+
return (cast(RPCEndpoint, method_str), params), response_formatters
|
|
89
|
+
|
|
90
|
+
return async_inner if module.is_async else inner
|
|
91
|
+
|
|
92
|
+
|
|
58
93
|
@curry
|
|
59
94
|
def retrieve_blocking_method_call_fn(
|
|
60
|
-
w3: "Web3",
|
|
95
|
+
w3: "Web3",
|
|
96
|
+
module: "Module",
|
|
97
|
+
method: Method[Callable[..., TReturn]],
|
|
61
98
|
) -> Callable[..., Union[TReturn, LogFilter]]:
|
|
62
99
|
def caller(*args: Any, **kwargs: Any) -> Union[TReturn, LogFilter]:
|
|
63
100
|
try:
|
|
@@ -82,9 +119,20 @@ def retrieve_blocking_method_call_fn(
|
|
|
82
119
|
|
|
83
120
|
@curry
|
|
84
121
|
def retrieve_async_method_call_fn(
|
|
85
|
-
async_w3: "AsyncWeb3",
|
|
86
|
-
|
|
87
|
-
|
|
122
|
+
async_w3: "AsyncWeb3",
|
|
123
|
+
module: "Module",
|
|
124
|
+
method: Method[Callable[..., Any]],
|
|
125
|
+
) -> Callable[
|
|
126
|
+
...,
|
|
127
|
+
Coroutine[
|
|
128
|
+
Any,
|
|
129
|
+
Any,
|
|
130
|
+
Optional[Union[RPCResponse, FormattedEthSubscriptionResponse, AsyncLogFilter]],
|
|
131
|
+
],
|
|
132
|
+
]:
|
|
133
|
+
async def caller(
|
|
134
|
+
*args: Any, **kwargs: Any
|
|
135
|
+
) -> Union[RPCResponse, FormattedEthSubscriptionResponse, AsyncLogFilter]:
|
|
88
136
|
try:
|
|
89
137
|
(method_str, params), response_formatters = method.process_params(
|
|
90
138
|
module, *args, **kwargs
|
|
@@ -93,32 +141,17 @@ def retrieve_async_method_call_fn(
|
|
|
93
141
|
return AsyncLogFilter(eth_module=module, filter_id=err.filter_id)
|
|
94
142
|
|
|
95
143
|
if isinstance(async_w3.provider, PersistentConnectionProvider):
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
cast(RPCEndpoint, method_str), params, response_formatters # type: ignore # noqa: E501
|
|
144
|
+
return await async_w3.manager.socket_request(
|
|
145
|
+
cast(RPCEndpoint, method_str),
|
|
146
|
+
params,
|
|
147
|
+
response_formatters=response_formatters,
|
|
101
148
|
)
|
|
102
|
-
try:
|
|
103
|
-
method_str = cast(RPCEndpoint, method_str)
|
|
104
|
-
return await async_w3.manager.send(method_str, params)
|
|
105
|
-
except Exception as e:
|
|
106
|
-
if (
|
|
107
|
-
cache_key is not None
|
|
108
|
-
and cache_key
|
|
109
|
-
in provider._request_processor._request_information_cache
|
|
110
|
-
):
|
|
111
|
-
provider._request_processor.pop_cached_request_information(
|
|
112
|
-
cache_key
|
|
113
|
-
)
|
|
114
|
-
raise e
|
|
115
149
|
else:
|
|
116
150
|
(
|
|
117
151
|
result_formatters,
|
|
118
152
|
error_formatters,
|
|
119
153
|
null_result_formatters,
|
|
120
154
|
) = response_formatters
|
|
121
|
-
|
|
122
155
|
result = await async_w3.manager.coro_request(
|
|
123
156
|
method_str, params, error_formatters, null_result_formatters
|
|
124
157
|
)
|
|
@@ -139,6 +172,9 @@ class Module:
|
|
|
139
172
|
self.retrieve_caller_fn = retrieve_async_method_call_fn(w3, self)
|
|
140
173
|
else:
|
|
141
174
|
self.retrieve_caller_fn = retrieve_blocking_method_call_fn(w3, self)
|
|
175
|
+
self.retrieve_request_information = retrieve_request_information_for_batching(
|
|
176
|
+
w3, self
|
|
177
|
+
)
|
|
142
178
|
self.w3 = w3
|
|
143
179
|
|
|
144
180
|
@property
|
|
@@ -152,8 +188,8 @@ class Module:
|
|
|
152
188
|
) -> None:
|
|
153
189
|
for method_name, method_class in methods.items():
|
|
154
190
|
klass = (
|
|
155
|
-
method_class.__get__(
|
|
191
|
+
method_class.__get__(module=self)()
|
|
156
192
|
if method_class.is_property
|
|
157
|
-
else method_class.__get__(
|
|
193
|
+
else method_class.__get__(module=self)
|
|
158
194
|
)
|
|
159
195
|
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
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import itertools
|
|
3
|
+
import logging
|
|
3
4
|
from typing import (
|
|
4
5
|
TYPE_CHECKING,
|
|
5
6
|
Any,
|
|
6
7
|
Callable,
|
|
7
8
|
Coroutine,
|
|
9
|
+
Dict,
|
|
10
|
+
List,
|
|
8
11
|
Optional,
|
|
9
12
|
Set,
|
|
10
13
|
Tuple,
|
|
14
|
+
Union,
|
|
11
15
|
cast,
|
|
12
16
|
)
|
|
13
17
|
|
|
@@ -18,7 +22,11 @@ from eth_utils import (
|
|
|
18
22
|
)
|
|
19
23
|
|
|
20
24
|
from web3._utils.caching import (
|
|
21
|
-
|
|
25
|
+
CACHEABLE_REQUESTS,
|
|
26
|
+
)
|
|
27
|
+
from web3._utils.empty import (
|
|
28
|
+
Empty,
|
|
29
|
+
empty,
|
|
22
30
|
)
|
|
23
31
|
from web3._utils.encoding import (
|
|
24
32
|
FriendlyJsonSerde,
|
|
@@ -36,9 +44,11 @@ from web3.middleware.base import (
|
|
|
36
44
|
)
|
|
37
45
|
from web3.types import (
|
|
38
46
|
RPCEndpoint,
|
|
47
|
+
RPCRequest,
|
|
39
48
|
RPCResponse,
|
|
40
49
|
)
|
|
41
50
|
from web3.utils import (
|
|
51
|
+
RequestCacheValidationThreshold,
|
|
42
52
|
SimpleCache,
|
|
43
53
|
)
|
|
44
54
|
|
|
@@ -56,41 +66,39 @@ if TYPE_CHECKING:
|
|
|
56
66
|
)
|
|
57
67
|
|
|
58
68
|
|
|
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
69
|
class AsyncBaseProvider:
|
|
70
|
+
# Set generic logger for the provider. Override in subclasses for more specificity.
|
|
71
|
+
logger: logging.Logger = logging.getLogger(
|
|
72
|
+
"web3.providers.async_base.AsyncBaseProvider"
|
|
73
|
+
)
|
|
77
74
|
_request_func_cache: Tuple[
|
|
78
75
|
Tuple[Middleware, ...], Callable[..., Coroutine[Any, Any, RPCResponse]]
|
|
79
76
|
] = (None, None)
|
|
80
77
|
|
|
78
|
+
_is_batching: bool = False
|
|
79
|
+
_batch_request_func_cache: Tuple[
|
|
80
|
+
Tuple[Middleware, ...], Callable[..., Coroutine[Any, Any, List[RPCResponse]]]
|
|
81
|
+
] = (None, None)
|
|
82
|
+
|
|
81
83
|
is_async = True
|
|
82
84
|
has_persistent_connection = False
|
|
83
85
|
global_ccip_read_enabled: bool = True
|
|
84
86
|
ccip_read_max_redirects: int = 4
|
|
85
87
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
def __init__(
|
|
89
|
+
self,
|
|
90
|
+
cache_allowed_requests: bool = False,
|
|
91
|
+
cacheable_requests: Set[RPCEndpoint] = None,
|
|
92
|
+
request_cache_validation_threshold: Optional[
|
|
93
|
+
Union[RequestCacheValidationThreshold, int, Empty]
|
|
94
|
+
] = empty,
|
|
95
|
+
) -> None:
|
|
93
96
|
self._request_cache = SimpleCache(1000)
|
|
97
|
+
self._request_cache_lock: asyncio.Lock = asyncio.Lock()
|
|
98
|
+
|
|
99
|
+
self.cache_allowed_requests = cache_allowed_requests
|
|
100
|
+
self.cacheable_requests = cacheable_requests or CACHEABLE_REQUESTS
|
|
101
|
+
self.request_cache_validation_threshold = request_cache_validation_threshold
|
|
94
102
|
|
|
95
103
|
async def request_func(
|
|
96
104
|
self, async_w3: "AsyncWeb3", middleware_onion: MiddlewareOnion
|
|
@@ -109,10 +117,33 @@ class AsyncBaseProvider:
|
|
|
109
117
|
)
|
|
110
118
|
return self._request_func_cache[-1]
|
|
111
119
|
|
|
112
|
-
|
|
120
|
+
async def batch_request_func(
|
|
121
|
+
self, async_w3: "AsyncWeb3", middleware_onion: MiddlewareOnion
|
|
122
|
+
) -> Callable[..., Coroutine[Any, Any, List[RPCResponse]]]:
|
|
123
|
+
middleware: Tuple[Middleware, ...] = middleware_onion.as_tuple_of_middleware()
|
|
124
|
+
|
|
125
|
+
cache_key = self._batch_request_func_cache[0]
|
|
126
|
+
if cache_key != middleware:
|
|
127
|
+
accumulator_fn = self.make_batch_request
|
|
128
|
+
for mw in reversed(middleware):
|
|
129
|
+
initialized = mw(async_w3)
|
|
130
|
+
# type ignore bc in order to wrap the method, we have to call
|
|
131
|
+
# `async_wrap_make_batch_request` with the accumulator_fn as the
|
|
132
|
+
# argument which breaks the type hinting for this particular case.
|
|
133
|
+
accumulator_fn = await initialized.async_wrap_make_batch_request( # type: ignore # noqa: E501
|
|
134
|
+
accumulator_fn
|
|
135
|
+
)
|
|
136
|
+
self._batch_request_func_cache = (middleware, accumulator_fn)
|
|
137
|
+
return self._batch_request_func_cache[-1]
|
|
138
|
+
|
|
113
139
|
async def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
|
|
114
140
|
raise NotImplementedError("Providers must implement this method")
|
|
115
141
|
|
|
142
|
+
async def make_batch_request(
|
|
143
|
+
self, requests: List[Tuple[RPCEndpoint, Any]]
|
|
144
|
+
) -> List[RPCResponse]:
|
|
145
|
+
raise NotImplementedError("Only AsyncHTTPProvider supports this method")
|
|
146
|
+
|
|
116
147
|
async def is_connected(self, show_traceback: bool = False) -> bool:
|
|
117
148
|
raise NotImplementedError("Providers must implement this method")
|
|
118
149
|
|
|
@@ -141,22 +172,33 @@ class AsyncBaseProvider:
|
|
|
141
172
|
|
|
142
173
|
|
|
143
174
|
class AsyncJSONBaseProvider(AsyncBaseProvider):
|
|
144
|
-
def __init__(self) -> None:
|
|
145
|
-
super().__init__()
|
|
175
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
176
|
+
super().__init__(**kwargs)
|
|
146
177
|
self.request_counter = itertools.count()
|
|
147
178
|
|
|
148
|
-
def
|
|
179
|
+
def form_request(self, method: RPCEndpoint, params: Any = None) -> RPCRequest:
|
|
149
180
|
request_id = next(self.request_counter)
|
|
150
181
|
rpc_dict = {
|
|
182
|
+
"id": request_id,
|
|
151
183
|
"jsonrpc": "2.0",
|
|
152
184
|
"method": method,
|
|
153
185
|
"params": params or [],
|
|
154
|
-
"id": request_id,
|
|
155
186
|
}
|
|
156
|
-
|
|
187
|
+
return cast(RPCRequest, rpc_dict)
|
|
188
|
+
|
|
189
|
+
@staticmethod
|
|
190
|
+
def encode_rpc_dict(rpc_dict: RPCRequest) -> bytes:
|
|
191
|
+
encoded = FriendlyJsonSerde().json_encode(
|
|
192
|
+
cast(Dict[str, Any], rpc_dict), cls=Web3JsonEncoder
|
|
193
|
+
)
|
|
157
194
|
return to_bytes(text=encoded)
|
|
158
195
|
|
|
159
|
-
def
|
|
196
|
+
def encode_rpc_request(self, method: RPCEndpoint, params: Any) -> bytes:
|
|
197
|
+
rpc_dict = self.form_request(method, params)
|
|
198
|
+
return self.encode_rpc_dict(rpc_dict)
|
|
199
|
+
|
|
200
|
+
@staticmethod
|
|
201
|
+
def decode_rpc_response(raw_response: bytes) -> RPCResponse:
|
|
160
202
|
text_response = str(
|
|
161
203
|
to_text(raw_response) if not is_text(raw_response) else raw_response
|
|
162
204
|
)
|
|
@@ -185,3 +227,16 @@ class AsyncJSONBaseProvider(AsyncBaseProvider):
|
|
|
185
227
|
if show_traceback:
|
|
186
228
|
raise ProviderConnectionError(f"Bad jsonrpc version: {response}")
|
|
187
229
|
return False
|
|
230
|
+
|
|
231
|
+
# -- batch requests -- #
|
|
232
|
+
|
|
233
|
+
def encode_batch_rpc_request(
|
|
234
|
+
self, requests: List[Tuple[RPCEndpoint, Any]]
|
|
235
|
+
) -> bytes:
|
|
236
|
+
return (
|
|
237
|
+
b"["
|
|
238
|
+
+ b", ".join(
|
|
239
|
+
self.encode_rpc_request(method, params) for method, params in requests
|
|
240
|
+
)
|
|
241
|
+
+ b"]"
|
|
242
|
+
)
|
web3/providers/base.py
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import itertools
|
|
2
|
+
import logging
|
|
2
3
|
import threading
|
|
3
4
|
from typing import (
|
|
4
5
|
TYPE_CHECKING,
|
|
5
6
|
Any,
|
|
6
7
|
Callable,
|
|
8
|
+
List,
|
|
9
|
+
Optional,
|
|
7
10
|
Set,
|
|
8
11
|
Tuple,
|
|
12
|
+
Union,
|
|
9
13
|
cast,
|
|
10
14
|
)
|
|
11
15
|
|
|
@@ -15,7 +19,11 @@ from eth_utils import (
|
|
|
15
19
|
)
|
|
16
20
|
|
|
17
21
|
from web3._utils.caching import (
|
|
18
|
-
|
|
22
|
+
CACHEABLE_REQUESTS,
|
|
23
|
+
)
|
|
24
|
+
from web3._utils.empty import (
|
|
25
|
+
Empty,
|
|
26
|
+
empty,
|
|
19
27
|
)
|
|
20
28
|
from web3._utils.encoding import (
|
|
21
29
|
FriendlyJsonSerde,
|
|
@@ -36,6 +44,7 @@ from web3.types import (
|
|
|
36
44
|
RPCResponse,
|
|
37
45
|
)
|
|
38
46
|
from web3.utils import (
|
|
47
|
+
RequestCacheValidationThreshold,
|
|
39
48
|
SimpleCache,
|
|
40
49
|
)
|
|
41
50
|
|
|
@@ -43,24 +52,9 @@ if TYPE_CHECKING:
|
|
|
43
52
|
from web3 import Web3 # noqa: F401
|
|
44
53
|
|
|
45
54
|
|
|
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
55
|
class BaseProvider:
|
|
56
|
+
# Set generic logger for the provider. Override in subclasses for more specificity.
|
|
57
|
+
logger: logging.Logger = logging.getLogger("web3.providers.base.BaseProvider")
|
|
64
58
|
# a tuple of (middleware, request_func)
|
|
65
59
|
_request_func_cache: Tuple[Tuple[Middleware, ...], Callable[..., RPCResponse]] = (
|
|
66
60
|
None,
|
|
@@ -72,14 +66,20 @@ class BaseProvider:
|
|
|
72
66
|
global_ccip_read_enabled: bool = True
|
|
73
67
|
ccip_read_max_redirects: int = 4
|
|
74
68
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
69
|
+
def __init__(
|
|
70
|
+
self,
|
|
71
|
+
cache_allowed_requests: bool = False,
|
|
72
|
+
cacheable_requests: Set[RPCEndpoint] = None,
|
|
73
|
+
request_cache_validation_threshold: Optional[
|
|
74
|
+
Union[RequestCacheValidationThreshold, int, Empty]
|
|
75
|
+
] = empty,
|
|
76
|
+
) -> None:
|
|
82
77
|
self._request_cache = SimpleCache(1000)
|
|
78
|
+
self._request_cache_lock: threading.Lock = threading.Lock()
|
|
79
|
+
|
|
80
|
+
self.cache_allowed_requests = cache_allowed_requests
|
|
81
|
+
self.cacheable_requests = cacheable_requests or CACHEABLE_REQUESTS
|
|
82
|
+
self.request_cache_validation_threshold = request_cache_validation_threshold
|
|
83
83
|
|
|
84
84
|
def request_func(
|
|
85
85
|
self, w3: "Web3", middleware_onion: MiddlewareOnion
|
|
@@ -106,7 +106,6 @@ class BaseProvider:
|
|
|
106
106
|
|
|
107
107
|
return self._request_func_cache[-1]
|
|
108
108
|
|
|
109
|
-
@handle_request_caching
|
|
110
109
|
def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
|
|
111
110
|
raise NotImplementedError("Providers must implement this method")
|
|
112
111
|
|
|
@@ -115,13 +114,16 @@ class BaseProvider:
|
|
|
115
114
|
|
|
116
115
|
|
|
117
116
|
class JSONBaseProvider(BaseProvider):
|
|
118
|
-
|
|
119
|
-
self.request_counter = itertools.count()
|
|
120
|
-
super().__init__()
|
|
117
|
+
logger = logging.getLogger("web3.providers.base.JSONBaseProvider")
|
|
121
118
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
119
|
+
_is_batching: bool = False
|
|
120
|
+
_batch_request_func_cache: Tuple[
|
|
121
|
+
Tuple[Middleware, ...], Callable[..., List[RPCResponse]]
|
|
122
|
+
] = (None, None)
|
|
123
|
+
|
|
124
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
125
|
+
super().__init__(**kwargs)
|
|
126
|
+
self.request_counter = itertools.count()
|
|
125
127
|
|
|
126
128
|
def encode_rpc_request(self, method: RPCEndpoint, params: Any) -> bytes:
|
|
127
129
|
rpc_dict = {
|
|
@@ -133,6 +135,11 @@ class JSONBaseProvider(BaseProvider):
|
|
|
133
135
|
encoded = FriendlyJsonSerde().json_encode(rpc_dict, Web3JsonEncoder)
|
|
134
136
|
return to_bytes(text=encoded)
|
|
135
137
|
|
|
138
|
+
@staticmethod
|
|
139
|
+
def decode_rpc_response(raw_response: bytes) -> RPCResponse:
|
|
140
|
+
text_response = to_text(raw_response)
|
|
141
|
+
return cast(RPCResponse, FriendlyJsonSerde().json_decode(text_response))
|
|
142
|
+
|
|
136
143
|
def is_connected(self, show_traceback: bool = False) -> bool:
|
|
137
144
|
try:
|
|
138
145
|
response = self.make_request(RPCEndpoint("web3_clientVersion"), [])
|
|
@@ -156,3 +163,41 @@ class JSONBaseProvider(BaseProvider):
|
|
|
156
163
|
if show_traceback:
|
|
157
164
|
raise ProviderConnectionError(f"Bad jsonrpc version: {response}")
|
|
158
165
|
return False
|
|
166
|
+
|
|
167
|
+
# -- batch requests -- #
|
|
168
|
+
|
|
169
|
+
def batch_request_func(
|
|
170
|
+
self, w3: "Web3", middleware_onion: MiddlewareOnion
|
|
171
|
+
) -> Callable[..., List[RPCResponse]]:
|
|
172
|
+
middleware: Tuple[Middleware, ...] = middleware_onion.as_tuple_of_middleware()
|
|
173
|
+
|
|
174
|
+
cache_key = self._batch_request_func_cache[0]
|
|
175
|
+
if cache_key != middleware:
|
|
176
|
+
accumulator_fn = self.make_batch_request
|
|
177
|
+
for mw in reversed(middleware):
|
|
178
|
+
initialized = mw(w3)
|
|
179
|
+
# type ignore bc in order to wrap the method, we have to call
|
|
180
|
+
# `wrap_make_batch_request` with the accumulator_fn as the argument
|
|
181
|
+
# which breaks the type hinting for this particular case.
|
|
182
|
+
accumulator_fn = initialized.wrap_make_batch_request(
|
|
183
|
+
accumulator_fn
|
|
184
|
+
) # type: ignore # noqa: E501
|
|
185
|
+
self._batch_request_func_cache = (middleware, accumulator_fn)
|
|
186
|
+
|
|
187
|
+
return self._batch_request_func_cache[-1]
|
|
188
|
+
|
|
189
|
+
def encode_batch_rpc_request(
|
|
190
|
+
self, requests: List[Tuple[RPCEndpoint, Any]]
|
|
191
|
+
) -> bytes:
|
|
192
|
+
return (
|
|
193
|
+
b"["
|
|
194
|
+
+ b", ".join(
|
|
195
|
+
self.encode_rpc_request(method, params) for method, params in requests
|
|
196
|
+
)
|
|
197
|
+
+ b"]"
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
def make_batch_request(
|
|
201
|
+
self, requests: List[Tuple[RPCEndpoint, Any]]
|
|
202
|
+
) -> List[RPCResponse]:
|
|
203
|
+
raise NotImplementedError("Providers must implement this method")
|
|
@@ -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(
|
|
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,15 +243,10 @@ 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),
|
|
249
|
+
"blobBaseFee": static_return(10**9),
|
|
268
250
|
"gasPrice": static_return(10**9), # must be >= base fee post-London
|
|
269
251
|
"accounts": call_eth_tester("get_accounts"),
|
|
270
252
|
"blockNumber": compose(
|
|
@@ -404,41 +386,6 @@ API_ENDPOINTS = {
|
|
|
404
386
|
"writeBlockProfile": not_implemented,
|
|
405
387
|
"writeMemProfile": not_implemented,
|
|
406
388
|
},
|
|
407
|
-
"personal": {
|
|
408
|
-
"ec_recover": not_implemented,
|
|
409
|
-
"import_raw_key": call_eth_tester("add_account"),
|
|
410
|
-
"list_accounts": call_eth_tester("get_accounts"),
|
|
411
|
-
"list_wallets": not_implemented,
|
|
412
|
-
"lock_account": excepts(
|
|
413
|
-
ValidationError,
|
|
414
|
-
compose(static_return(True), call_eth_tester("lock_account")),
|
|
415
|
-
static_return(False),
|
|
416
|
-
),
|
|
417
|
-
"new_account": create_new_account,
|
|
418
|
-
"unlock_account": excepts(
|
|
419
|
-
ValidationError,
|
|
420
|
-
compose(static_return(True), call_eth_tester("unlock_account")),
|
|
421
|
-
static_return(False),
|
|
422
|
-
),
|
|
423
|
-
"send_transaction": personal_send_transaction,
|
|
424
|
-
"sign": not_implemented,
|
|
425
|
-
# deprecated
|
|
426
|
-
"ecRecover": not_implemented,
|
|
427
|
-
"importRawKey": call_eth_tester("add_account"),
|
|
428
|
-
"listAccounts": call_eth_tester("get_accounts"),
|
|
429
|
-
"lockAccount": excepts(
|
|
430
|
-
ValidationError,
|
|
431
|
-
compose(static_return(True), call_eth_tester("lock_account")),
|
|
432
|
-
static_return(False),
|
|
433
|
-
),
|
|
434
|
-
"newAccount": create_new_account,
|
|
435
|
-
"unlockAccount": excepts(
|
|
436
|
-
ValidationError,
|
|
437
|
-
compose(static_return(True), call_eth_tester("unlock_account")),
|
|
438
|
-
static_return(False),
|
|
439
|
-
),
|
|
440
|
-
"sendTransaction": personal_send_transaction,
|
|
441
|
-
},
|
|
442
389
|
"testing": {
|
|
443
390
|
"timeTravel": call_eth_tester("time_travel"),
|
|
444
391
|
},
|