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.
Files changed (50) hide show
  1. web3/_utils/batching.py +217 -0
  2. web3/_utils/caching.py +26 -2
  3. web3/_utils/compat/__init__.py +1 -0
  4. web3/_utils/contracts.py +5 -5
  5. web3/_utils/events.py +20 -20
  6. web3/_utils/filters.py +6 -6
  7. web3/_utils/method_formatters.py +0 -23
  8. web3/_utils/module_testing/__init__.py +0 -3
  9. web3/_utils/module_testing/eth_module.py +442 -373
  10. web3/_utils/module_testing/module_testing_utils.py +13 -0
  11. web3/_utils/module_testing/web3_module.py +438 -17
  12. web3/_utils/rpc_abi.py +0 -18
  13. web3/contract/async_contract.py +11 -11
  14. web3/contract/base_contract.py +19 -18
  15. web3/contract/contract.py +13 -13
  16. web3/contract/utils.py +112 -4
  17. web3/eth/async_eth.py +10 -8
  18. web3/eth/eth.py +7 -6
  19. web3/exceptions.py +75 -21
  20. web3/gas_strategies/time_based.py +2 -2
  21. web3/geth.py +0 -188
  22. web3/main.py +21 -13
  23. web3/manager.py +237 -74
  24. web3/method.py +29 -9
  25. web3/middleware/base.py +43 -0
  26. web3/middleware/filter.py +18 -6
  27. web3/middleware/signing.py +2 -2
  28. web3/module.py +47 -7
  29. web3/providers/async_base.py +55 -23
  30. web3/providers/base.py +59 -26
  31. web3/providers/eth_tester/defaults.py +0 -48
  32. web3/providers/eth_tester/main.py +36 -11
  33. web3/providers/eth_tester/middleware.py +3 -8
  34. web3/providers/ipc.py +23 -8
  35. web3/providers/legacy_websocket.py +26 -1
  36. web3/providers/persistent/async_ipc.py +60 -76
  37. web3/providers/persistent/persistent.py +134 -10
  38. web3/providers/persistent/request_processor.py +98 -14
  39. web3/providers/persistent/websocket.py +43 -66
  40. web3/providers/rpc/async_rpc.py +20 -2
  41. web3/providers/rpc/rpc.py +22 -2
  42. web3/providers/rpc/utils.py +1 -10
  43. web3/tools/benchmark/node.py +2 -8
  44. web3/types.py +8 -2
  45. {web3-7.0.0b4.dist-info → web3-7.0.0b6.dist-info}/LICENSE +1 -1
  46. {web3-7.0.0b4.dist-info → web3-7.0.0b6.dist-info}/METADATA +32 -21
  47. {web3-7.0.0b4.dist-info → web3-7.0.0b6.dist-info}/RECORD +49 -49
  48. web3/_utils/module_testing/go_ethereum_personal_module.py +0 -300
  49. {web3-7.0.0b4.dist-info → web3-7.0.0b6.dist-info}/WHEEL +0 -0
  50. {web3-7.0.0b4.dist-info → web3-7.0.0b6.dist-info}/top_level.txt +0 -0
web3/manager.py CHANGED
@@ -1,9 +1,11 @@
1
+ import asyncio
1
2
  import logging
