web3 7.0.0b4__py3-none-any.whl → 7.0.0b6__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.
- web3/_utils/batching.py +217 -0
- web3/_utils/caching.py +26 -2
- web3/_utils/compat/__init__.py +1 -0
- web3/_utils/contracts.py +5 -5
- web3/_utils/events.py +20 -20
- web3/_utils/filters.py +6 -6
- web3/_utils/method_formatters.py +0 -23
- web3/_utils/module_testing/__init__.py +0 -3
- web3/_utils/module_testing/eth_module.py +442 -373
- web3/_utils/module_testing/module_testing_utils.py +13 -0
- web3/_utils/module_testing/web3_module.py +438 -17
- web3/_utils/rpc_abi.py +0 -18
- web3/contract/async_contract.py +11 -11
- web3/contract/base_contract.py +19 -18
- web3/contract/contract.py +13 -13
- web3/contract/utils.py +112 -4
- web3/eth/async_eth.py +10 -8
- web3/eth/eth.py +7 -6
- web3/exceptions.py +75 -21
- web3/gas_strategies/time_based.py +2 -2
- web3/geth.py +0 -188
- web3/main.py +21 -13
- web3/manager.py +237 -74
- web3/method.py +29 -9
- web3/middleware/base.py +43 -0
- web3/middleware/filter.py +18 -6
- web3/middleware/signing.py +2 -2
- web3/module.py +47 -7
- web3/providers/async_base.py +55 -23
- web3/providers/base.py +59 -26
- web3/providers/eth_tester/defaults.py +0 -48
- web3/providers/eth_tester/main.py +36 -11
- web3/providers/eth_tester/middleware.py +3 -8
- web3/providers/ipc.py +23 -8
- web3/providers/legacy_websocket.py +26 -1
- 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/async_rpc.py +20 -2
- web3/providers/rpc/rpc.py +22 -2
- web3/providers/rpc/utils.py +1 -10
- web3/tools/benchmark/node.py +2 -8
- web3/types.py +8 -2
- {web3-7.0.0b4.dist-info → web3-7.0.0b6.dist-info}/LICENSE +1 -1
- {web3-7.0.0b4.dist-info → web3-7.0.0b6.dist-info}/METADATA +32 -21
- {web3-7.0.0b4.dist-info → web3-7.0.0b6.dist-info}/RECORD +49 -49
- web3/_utils/module_testing/go_ethereum_personal_module.py +0 -300
- {web3-7.0.0b4.dist-info → web3-7.0.0b6.dist-info}/WHEEL +0 -0
- {web3-7.0.0b4.dist-info → web3-7.0.0b6.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,
|
|
@@ -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/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")
|
|
@@ -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,
|
|
@@ -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,
|
|
@@ -404,41 +391,6 @@ API_ENDPOINTS = {
|
|
|
404
391
|
"writeBlockProfile": not_implemented,
|
|
405
392
|
"writeMemProfile": not_implemented,
|
|
406
393
|
},
|
|
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
394
|
"testing": {
|
|
443
395
|
"timeTravel": call_eth_tester("time_travel"),
|
|
444
396
|
},
|
|
@@ -7,6 +7,7 @@ from typing import (
|
|
|
7
7
|
Literal,
|
|
8
8
|
Optional,
|
|
9
9
|
Union,
|
|
10
|
+
cast,
|
|
10
11
|
)
|
|
11
12
|
|
|
12
13
|
from eth_abi import (
|
|
@@ -59,6 +60,7 @@ if TYPE_CHECKING:
|
|
|
59
60
|
|
|
60
61
|
|
|
61
62
|
class AsyncEthereumTesterProvider(AsyncBaseProvider):
|
|
63
|
+
_current_request_id = 0
|
|
62
64
|
_middleware = (
|
|
63
65
|
default_transaction_fields_middleware,
|
|
64
66
|
ethereum_tester_middleware,
|
|
@@ -99,13 +101,22 @@ class AsyncEthereumTesterProvider(AsyncBaseProvider):
|
|
|
99
101
|
return self._request_func_cache[-1]
|
|
100
102
|
|
|
101
103
|
async def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
|
|
102
|
-
|
|
104
|
+
response = _make_request(
|
|
105
|
+
method,
|
|
106
|
+
params,
|
|
107
|
+
self.api_endpoints,
|
|
108
|
+
self.ethereum_tester,
|
|
109
|
+
repr(self._current_request_id),
|
|
110
|
+
)
|
|
111
|
+
self._current_request_id += 1
|
|
112
|
+
return response
|
|
103
113
|
|
|
104
114
|
async def is_connected(self, show_traceback: bool = False) -> Literal[True]:
|
|
105
115
|
return True
|
|
106
116
|
|
|
107
117
|
|
|
108
118
|
class EthereumTesterProvider(BaseProvider):
|
|
119
|
+
_current_request_id = 0
|
|
109
120
|
_middleware = (
|
|
110
121
|
default_transaction_fields_middleware,
|
|
111
122
|
ethereum_tester_middleware,
|
|
@@ -173,23 +184,32 @@ class EthereumTesterProvider(BaseProvider):
|
|
|
173
184
|
return self._request_func_cache[-1]
|
|
174
185
|
|
|
175
186
|
def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
|
|
176
|
-
|
|
187
|
+
response = _make_request(
|
|
188
|
+
method,
|
|
189
|
+
params,
|
|
190
|
+
self.api_endpoints,
|
|
191
|
+
self.ethereum_tester,
|
|
192
|
+
repr(self._current_request_id),
|
|
193
|
+
)
|
|
194
|
+
self._current_request_id += 1
|
|
195
|
+
return response
|
|
177
196
|
|
|
178
197
|
def is_connected(self, show_traceback: bool = False) -> Literal[True]:
|
|
179
198
|
return True
|
|
180
199
|
|
|
181
200
|
|
|
182
|
-
def _make_response(result: Any, message: str = "") -> RPCResponse:
|
|
201
|
+
def _make_response(result: Any, response_id: str, message: str = "") -> RPCResponse:
|
|
183
202
|
if isinstance(result, Exception):
|
|
184
|
-
return
|
|
203
|
+
return cast(
|
|
204
|
+
RPCResponse,
|
|
185
205
|
{
|
|
186
|
-
"id":
|
|
206
|
+
"id": response_id,
|
|
187
207
|
"jsonrpc": "2.0",
|
|
188
|
-
"error": RPCError
|
|
189
|
-
}
|
|
208
|
+
"error": cast(RPCError, {"code": -32601, "message": message}),
|
|
209
|
+
},
|
|
190
210
|
)
|
|
191
211
|
|
|
192
|
-
return RPCResponse
|
|
212
|
+
return cast(RPCResponse, {"id": response_id, "jsonrpc": "2.0", "result": result})
|
|
193
213
|
|
|
194
214
|
|
|
195
215
|
def _make_request(
|
|
@@ -197,6 +217,7 @@ def _make_request(
|
|
|
197
217
|
params: Any,
|
|
198
218
|
api_endpoints: Dict[str, Dict[str, Any]],
|
|
199
219
|
ethereum_tester_instance: "EthereumTester",
|
|
220
|
+
request_id: str,
|
|
200
221
|
) -> RPCResponse:
|
|
201
222
|
# do not import eth_tester derivatives until runtime,
|
|
202
223
|
# it is not a default dependency
|
|
@@ -209,11 +230,15 @@ def _make_request(
|
|
|
209
230
|
try:
|
|
210
231
|
delegator = api_endpoints[namespace][endpoint]
|
|
211
232
|
except KeyError as e:
|
|
212
|
-
return _make_response(e, f"Unknown RPC Endpoint: {method}")
|
|
233
|
+
return _make_response(e, request_id, message=f"Unknown RPC Endpoint: {method}")
|
|
213
234
|
try:
|
|
214
235
|
response = delegator(ethereum_tester_instance, params)
|
|
215
236
|
except NotImplementedError as e:
|
|
216
|
-
return _make_response(
|
|
237
|
+
return _make_response(
|
|
238
|
+
e,
|
|
239
|
+
request_id,
|
|
240
|
+
message=f"RPC Endpoint has not been implemented: {method}",
|
|
241
|
+
)
|
|
217
242
|
except TransactionFailed as e:
|
|
218
243
|
first_arg = e.args[0]
|
|
219
244
|
try:
|
|
@@ -230,4 +255,4 @@ def _make_request(
|
|
|
230
255
|
reason = first_arg
|
|
231
256
|
raise TransactionFailed(f"execution reverted: {reason}")
|
|
232
257
|
else:
|
|
233
|
-
return _make_response(response)
|
|
258
|
+
return _make_response(response, request_id)
|
|
@@ -110,14 +110,14 @@ filter_request_remapper = apply_key_map(FILTER_REQUEST_KEY_MAPPING)
|
|
|
110
110
|
|
|
111
111
|
|
|
112
112
|
FILTER_REQUEST_FORMATTERS = {
|
|
113
|
-
"
|
|
114
|
-
"
|
|
113
|
+
"from_block": to_integer_if_hex,
|
|
114
|
+
"to_block": to_integer_if_hex,
|
|
115
115
|
}
|
|
116
116
|
filter_request_formatter = apply_formatters_to_dict(FILTER_REQUEST_FORMATTERS)
|
|
117
117
|
|
|
118
118
|
filter_request_transformer = compose(
|
|
119
|
-
filter_request_remapper,
|
|
120
119
|
filter_request_formatter,
|
|
120
|
+
filter_request_remapper,
|
|
121
121
|
)
|
|
122
122
|
|
|
123
123
|
|
|
@@ -285,11 +285,6 @@ request_formatters = {
|
|
|
285
285
|
),
|
|
286
286
|
# EVM
|
|
287
287
|
RPCEndpoint("evm_revert"): apply_formatters_to_args(hex_to_integer),
|
|
288
|
-
# Personal
|
|
289
|
-
RPCEndpoint("personal_sendTransaction"): apply_formatters_to_args(
|
|
290
|
-
transaction_request_transformer,
|
|
291
|
-
identity,
|
|
292
|
-
),
|
|
293
288
|
}
|
|
294
289
|
|
|
295
290
|
result_formatters: Optional[Dict[RPCEndpoint, Callable[..., Any]]] = {
|
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,9 @@ from web3.types import (
|
|
|
26
29
|
RPCResponse,
|
|
27
30
|
)
|
|
28
31
|
|
|
32
|
+
from .._utils.batching import (
|
|
33
|
+
sort_batch_response_by_response_ids,
|
|
34
|
+
)
|
|
29
35
|
from ..exceptions import (
|
|
30
36
|
Web3TypeError,
|
|
31
37
|
Web3ValueError,
|
|
@@ -135,7 +141,6 @@ class IPCProvider(JSONBaseProvider):
|
|
|
135
141
|
self,
|
|
136
142
|
ipc_path: Union[str, Path] = None,
|
|
137
143
|
timeout: int = 30,
|
|
138
|
-
*args: Any,
|
|
139
144
|
**kwargs: Any,
|
|
140
145
|
) -> None:
|
|
141
146
|
if ipc_path is None:
|
|
@@ -148,17 +153,12 @@ class IPCProvider(JSONBaseProvider):
|
|
|
148
153
|
self.timeout = timeout
|
|
149
154
|
self._lock = threading.Lock()
|
|
150
155
|
self._socket = PersistantSocket(self.ipc_path)
|
|
151
|
-
super().__init__()
|
|
156
|
+
super().__init__(**kwargs)
|
|
152
157
|
|
|
153
158
|
def __str__(self) -> str:
|
|
154
159
|
return f"<{self.__class__.__name__} {self.ipc_path}>"
|
|
155
160
|
|
|
156
|
-
def
|
|
157
|
-
self.logger.debug(
|
|
158
|
-
f"Making request IPC. Path: {self.ipc_path}, Method: {method}"
|
|
159
|
-
)
|
|
160
|
-
request = self.encode_rpc_request(method, params)
|
|
161
|
-
|
|
161
|
+
def _make_request(self, request: bytes) -> RPCResponse:
|
|
162
162
|
with self._lock, self._socket as sock:
|
|
163
163
|
try:
|
|
164
164
|
sock.sendall(request)
|
|
@@ -189,6 +189,21 @@ class IPCProvider(JSONBaseProvider):
|
|
|
189
189
|
timeout.sleep(0)
|
|
190
190
|
continue
|
|
191
191
|
|
|
192
|
+
def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
|
|
193
|
+
self.logger.debug(
|
|
194
|
+
f"Making request IPC. Path: {self.ipc_path}, Method: {method}"
|
|
195
|
+
)
|
|
196
|
+
request = self.encode_rpc_request(method, params)
|
|
197
|
+
return self._make_request(request)
|
|
198
|
+
|
|
199
|
+
def make_batch_request(
|
|
200
|
+
self, requests: List[Tuple[RPCEndpoint, Any]]
|
|
201
|
+
) -> List[RPCResponse]:
|
|
202
|
+
self.logger.debug(f"Making batch request IPC. Path: {self.ipc_path}")
|
|
203
|
+
request_data = self.encode_batch_rpc_request(requests)
|
|
204
|
+
response = cast(List[RPCResponse], self._make_request(request_data))
|
|
205
|
+
return sort_batch_response_by_response_ids(response)
|
|
206
|
+
|
|
192
207
|
|
|
193
208
|
# A valid JSON RPC response can only end in } or ] http://www.jsonrpc.org/specification
|
|
194
209
|
def has_valid_json_rpc_ending(raw_response: bytes) -> bool:
|