Skip to content
/ ape Public
forked from ApeWorX/ape

Commit 7e5e462

Browse files
authored
perf: break early on proxy detection when realize can't get storage (ApeWorX#2514)
1 parent e69daba commit 7e5e462

File tree

3 files changed

+59
-8
lines changed

3 files changed

+59
-8
lines changed

src/ape_ethereum/ecosystem.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -505,8 +505,10 @@ def str_to_slot(text):
505505
try:
506506
# TODO perf: use a batch call here when ape adds support
507507
storage = self.provider.get_storage(address, slot)
508-
except APINotImplementedError:
509-
continue
508+
except NotImplementedError:
509+
# Break early on not-implemented error rather than attempting
510+
# to try more proxy types.
511+
break
510512

511513
if sum(storage) == 0:
512514
continue

tests/functional/geth/test_proxy.py

-6
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77

88
@geth_process_test
99
def test_standard_proxy(get_contract_type, owner, geth_contract, ethereum):
10-
"""
11-
NOTE: Geth is used here because EthTester does not implement getting storage slots.
12-
"""
1310
_type = get_contract_type("eip1967")
1411
contract = ContractContainer(_type)
1512
target = geth_contract.address
@@ -22,9 +19,6 @@ def test_standard_proxy(get_contract_type, owner, geth_contract, ethereum):
2219

2320
@geth_process_test
2421
def test_beacon_proxy(get_contract_type, geth_contract, owner, ethereum):
25-
"""
26-
NOTE: Geth is used here because EthTester does not implement getting storage slots.
27-
"""
2822
_type = get_contract_type("beacon")
2923
beacon_contract = ContractContainer(_type)
3024
target = geth_contract.address

tests/functional/test_proxy.py

+55
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1+
from typing import TYPE_CHECKING, Optional
2+
3+
from eth_pydantic_types import HexBytes
4+
5+
from ape.contracts.base import ContractContainer
16
from ape_ethereum.proxies import ProxyType
7+
from ape_test.provider import LocalProvider
8+
9+
if TYPE_CHECKING:
10+
from ape.types import AddressType, BlockID
211

312
"""
413
NOTE: Most proxy tests are in `geth/test_proxy.py`.
@@ -24,3 +33,49 @@ def test_minimal_proxy(ethereum, minimal_proxy_container, chain, owner):
2433
if isinstance(abi, list):
2534
assert abi == []
2635
# else: is messed up from other test (xdist).
36+
37+
38+
def test_provider_not_supports_get_storage(
39+
get_contract_type, owner, vyper_contract_instance, ethereum, chain, networks
40+
):
41+
"""
42+
The get storage slot RPC is required to detect this proxy, so it won't work
43+
on EthTester provider. However, we can make sure that it doesn't try to
44+
call `get_storage()` more than once.
45+
"""
46+
47+
class MyProvider(LocalProvider):
48+
times_get_storage_was_called: int = 0
49+
50+
def get_storage( # type: ignore[empty-body]
51+
self, address: "AddressType", slot: int, block_id: Optional["BlockID"] = None
52+
) -> "HexBytes":
53+
self.times_get_storage_was_called += 1
54+
raise NotImplementedError()
55+
56+
my_provider = MyProvider(name="test", network=ethereum.local)
57+
my_provider._web3 = chain.provider._web3
58+
59+
_type = get_contract_type("beacon")
60+
beacon_contract = ContractContainer(_type)
61+
target = vyper_contract_instance.address
62+
beacon_instance = owner.deploy(beacon_contract, target)
63+
beacon = beacon_instance.address
64+
65+
_type = get_contract_type("BeaconProxy")
66+
contract = ContractContainer(_type)
67+
contract_instance = owner.deploy(contract, beacon, HexBytes(""))
68+
69+
# Ensure not already cached.
70+
if contract_instance.address in chain.contracts.proxy_infos:
71+
del chain.contracts.proxy_infos[contract_instance.address]
72+
73+
init_provider = networks.active_provider
74+
networks.active_provider = my_provider
75+
try:
76+
actual = ethereum.get_proxy_info(contract_instance.address)
77+
finally:
78+
networks.active_provider = init_provider
79+
80+
assert actual is None # Because of provider.
81+
assert my_provider.times_get_storage_was_called == 1

0 commit comments

Comments
 (0)