Skip to content

Commit

Permalink
fix: handle HTTPError-based not-implemented RPCs and parity-trace det…
Browse files Browse the repository at this point in the history
…ection error handling easement (ApeWorX#2080)
  • Loading branch information
antazoey committed May 9, 2024
1 parent 9765621 commit 2fd4240
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 2 deletions.
16 changes: 15 additions & 1 deletion src/ape_ethereum/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
get_calltree_from_parity_trace,
)
from pydantic.dataclasses import dataclass
from requests import HTTPError
from web3 import HTTPProvider, IPCProvider, Web3
from web3.exceptions import ContractLogicError as Web3ContractLogicError
from web3.exceptions import (
Expand Down Expand Up @@ -1078,7 +1079,16 @@ def _create_trace_frame(self, evm_frame: EvmTraceFrame) -> TraceFrame:

def _make_request(self, endpoint: str, parameters: Optional[List] = None) -> Any:
parameters = parameters or []
result = self.web3.provider.make_request(RPCEndpoint(endpoint), parameters)

try:
result = self.web3.provider.make_request(RPCEndpoint(endpoint), parameters)
except HTTPError as err:
if "method not allowed" in str(err).lower():
raise APINotImplementedError(
f"RPC method '{endpoint}' is not implemented by this node instance."
)

raise ProviderError(str(err)) from err

if "error" in result:
error = result["error"]
Expand Down Expand Up @@ -1422,6 +1432,10 @@ def get_call_tree(self, txn_hash: str) -> CallTreeNode:
except (ValueError, APINotImplementedError, ProviderError):
self.can_use_parity_traces = False
return self._get_geth_call_tree(txn_hash)
except Exception as err:
logger.error(f"Unknown exception while checking for Parity-trace support: {err} ")
self.can_use_parity_traces = False
return self._get_geth_call_tree(txn_hash)

# Parity style works.
self.can_use_parity_traces = True
Expand Down
26 changes: 25 additions & 1 deletion tests/functional/test_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from eth_typing import HexStr
from eth_utils import ValidationError
from hexbytes import HexBytes
from requests import HTTPError
from web3.exceptions import ContractPanicError

from ape.exceptions import (
Expand Down Expand Up @@ -358,7 +359,8 @@ def test_make_request_not_exists(eth_tester_provider):
@pytest.mark.parametrize("msg", ("Method not found", "Method ape_thisDoesNotExist not found"))
def test_make_request_not_exists_dev_nodes(eth_tester_provider, mock_web3, msg):
"""
Simulate what *most* of the dev providers do, like hardhat, anvil, and ganache.
Handle an issue found from Base-sepolia where not-implemented RPCs
caused HTTPErrors.
"""
real_web3 = eth_tester_provider._web3
mock_web3.eth = real_web3.eth
Expand All @@ -378,6 +380,28 @@ def custom_make_request(rpc, params):
eth_tester_provider._make_request("ape_thisDoesNotExist")


def test_make_request_handles_http_error_method_not_allowed(eth_tester_provider, mock_web3):
"""
Simulate what *most* of the dev providers do, like hardhat, anvil, and ganache.
"""
real_web3 = eth_tester_provider._web3
mock_web3.eth = real_web3.eth
eth_tester_provider._web3 = mock_web3

def custom_make_request(rpc, params):
if rpc == "ape_thisDoesNotExist":
raise HTTPError("Client error: Method Not Allowed")

return real_web3.provider.make_request(rpc, params)

mock_web3.provider.make_request.side_effect = custom_make_request
with pytest.raises(
APINotImplementedError,
match="RPC method 'ape_thisDoesNotExist' is not implemented by this node instance.",
):
eth_tester_provider._make_request("ape_thisDoesNotExist")


def test_base_fee(eth_tester_provider):
actual = eth_tester_provider.base_fee
assert actual > 0
Expand Down

0 comments on commit 2fd4240

Please sign in to comment.