Skip to content

perf: cache proxy detection misses#2786

Open
banteg wants to merge 3 commits into
ApeWorX:mainfrom
banteg:feat/cache-proxy-misses
Open

perf: cache proxy detection misses#2786
banteg wants to merge 3 commits into
ApeWorX:mainfrom
banteg:feat/cache-proxy-misses

Conversation

@banteg

@banteg banteg commented May 8, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Cache proxy-detection misses in the existing proxy_info disk cache by writing JSON null for addresses confirmed not to be proxies.
  • Add a proxy-info-specific cache lookup that distinguishes unchecked addresses from checked ProxyInfoAPI | None results.
  • Skip ecosystem.get_proxy_info() when proxy_info/<address>.json already exists, whether it contains proxy info or null.
  • Keep normal proxy-info reads returning ProxyInfoAPI | None, so a negative marker never becomes fake proxy info.
  • Add backwards-compatibility coverage showing existing on-disk proxy-info JSON objects still load as proxy info.

Performance implications

This removes repeat proxy-detection work for contracts already known not to be proxies. That matters on the contract lookup hot path because a miss currently still re-enters get_proxy_info() every time when no contract type is cached.

For bytecode with no storage-backed proxy shape, the improvement is mostly CPU/cache lookup overhead. For non-proxy bytecode that contains DELEGATECALL, the null marker also avoids repeated storage probes.

Live local Reth mainnet archive-node check from the previous implementation of the same no-hit behavior:

WEB3_PROVIDER_URI=http://127.0.0.1:8545 uv run python /private/tmp/ape_proxy_miss_bench.py
provider=http://127.0.0.1:8545 chain_id=1
WETH9: before_rpc={"get_code": 0, "get_storage": 0, "send_call": 0} after_rpc={"get_code": 0, "get_storage": 0, "send_call": 0} before_mean_ms=0.381 after_mean_ms=0.032 before_median_ms=0.287 after_median_ms=0.018
Safe singleton v1.3.0: before_rpc={"get_code": 0, "get_storage": 100, "send_call": 0} after_rpc={"get_code": 0, "get_storage": 5, "send_call": 0} before_mean_ms=53.274 after_mean_ms=2.604 before_median_ms=50.451 after_median_ms=0.021

Benchmark setup used 20 repeated chain.contracts.get(..., fetch_from_explorer=False, fetch_from_disk=False) calls with ChainManager code cache pre-warmed. The "before" case clears the negative marker between calls to simulate current behavior; the "after" case keeps it.

Tests

  • uv run ruff check src/ape/managers/_contractscache.py src/ape/utils/os.py tests/functional/test_contracts_cache.py
  • uv run ruff format --check src/ape/managers/_contractscache.py src/ape/utils/os.py tests/functional/test_contracts_cache.py
  • uv run mypy src/ape/managers/_contractscache.py src/ape/utils/os.py
  • uv run pytest tests/functional/test_contracts_cache.py

Commit hook note: full-repo mypy still fails on unrelated existing errors in src/ape/cli/choices.py, src/ape/api/config.py, and src/ape_ethereum/ecosystem.py.

@banteg banteg force-pushed the feat/cache-proxy-misses branch 5 times, most recently from 0eb95f9 to d2ee438 Compare May 8, 2026 19:43
@banteg banteg force-pushed the feat/cache-proxy-misses branch from d2ee438 to 0a7f154 Compare May 8, 2026 20:10
@github-actions

Copy link
Copy Markdown

This pull request is considered stale because it has been open 30 days with no activity. Remove stale label, add a comment, or make a new commit, otherwise this PR will be closed in 5 days.

@github-actions github-actions Bot added the stale No activity for 30 days label Jun 10, 2026
@fubuloubu fubuloubu removed the stale No activity for 30 days label Jun 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants