Repository: ethereum/web3.py

Issue:
The return type of eth_call should be HexBytes instead of bytes
* Version: 6.0.0-beta.10
* Python: 3.10
* OS: Linux(WSL)

### What was wrong?

The return type annotation of `eth_call` is `bytes | bytearray`, but actually uses `hexbytes.HexBytes` as the return type. But since the hexbytes library has compatibility issues(ethereum/hexbytes#14), it can bother users developing and create unexpected problems.
It looks like this issue has been reported to the hexbytes library long time ago, but it has never been released. And there is no expectation that this will be fixed. As a project that uses hexbytes as a dependency, it is necessary to explicitly tell users the correct specific return type, so that users can directly code for the type (to fix the compatibility issue).

A minimal reproducible example is as follows:
```python
import asyncio
import typing

from web3 import AsyncHTTPProvider, Web3
from web3.eth.async_eth import AsyncEth
from web3.types import TxParams

addr = Web3.to_checksum_address(f"0x8ad599c3a0ff1de082011efddc58f1908eb6e6d8")

txn: TxParams = {"to": addr, "data": bytes.fromhex("0x3850c7bd"[2:])}


async def main():
    url = "http://localhost:8545/"
    w3 = Web3(AsyncHTTPProvider(url))
    result = await typing.cast(AsyncEth, w3.eth).call(txn, "latest")
    print(type(result), f"0x{result.hex()}")


asyncio.run(main())
```
The output is as follows:
```
<class 'hexbytes.main.HexBytes'> 0x0x000000...00000001
```
It can be observed that `0x` appears twice, due to the inconsistency in `hex` between HexBytes and bytes.

### How can it be fixed?

Explicitly declare the return type annotation of `eth_call` as `HexBytes`, which allows users to find such inconsistencies faster and use the `isinstance` method to solve them. This saves a lot of debugging time.



Discussion:

Resolving patch:
diff --git a/web3/eth/async_eth.py b/web3/eth/async_eth.py
--- a/web3/eth/async_eth.py
+++ b/web3/eth/async_eth.py
@@ -225,7 +225,7 @@ async def fee_history(
                 Optional[BlockIdentifier],
                 Optional[CallOverride],
             ],
-            Awaitable[Union[bytes, bytearray]],
+            Awaitable[HexBytes],
         ]
     ] = Method(RPC.eth_call, mungers=[BaseEth.call_munger])
 
@@ -235,7 +235,7 @@ async def call(
         block_identifier: Optional[BlockIdentifier] = None,
         state_override: Optional[CallOverride] = None,
         ccip_read_enabled: Optional[bool] = None,
-    ) -> Union[bytes, bytearray]:
+    ) -> HexBytes:
         ccip_read_enabled_on_provider = self.w3.provider.global_ccip_read_enabled
         if (
             # default conditions:
@@ -255,7 +255,7 @@ async def _durin_call(
         transaction: TxParams,
         block_identifier: Optional[BlockIdentifier] = None,
         state_override: Optional[CallOverride] = None,
-    ) -> Union[bytes, bytearray]:
+    ) -> HexBytes:
         max_redirects = self.w3.provider.ccip_read_max_redirects
 
         if not max_redirects or max_redirects < 4:
diff --git a/web3/eth/eth.py b/web3/eth/eth.py
--- a/web3/eth/eth.py
+++ b/web3/eth/eth.py
@@ -234,7 +234,7 @@ def fee_history(
     _call: Method[
         Callable[
             [TxParams, Optional[BlockIdentifier], Optional[CallOverride]],
-            Union[bytes, bytearray],
+            HexBytes,
         ]
     ] = Method(RPC.eth_call, mungers=[BaseEth.call_munger])
 
@@ -244,7 +244,7 @@ def call(
         block_identifier: Optional[BlockIdentifier] = None,
         state_override: Optional[CallOverride] = None,
         ccip_read_enabled: Optional[bool] = None,
-    ) -> Union[bytes, bytearray]:
+    ) -> HexBytes:
         ccip_read_enabled_on_provider = self.w3.provider.global_ccip_read_enabled
         if (
             # default conditions:
@@ -264,7 +264,7 @@ def _durin_call(
         transaction: TxParams,
         block_identifier: Optional[BlockIdentifier] = None,
         state_override: Optional[CallOverride] = None,
-    ) -> Union[bytes, bytearray]:
+    ) -> HexBytes:
         max_redirects = self.w3.provider.ccip_read_max_redirects
 
         if not max_redirects or max_redirects < 4:


Test patch: