Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support web3.py v7 (in addition to v6) #2394

Merged
merged 12 commits into from
Dec 6, 2024
13 changes: 6 additions & 7 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,15 +118,14 @@
"urllib3>=2.0.0,<3",
"watchdog>=3.0,<4",
# ** Dependencies maintained by Ethereum Foundation **
# All version pins dependent on web3[tester]
"eth-abi",
"eth-account",
"eth-typing>=3.5.2,<4",
"eth-utils",
"hexbytes",
"eth-abi>=5.1.0,<6",
"eth-account>=0.13.4,<0.14",
"eth-typing>=3.5.2,<6",
"eth-utils>=5.1.0,<6",
"hexbytes>=1.2.1,<2",
"py-geth>=5.1.0,<6",
"trie>=3.0.1,<4", # Peer: stricter pin needed for uv support.
"web3[tester]>=6.17.2,<7",
"web3[tester]>=6.20.3,<8",
# ** Dependencies maintained by ApeWorX **
"eip712>=0.2.10,<0.3",
"ethpm-types>=0.6.19,<0.7",
Expand Down
28 changes: 28 additions & 0 deletions src/ape/utils/_web3_compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from eth_account import Account as EthAccount

try:
# Web3 v7
from web3.middleware import ExtraDataToPOAMiddleware # type: ignore
except ImportError:
from web3.middleware import geth_poa_middleware as ExtraDataToPOAMiddleware # type: ignore

try:
from web3.providers import WebsocketProviderV2 as WebsocketProvider # type: ignore
except ImportError:
from web3.providers import WebSocketProvider as WebsocketProvider # type: ignore


def sign_hash(msghash, private_key):
try:
# Web3 v7
return EthAccount.unsafe_sign_hash(msghash, private_key) # type: ignore
except AttributeError:
# Web3 v6
return EthAccount.signHash(msghash, private_key) # type: ignore


__all__ = [
"ExtraDataToPOAMiddleware",
"sign_hash",
"WebsocketProvider",
]
2 changes: 1 addition & 1 deletion src/ape_accounts/accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ def sign_raw_msghash(self, msghash: HexBytes) -> Optional[MessageSignature]:
# Also, we have already warned the user about the safety.
with warnings.catch_warnings():
warnings.simplefilter("ignore")
signed_msg = EthAccount.signHash(msghash, self.__key)
signed_msg = EthAccount.unsafe_sign_hash(msghash, self.__key)

