Skip to content

Verify speculative base against stored state_id only#145

Merged
ikehara merged 3 commits into
feature/explicit-state-parallelizationfrom
fix/base-state-verify-canonical-state-id
Jun 12, 2026
Merged

Verify speculative base against stored state_id only#145
ikehara merged 3 commits into
feature/explicit-state-parallelizationfrom
fix/base-state-verify-canonical-state-id

Conversation

@ikehara

@ikehara ikehara commented Jun 12, 2026

Copy link
Copy Markdown

Problem

The stitch-phase base verification in verify_expected_base_state_in_tx recomputes the expected prev_state_id with gen_state_id_from_any over the raw caller-supplied Anys. Light clients derive state IDs from a canonicalized client state (e.g. latest_height/frozen reset before hashing — see tendermint-lc and other ELCs), and that canonicalization is ELC-specific and only available inside the enclave.

As a result, the recomputed hash never matches the enclave-observed prev_state_id for any light client whose canonicalization is not the identity, and every explicit-state speculative batch deterministically fails at the stitch phase with BaseStateMismatch.

The existing unit tests did not catch this because the test helper (state_id_for_base_state) and mock-lc's gen_state_id both hash the raw Anys without canonicalization, so they were self-consistent with the buggy recompute.

Fix

  • Drop the raw-Any recompute (former check 3). The remaining checks still close the chain:
    1. supplied client_state bytes == stored canonical client_state
    2. supplied consensus_state bytes == stored canonical consensus_state at prev_height
    3. enclave-observed prev_state_id == height-indexed state_id stored by the in-enclave light client at create/update time
  • Add a regression test simulating an ELC whose canonicalized-form state_id differs from the raw-Any hash, so the asymmetry cannot reappear.
  • Rework the mismatch-rejection test so it still fails through the stored-state_id check.

Testing

  • cargo test -p service (38 passed, includes the new regression test)
  • cargo test -p enclave-api
  • cargo clippy -p enclave-api -p service --tests (only a pre-existing large_enum_variant warning in scheduler.rs, untouched by this PR)

Kiyoshi Nakao added 3 commits June 11, 2026 19:56
The stitch-phase base verification recomputed the expected prev_state_id
with gen_state_id_from_any over the raw caller-supplied Anys. Light
clients derive state IDs from a canonicalized client state (e.g.
latest_height/frozen reset before hashing), and that canonicalization is
ELC-specific and only available inside the enclave, so the recomputed
hash never matches the enclave-observed prev_state_id for any ELC whose
canonicalization is not the identity. This made every explicit-state
speculative batch fail with BaseStateMismatch at the stitch phase.

Drop the raw recompute and rely on the remaining checks: the supplied
(client_state, consensus_state) bytes are pinned to the canonical store,
and the enclave-observed prev_state_id must match the height-indexed
state_id stored by the in-enclave light client at create/update time.
@ikehara ikehara merged commit 9189c57 into feature/explicit-state-parallelization Jun 12, 2026
2 checks passed
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.

1 participant