Skip to content

fix(genvm): serve latest-finalized storage reads from finalized state 🐛 - #1792

Open
kp2pml30 wants to merge 1 commit into
v0.123-devfrom
fix/1791-latest-finalized-storage-read
Open

kp2pml30 wants to merge 1 commit into
v0.123-devfrom
fix/1791-latest-finalized-storage-read

Conversation

@kp2pml30

Copy link
Copy Markdown
Member

Fixes #1791

Problem and outcome

A cross-contract view(state=LATEST_FINAL) / LATEST_FINALIZED makes GenVM call host storage_read with mode 1. Host.storage_read had assert type != StorageView.LATEST_FINALIZED; the AssertionError escaped the host loop, and run_genvm_host treated it as a transient failure, retrying with exponential backoff (5s, 10s, 20s, …) until the 600s budget ran out:

  • gen_call hangs for 600s and returns -32603 Internal error (behind Cloudflare: 524 after ~125s)
  • writes end with CONSENSUS_LEADER_EXEC_TIMEOUT / Leader execution exceeded 600.000s

The prd image (v0.121.24) and v0.123-dev both contain the assert.

Now LATEST_FINALIZED reads are served from the contract's finalized state. Slots without a finalized value (including contracts that are not finalized yet, or have no finalized bucket) read as zeroes. DEFAULT / LATEST_DECIDED reads are unchanged.

Implementation and validation

  • StateProxy.storage_read_finalized: defaults to zeroes, for proxies with no finalized state such as _StateProxyNone
  • _SnapshotView implements it over states["finalized"]. The decode caches are now keyed by state status, so accepted and finalized reads of the same slot can't alias, and writes don't leak into the finalized view
  • tests/unit/test_storage_read_latest_finalized.py: red on v0.123-dev (the AssertionError), green with the fix. Full tests/unit/ suite passes

Local stack, with a minimal source and caller contract (not the reporter's code):

Build Call Result
v0.121.24 (prd) read_default, read_latest_non_final OK, 1.0s
v0.121.24 (prd) read_latest_final -32603 after 600.2s; 7 GenVM attempts, each AssertionError in host_loop
this PR read_latest_final OK, 0.3s
this PR set_marker accepted, not finalized non-final returns the new value, finalized returns the old value
this PR after finalization both views return the new value
this PR consume_latest_final write MAJORITY_AGREE, leader SUCCESS, 15s

Not in scope

  • Retry policy: any non-HostException raised from a host callback still turns into retries until the time budget runs out
  • LATEST_DECIDED: still follows the run's state_status, which read_contract_major relies on

@kp2pml30 kp2pml30 self-assigned this Oct 14, 2026
@coderabbitai

coderabbitai Bot commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 3cb0b104-40b7-4fbd-b474-ef19aca48fce

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kp2pml30 kp2pml30 assigned MuncleUscles and unassigned kp2pml30 Oct 14, 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