return MessageSignature(
v=signed_msg.v,
Expand Down
14 changes: 6 additions & 8 deletions src/ape_ethereum/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,16 @@
from pydantic.dataclasses import dataclass
from requests import HTTPError
from web3 import HTTPProvider, IPCProvider, Web3
from web3 import WebsocketProvider as WebSocketProvider
from web3._utils.http import construct_user_agent
from web3 import __version__ as web3_version
from web3.exceptions import ContractLogicError as Web3ContractLogicError
from web3.exceptions import (
ExtraDataLengthError,
MethodUnavailable,
TimeExhausted,
TransactionNotFound,
Web3RPCError,
)
from web3.gas_strategies.rpc import rpc_gas_price_strategy
from web3.middleware import geth_poa_middleware as ExtraDataToPOAMiddleware
from web3.middleware.validation import MAX_EXTRADATA_LENGTH
from web3.providers import AutoProvider
from web3.providers.auto import load_provider_from_environment
Expand Down Expand Up @@ -59,6 +58,7 @@
from ape.types.events import ContractLog, LogFilter
from ape.types.gas import AutoGasLimit
from ape.types.trace import SourceTraceback
from ape.utils._web3_compat import ExtraDataToPOAMiddleware, WebsocketProvider
from ape.utils.basemodel import ManagerAccessMixin
from ape.utils.misc import DEFAULT_MAX_RETRIES_TX, gas_estimation_error_message, to_int
from ape_ethereum._print import CONSOLE_ADDRESS, console_contract
Expand Down Expand Up @@ -1034,7 +1034,7 @@ def send_transaction(self, txn: TransactionAPI) -> ReceiptAPI:
if txn_hash is None:
txn_hash = to_hex(self.web3.eth.send_raw_transaction(txn.serialize_transaction()))

except (ValueError, Web3ContractLogicError) as err:
except (ValueError, Web3ContractLogicError, Web3RPCError) as err:
vm_err = self.get_virtual_machine_error(
err, txn=txn, set_ape_traceback=txn.raise_on_revert
)
Expand Down Expand Up @@ -1326,9 +1326,7 @@ class EthereumNodeProvider(Web3Provider, ABC):
name: str = "node"

# NOTE: Appends user-agent to base User-Agent string.
request_header: dict = {
"User-Agent": construct_user_agent(str(HTTPProvider)),
}
request_header: dict = {"User-Agent": f"EthereumNodeProvider/web3.py/{web3_version}"}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note to reviewer: this basically makes it the same as it was before, v7 changes this method to make it more web3-specific by including a required module arg


@property
def uri(self) -> str:
Expand Down Expand Up @@ -1619,7 +1617,7 @@ def _create_web3(

providers.append(lambda: HTTPProvider(endpoint_uri=http, request_kwargs=request_kwargs))
if ws := ws_uri:
providers.append(lambda: WebSocketProvider(endpoint_uri=ws))
providers.append(lambda: WebsocketProvider(endpoint_uri=ws))

provider = AutoProvider(potential_providers=providers)
return Web3(provider)
Expand Down
2 changes: 1 addition & 1 deletion src/ape_node/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
from pydantic import field_validator
from pydantic_settings import SettingsConfigDict
from requests.exceptions import ConnectionError
from web3.middleware import geth_poa_middleware as ExtraDataToPOAMiddleware

from ape.api.config import PluginConfig
from ape.api.providers import SubprocessProvider, TestProviderAPI
from ape.logging import LogLevel, logger
from ape.utils._web3_compat import ExtraDataToPOAMiddleware
from ape.utils.misc import ZERO_ADDRESS, log_instead_of_fail, raises_not_implemented
from ape.utils.process import JoinableQueue, spawn
from ape.utils.testing import (
Expand Down
2 changes: 1 addition & 1 deletion src/ape_test/accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ def sign_transaction(
def sign_raw_msghash(self, msghash: HexBytes) -> MessageSignature:
with warnings.catch_warnings():
warnings.simplefilter("ignore")
signed_msg = EthAccount.signHash(msghash, self.private_key)
signed_msg = EthAccount.unsafe_sign_hash(msghash, self.private_key)

return MessageSignature(
v=signed_msg.v,
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/geth/test_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from web3 import AutoProvider, Web3
from web3.exceptions import ContractLogicError as Web3ContractLogicError
from web3.exceptions import ExtraDataLengthError
from web3.middleware import geth_poa_middleware as ExtraDataToPOAMiddleware
from web3.providers import HTTPProvider

from ape.exceptions import (
Expand All @@ -26,6 +25,7 @@
VirtualMachineError,
)
from ape.utils import to_int
from ape.utils._web3_compat import ExtraDataToPOAMiddleware
from ape_ethereum.ecosystem import Block
from ape_ethereum.provider import DEFAULT_SETTINGS, EthereumNodeProvider
from ape_ethereum.trace import TraceApproach
Expand Down
4 changes: 2 additions & 2 deletions tests/functional/test_ecosystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -1188,11 +1188,11 @@ def get_calltree(self) -> CallTreeNode:
{
"name": "NumberChange",
"calldata": {
"b": "0x3e..404b",
"b": "0x3ee0..404b",
"prevNum": 0,
"dynData": '"Dynamic"',
"newNum": 123,
"dynIndexed": "0x9f..a94d",
"dynIndexed": "0x9f3d..a94d",
},
}
]
Expand Down
Loading