Skip to content

fix: invalidate per-contract ABI cache after metadata update#255

Draft
Uxio0 wants to merge 1 commit into
mainfrom
bug/e-abi-cache-invalidation
Draft

fix: invalidate per-contract ABI cache after metadata update#255
Uxio0 wants to merge 1 commit into
mainfrom
bug/e-abi-cache-invalidation

Conversation

@Uxio0
Copy link
Copy Markdown
Member

@Uxio0 Uxio0 commented Apr 15, 2026

Problem

DataDecoderService.get_contract_abi and get_contract_abi_selectors_with_functions were decorated with @alru_cache(maxsize=2048) with no TTL and no invalidation. When a contract's ABI was updated in the database (e.g. after a proxy implementation refresh via update_proxies_task), the in-memory cache continued returning the old ABI for the lifetime of the process.

Changes

app/services/data_decoder.py

  • Add ttl=600 to both @alru_cache decorators — stale entries expire within 10 minutes automatically.
  • Add invalidate_contract_abi_cache(address, chain_id) which calls cache_invalidate on both caches for the given contract, enabling immediate eviction.

app/services/contract_metadata_service.py

  • After successfully linking a new ABI to a contract in process_contract_metadata, call decoder.invalidate_contract_abi_cache(...) so the next decode request fetches the fresh ABI without waiting for the TTL.

get_contract_abi and get_contract_abi_selectors_with_functions were
cached indefinitely with alru_cache(maxsize=2048), so updating a
contract's ABI in the database (e.g. after a proxy implementation
refresh) had no effect until the process restarted.

Two changes:
- Add ttl=600 to both caches as a safety net so stale entries expire
  automatically within 10 minutes even if explicit invalidation is missed.
- Add DataDecoderService.invalidate_contract_abi_cache() and call it
  from ContractMetadataService.process_contract_metadata() immediately
  after a new ABI is linked, so decodings in subsequent requests use
  the fresh ABI without waiting for the TTL.
@coveralls
Copy link
Copy Markdown

Coverage Report for CI Build 24461034871

Coverage increased (+0.04%) to 91.609%

Details

  • Coverage increased (+0.04%) from the base build.
  • Patch coverage: 8 of 8 lines across 2 files are fully covered (100%).
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 1442
Covered Lines: 1321
Line Coverage: 91.61%
Coverage Strength: 0.92 hits per line

💛 - Coveralls

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f1e98b3bcf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +206 to +210
decoder = await get_data_decoder_service()
decoder.invalidate_contract_abi_cache(
contract_metadata.address,
contract_metadata.chain_id,
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Move cache invalidation after persisting ABI update

process_contract_metadata invalidates the decoder cache before await contract.update() writes the new abi_id to the database. If a decode request arrives in that gap, get_contract_abi will repopulate the cache from the still-old DB row, and stale ABI data will remain cached (now for up to the 600s TTL). This makes the “immediate refresh after metadata update” behavior unreliable under concurrent traffic.

Useful? React with 👍 / 👎.

Comment on lines +514 to +517
self.get_contract_abi.cache_invalidate(self, address, chain_id)
self.get_contract_abi_selectors_with_functions.cache_invalidate(
self, address, chain_id
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Invalidate the chainless ABI cache key as well

invalidate_contract_abi_cache evicts only the exact (address, chain_id) key, but the decoder also caches lookups under (address, None) (used when chain_id is omitted and as a fallback path). Because metadata updates call invalidation with a concrete chain_id, stale chainless entries can survive until TTL expiry, so requests without chain_id may still decode with outdated ABI right after an update.

Useful? React with 👍 / 👎.

@Uxio0 Uxio0 changed the title bug(e): invalidate per-contract ABI cache after metadata update fix: invalidate per-contract ABI cache after metadata update Apr 16, 2026
@Uxio0 Uxio0 marked this pull request as draft April 16, 2026 12:36
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