2
3
  from typing import (
3
4
  TYPE_CHECKING,
4
5
  Any,
5
6
  AsyncGenerator,
6
7
  Callable,
8
+ Coroutine,
7
9
  List,
8
10
  Optional,
9
11
  Sequence,
@@ -22,6 +24,9 @@ from websockets.exceptions import (
22
24
  ConnectionClosedOK,
23
25
  )
24
26
 
27
+ from web3._utils.batching import (
28
+ RequestBatcher,
29
+ )
25
30
  from web3._utils.caching import (
26
31
  generate_cache_key,
27
32
  )
@@ -35,8 +40,12 @@ from web3.exceptions import (
35
40
  BadResponseFormat,
36
41
  MethodUnavailable,
37
42
  ProviderConnectionError,
43
+ TaskNotRunning,
44
+ Web3RPCError,
38
45
  Web3TypeError,
39
- Web3ValueError,
46
+ )
47
+ from web3.method import (
48
+ Method,
40
49
  )
41
50
  from web3.middleware import (
42
51
  AttributeDictMiddleware,
@@ -54,8 +63,12 @@ from web3.module import (
54
63
  )
55
64
  from web3.providers import (
56
65
  AutoProvider,
66
+ JSONBaseProvider,
57
67
  PersistentConnectionProvider,
58
68
  )
69
+ from web3.providers.async_base import (
70
+ AsyncJSONBaseProvider,
71
+ )
59
72
  from web3.types import (
60
73
  RPCEndpoint,
61
74
  RPCResponse,
@@ -87,6 +100,7 @@ def _raise_bad_response_format(response: RPCResponse, error: str = "") -> None:
87
100
  raw_response = f"The raw response is: {response}"
88
101
 
89
102
  if error is not None and error != "":
103
+ error = error[:-1] if error.endswith(".") else error
90
104
  message = f"{message} {error}. {raw_response}"
91
105
  else:
92
106
  message = f"{message} {raw_response}"
@@ -117,6 +131,111 @@ def apply_null_result_formatters(
117
131
  return response
118
132
 
119
133
 
134
+ def _validate_subscription_fields(response: RPCResponse) -> None:
135
+ params = response["params"]
136
+ subscription = params["subscription"]
137
+ if not isinstance(subscription, str) and not len(subscription) == 34:
138
+ _raise_bad_response_format(
139
+ response, "eth_subscription 'params' must include a 'subscription' field."
140
+ )
141
+
142
+
143
+ def _validate_response(
144
+ response: RPCResponse,
145
+ error_formatters: Optional[Callable[..., Any]],
146
+ is_subscription_response: bool = False,
147
+ logger: Optional[logging.Logger] = None,
148
+ ) -> None:
149
+ if "jsonrpc" not in response or response["jsonrpc"] != "2.0":
150
+ _raise_bad_response_format(
151
+ response, 'The "jsonrpc" field must be present with a value of "2.0".'
152
+ )
153
+
154
+ response_id = response.get("id")
155
+ if "id" in response:
156
+ int_error_msg = (
157
+ '"id" must be an integer or a string representation of an integer.'
158
+ )
159
+ if response_id is None and "error" in response:
160
+ # errors can sometimes have null `id`, according to the JSON-RPC spec
161
+ pass
162
+ elif not isinstance(response_id, (str, int)):
163
+ _raise_bad_response_format(response, int_error_msg)
164
+ elif isinstance(response_id, str):
165
+ try:
166
+ int(response_id)
167
+ except ValueError:
168
+ _raise_bad_response_format(response, int_error_msg)
169
+ elif is_subscription_response:
170
+ # if `id` is not present, this must be a subscription response
171
+ _validate_subscription_fields(response)
172
+ else:
173
+ _raise_bad_response_format(
174
+ response,
175
+ 'Response must include an "id" field or be formatted as an '
176
+ "`eth_subscription` response.",
177
+ )
178
+
179
+ if all(key in response for key in {"error", "result"}):
180
+ _raise_bad_response_format(
181
+ response, 'Response cannot include both "error" and "result".'
182
+ )
183
+ elif (
184
+ not any(key in response for key in {"error", "result"})
185
+ and not is_subscription_response
186
+ ):
187
+ _raise_bad_response_format(
188
+ response, 'Response must include either "error" or "result".'
189
+ )
190
+ elif "error" in response:
191
+ error = response["error"]
192
+
193
+ # raise the error when the value is a string
194
+ if error is None or not isinstance(error, dict):
195
+ _raise_bad_response_format(
196
+ response,
197
+ 'response["error"] must be a valid object as defined by the '
198
+ "JSON-RPC 2.0 specification.",
199
+ )
200
+
201
+ # errors must include an integer code
202
+ code = error.get("code")
203
+ if not isinstance(code, int):
204
+ _raise_bad_response_format(
205
+ response, 'error["code"] is required and must be an integer value.'
206
+ )
207
+ elif code == METHOD_NOT_FOUND:
208
+ exception = MethodUnavailable(
209
+ repr(error),
210
+ rpc_response=response,
211
+ user_message=(
212
+ "This method is not available. Check your node provider or your "
213
+ "client's API docs to see what methods are supported and / or "
214
+ "currently enabled."
215
+ ),
216
+ )
217
+ logger.error(exception.user_message)
218
+ logger.debug(f"RPC error response: {response}")
219
+ raise exception
220
+
221
+ # errors must include a message
222
+ error_message = error.get("message")
223
+ if not isinstance(error_message, str):
224
+ _raise_bad_response_format(
225
+ response, 'error["message"] is required and must be a string value.'
226
+ )
227
+
228
+ apply_error_formatters(error_formatters, response)
229
+
230
+ web3_rpc_error = Web3RPCError(repr(error), rpc_response=response)
231
+ logger.error(web3_rpc_error.user_message)
232
+ logger.debug(f"RPC error response: {response}")
233
+ raise web3_rpc_error
234
+
235
+ elif "result" not in response and not is_subscription_response:
236
+ _raise_bad_response_format(response)
237
+
238
+
120
239
  class RequestManager:
121
240
  logger = logging.getLogger("web3.manager.RequestManager")
122
241
 
@@ -203,90 +322,42 @@ class RequestManager:
203
322
  #
204
323
  # See also: https://www.jsonrpc.org/specification
205
324
  #
206
- @staticmethod
207
325
  def formatted_response(
326
+ self,
208
327
  response: RPCResponse,
209
328
  params: Any,
210
329
  error_formatters: Optional[Callable[..., Any]] = None,
211
330
  null_result_formatters: Optional[Callable[..., Any]] = None,
212
331
  ) -> Any:
213
- # jsonrpc is not enforced (as per the spec) but if present, it must be 2.0
214
- if "jsonrpc" in response and response["jsonrpc"] != "2.0":
215
- _raise_bad_response_format(
216
- response, 'The "jsonrpc" field must be present with a value of "2.0"'
217
- )
218
-
219
- # id is not enforced (as per the spec) but if present, it must be a
220
- # string or integer
221
- # TODO: v7 - enforce id per the spec
222
- if "id" in response:
223
- response_id = response["id"]
224
- # id is always None for errors
225
- if response_id is None and "error" not in response:
226
- _raise_bad_response_format(
227
- response, '"id" must be None when an error is present'
228
- )
229
- elif not isinstance(response_id, (str, int, type(None))):
230
- _raise_bad_response_format(response, '"id" must be a string or integer')
231
-
232
- # Response may not include both "error" and "result"
233
- if "error" in response and "result" in response:
234
- _raise_bad_response_format(
235
- response, 'Response cannot include both "error" and "result"'
236
- )
237
-
238
- # Format and validate errors
239
- elif "error" in response:
240
- error = response.get("error")
241
- # Raise the error when the value is a string
242
- if error is None or isinstance(error, str):
243
- raise Web3ValueError(error)
244
-
245
- # Errors must include an integer code
246
- code = error.get("code")
247
- if not isinstance(code, int):
248
- _raise_bad_response_format(response, "error['code'] must be an integer")
249
- elif code == METHOD_NOT_FOUND:
250
- raise MethodUnavailable(
251
- error,
252
- user_message="Check your node provider's API docs to see what "
253
- "methods are supported",
254
- )
255
-
256
- # Errors must include a message
257
- if not isinstance(error.get("message"), str):
258
- _raise_bad_response_format(
259
- response, "error['message'] must be a string"
260
- )
261
-
262
- apply_error_formatters(error_formatters, response)
332
+ is_subscription_response = (
333
+ response.get("method") == "eth_subscription"
334
+ and response.get("params") is not None
335
+ and response["params"].get("subscription") is not None
336
+ and response["params"].get("result") is not None
337
+ )
263
338
 
264
- raise Web3ValueError(error)
339
+ _validate_response(
340
+ response,
341
+ error_formatters,
342
+ is_subscription_response=is_subscription_response,
343
+ logger=self.logger,
344
+ )
265
345
 
266
- # Format and validate results
267
- elif "result" in response:
346
+ # format results
347
+ if "result" in response:
268
348
  # Null values for result should apply null_result_formatters
269
349
  # Skip when result not present in the response (fallback to False)
270
350
  if response.get("result", False) in NULL_RESPONSES:
271
351
  apply_null_result_formatters(null_result_formatters, response, params)
272
352
  return response.get("result")
273
353
 
274
- # Response from eth_subscription includes response["params"]["result"]
275
- elif (
276
- response.get("method") == "eth_subscription"
277
- and response.get("params") is not None
278
- and response["params"].get("subscription") is not None
279
- and response["params"].get("result") is not None
280
- ):
354
+ # response from eth_subscription includes response["params"]["result"]
355
+ elif is_subscription_response:
281
356
  return {
282
357
  "subscription": response["params"]["subscription"],
283
358
  "result": response["params"]["result"],
284
359
  }
285
360
 
286
- # Any other response type raises BadResponseFormat
287
- else:
288
- _raise_bad_response_format(response)
289
-
290
361
  def request_blocking(
291
362
  self,
292
363
  method: Union[RPCEndpoint, Callable[..., RPCEndpoint]],
@@ -317,6 +388,88 @@ class RequestManager:
317
388
  response, params, error_formatters, null_result_formatters
318
389
  )
319
390
 
391
+ # -- batch requests management -- #
392
+
393
+ def _batch_requests(self) -> RequestBatcher[Method[Callable[..., Any]]]:
394
+ """
395
+ Context manager for making batch requests
396
+ """
397
+ if not isinstance(self.provider, (AsyncJSONBaseProvider, JSONBaseProvider)):
398
+ raise Web3TypeError("Batch requests are not supported by this provider.")
399
+ return RequestBatcher(self.w3)
400
+
401
+ def _make_batch_request(
402
+ self, requests_info: List[Tuple[Tuple["RPCEndpoint", Any], Sequence[Any]]]
403
+ ) -> List[RPCResponse]:
404
+ """
405
+ Make a batch request using the provider
406
+ """
407
+ provider = cast(JSONBaseProvider, self.provider)
408
+ request_func = provider.batch_request_func(
409
+ cast("Web3", self.w3), cast("MiddlewareOnion", self.middleware_onion)
410
+ )
411
+ responses = request_func(
412
+ [
413
+ (method, params)
414
+ for (method, params), _response_formatters in requests_info
415
+ ]
416
+ )
417
+ formatted_responses = [
418
+ self._format_batched_response(info, resp)
419
+ for info, resp in zip(requests_info, responses)
420
+ ]
421
+ return list(formatted_responses)
422
+
423
+ async def _async_make_batch_request(
424
+ self,
425
+ requests_info: List[
426
+ Coroutine[Any, Any, Tuple[Tuple["RPCEndpoint", Any], Sequence[Any]]]
427
+ ],
428
+ ) -> List[RPCResponse]:
429
+ """
430
+ Make an asynchronous batch request using the provider
431
+ """
432
+ provider = cast(AsyncJSONBaseProvider, self.provider)
433
+ request_func = await provider.batch_request_func(
434
+ cast("AsyncWeb3", self.w3),
435
+ cast("MiddlewareOnion", self.middleware_onion),
436
+ )
437
+ # since we add items to the batch without awaiting, we unpack the coroutines
438
+ # and await them all here
439
+ unpacked_requests_info = await asyncio.gather(*requests_info)
440
+ responses = await request_func(
441
+ [
442
+ (method, params)
443
+ for (method, params), _response_formatters in unpacked_requests_info
444
+ ]
445
+ )
446
+
447
+ if isinstance(self.provider, PersistentConnectionProvider):
448
+ # call _process_response for each response in the batch
449
+ return [await self._process_response(resp) for resp in responses]
450
+
451
+ formatted_responses = [
452
+ self._format_batched_response(info, resp)
453
+ for info, resp in zip(unpacked_requests_info, responses)
454
+ ]
455
+ return list(formatted_responses)
456
+
457
+ def _format_batched_response(
458
+ self,
459
+ requests_info: Tuple[Tuple[RPCEndpoint, Any], Sequence[Any]],
460
+ response: RPCResponse,
461
+ ) -> RPCResponse:
462
+ result_formatters, error_formatters, null_result_formatters = requests_info[1]
463
+ return apply_result_formatters(
464
+ result_formatters,
465
+ self.formatted_response(
466
+ response,
467
+ requests_info[0][1],
468
+ error_formatters,
469
+ null_result_formatters,
470
+ ),
471
+ )
472
+
320
473
  # -- persistent connection -- #
321
474
 
322
475
  async def send(self, method: RPCEndpoint, params: Any) -> RPCResponse:
@@ -350,14 +503,24 @@ class RequestManager:
350
503
  )
351
504
 
352
505
  while True:
353
- response = await self._request_processor.pop_raw_response(subscription=True)
354
- if (
355
- response is not None
356
- and response.get("params", {}).get("subscription")
357
- in self._request_processor.active_subscriptions
358
- ):
359
- # if response is an active subscription response, process it
360
- yield await self._process_response(response)
506
+ try:
507
+ response = await self._request_processor.pop_raw_response(
508
+ subscription=True
509
+ )
510
+ if (
511
+ response is not None
512
+ and response.get("params", {}).get("subscription")
513
+ in self._request_processor.active_subscriptions
514
+ ):
515
+ # if response is an active subscription response, process it
516
+ yield await self._process_response(response)
517
+ except TaskNotRunning:
518
+ self._provider._handle_listener_task_exceptions()
519
+ self.logger.error(
520
+ "Message listener background task has stopped unexpectedly. "
521
+ "Stopping message stream."
522
+ )
523
+ raise StopAsyncIteration
361
524
 
362
525
  async def _process_response(self, response: RPCResponse) -> RPCResponse:
363
526
  provider = cast(PersistentConnectionProvider, self._provider)
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 Web3 # noqa: F401
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, obj: Optional["Module"] = None, obj_type: Optional[Type["Module"]] = None
156
+ self,
157
+ module: Optional["Module"] = None,
158
+ _type: Optional[Type["Module"]] = None,
153
159
  ) -> TFunc:
154
- if obj is None:
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 an module instance, "
164
+ "Methods must be called from a module instance, "
158
165
  "usually attached to a web3 instance."
159
166
  )
160
- return obj.retrieve_caller_fn(self)
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/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/middleware/filter.py CHANGED
@@ -589,6 +589,10 @@ SyncFilter = Union[RequestLogs, RequestBlocks]
589
589
  AsyncFilter = Union[AsyncRequestLogs, AsyncRequestBlocks]
590
590
 
591
591
 
592
+ def _simulate_rpc_response_with_result(filter_id: str) -> "RPCResponse":
593
+ return {"jsonrpc": "2.0", "id": -1, "result": filter_id}
594
+
595
+
592
596
  class LocalFilterMiddleware(Web3Middleware):
593
597
  def __init__(self, w3: Union["Web3", "AsyncWeb3"]):
594
598
  self.filters: Dict[str, SyncFilter] = {}
@@ -615,7 +619,7 @@ class LocalFilterMiddleware(Web3Middleware):
615
619
  raise NotImplementedError(method)
616
620
 
617
621
  self.filters[filter_id] = _filter
618
- return {"result": filter_id}
622
+ return _simulate_rpc_response_with_result(filter_id)
619
623
 
620
624
  elif method in FILTER_CHANGES_METHODS:
621
625
  _filter_id = params[0]
@@ -626,12 +630,16 @@ class LocalFilterMiddleware(Web3Middleware):
626
630
 
627
631
  _filter = self.filters[_filter_id]
628
632
  if method == RPC.eth_getFilterChanges:
629
- return {"result": next(_filter.filter_changes)}
633
+ return _simulate_rpc_response_with_result(
634
+ next(_filter.filter_changes) # type: ignore
635
+ )
630
636
 
631
637
  elif method == RPC.eth_getFilterLogs:
632
638
  # type ignored b/c logic prevents RequestBlocks which
633
639
  # doesn't implement get_logs
634
- return {"result": _filter.get_logs()} # type: ignore
640
+ return _simulate_rpc_response_with_result(
641
+ _filter.get_logs() # type: ignore
642
+ )
635
643
  else:
636
644
  raise NotImplementedError(method)
637
645
  else:
@@ -663,7 +671,7 @@ class LocalFilterMiddleware(Web3Middleware):
663
671
  raise NotImplementedError(method)
664
672
 
665
673
  self.async_filters[filter_id] = _filter
666
- return {"result": filter_id}
674
+ return _simulate_rpc_response_with_result(filter_id)
667
675
 
668
676
  elif method in FILTER_CHANGES_METHODS:
669
677
  _filter_id = params[0]
@@ -674,12 +682,16 @@ class LocalFilterMiddleware(Web3Middleware):
674
682
 
675
683
  _filter = self.async_filters[_filter_id]
676
684
  if method == RPC.eth_getFilterChanges:
677
- return {"result": await _filter.filter_changes.__anext__()}
685
+ return _simulate_rpc_response_with_result(
686
+ await _filter.filter_changes.__anext__() # type: ignore
687
+ )
678
688
 
679
689
  elif method == RPC.eth_getFilterLogs:
680
690
  # type ignored b/c logic prevents RequestBlocks which
681
691
  # doesn't implement get_logs
682
- return {"result": await _filter.get_logs()} # type: ignore
692
+ return _simulate_rpc_response_with_result(
693
+ await _filter.get_logs() # type: ignore
694
+ )
683
695
  else:
684
696
  raise NotImplementedError(method)
685
697
  else:
@@ -182,7 +182,7 @@ class SignAndSendRawMiddlewareBuilder(Web3MiddlewareBuilder):
182
182
  return method, params
183
183
  else:
184
184
  account = self._accounts[to_checksum_address(tx_from)]
185
- raw_tx = account.sign_transaction(filled_transaction).rawTransaction
185
+ raw_tx = account.sign_transaction(filled_transaction).raw_transaction
186
186
 
187
187
  return (
188
188
  RPCEndpoint("eth_sendRawTransaction"),
@@ -211,7 +211,7 @@ class SignAndSendRawMiddlewareBuilder(Web3MiddlewareBuilder):
211
211
  return method, params
212
212
  else:
213
213
  account = self._accounts[to_checksum_address(tx_from)]
214
- raw_tx = account.sign_transaction(filled_transaction).rawTransaction
214
+ raw_tx = account.sign_transaction(filled_transaction).raw_transaction
215
215
 
216
216
  return (
217
217
  RPCEndpoint("eth_sendRawTransaction"),