Source on-chain explicit-state base payload from LCP canonical store#74
Closed
ikehara wants to merge 2 commits into
Closed
Source on-chain explicit-state base payload from LCP canonical store#74ikehara wants to merge 2 commits into
ikehara wants to merge 2 commits into
Conversation
added 2 commits
June 12, 2026 16:13
queryOnChainCommittedExplicitStateBase rebuilt the ELC base payload from scratch via CreateInitialLightClientState at the on-chain committed height. The rebuilt payload only matches the LCP canonical store at the create-client height: after any committed in-enclave update, the stored canonical client_state is the enclave's round-trip encoding (notably chain_info_json is re-serialized by serde with different key names, order, and dropped unknown keys), so LCP's stitch-phase byte-equality check rejected every speculative batch anchored at the on-chain base with BaseStateMismatch (stored speculative base client_state mismatch). Use the on-chain commitment only as the (height, state_id) witness and take the payload bytes verbatim from the LCP canonical query. The on-chain state_id is still threaded into the first unit's prev_state_id, so LCP keeps verifying that the speculative chain anchors at exactly the committed state. When the canonical latest height does not match the on-chain committed height (canonical drifted ahead), fail fast with both heights instead of letting LCP reject the batch with a byte-level mismatch; serving historical payloads needs LCP-side support either way.
The explicit-state path anchors speculative batches at the on-chain committed base, but the LCP canonical store routinely advances past the on-chain commitment: updateELC commits canonical state at the stitch regardless of whether the caller submits the resulting UpdateClient message (e.g. a channel handshake step that turns out to need no proof discards it). Once canonical is ahead, the speculative path cannot anchor at the on-chain height — the canonical store only serves the latest payload — and previously every subsequent update attempt failed without a recovery path. Type the drift detection as ExplicitStateBaseDriftError and recover in updateELCForUpdateClient by falling back to the serial update path: the origin prover builds headers trusted at the on-chain client state, and the enclave anchors each serial update at its stored consensus for that height (light clients accept updates from older trusted heights and only move latest_height forward), producing messages that reconnect the on-chain client regardless of how far canonical has advanced. The fallback re-verifies the drifted span, so it is slower than the speculative path, but it is stateless and heals the drift on the next submission; subsequent updates use the speculative path again.
Author
|
Superseded by upstream lcp change datachainlab/lcp#143 (commit c6fa4ce "enclave-api: drop inappropriate bincode checks from speculative base verify"), which removes the underlying byte-equality check this PR was working around. state_id remains the CAS and absorbs canonicalize-equivalent differences in the supplied Anys; value-level divergence still surfaces as a state_id mismatch. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
queryOnChainCommittedExplicitStateBaserebuilds the ELC base payload from scratch viaCreateInitialLightClientState(baseHeight). The rebuilt payload only byte-matches the LCP canonical store at the create-client height: after any committed in-enclave update, the stored canonicalclient_stateis the enclave's round-trip encoding. In particularchain_info_jsonis parsed into a typed struct and re-serialized by serde inside the enclave, which changes key names (kebab-case → snake_case for fields without a rename), key order, and silently drops unknown keys.As a result, every speculative batch anchored at the on-chain base after the first committed update is deterministically rejected by LCP's stitch-phase byte-equality verification:
The activate-client path is unaffected (it uses the LCP canonical base verbatim), so the failure first surfaces on the handshake
updateClientpath. Reproduced deterministically on cosmos-arbitrum-ibc-lcp E2E CI and on a dev cluster handshake run.Fix
Use the on-chain commitment only as the
(height, state_id)witness and take the base payload bytes verbatim from the LCP canonical query:state_idis still threaded into the first unit'sprev_state_id(bindFirstUnitToExplicitStateBase), so LCP keeps verifying that the speculative chain anchors at exactly the on-chain committed state.Tests
TestQueryOnChainExplicitStateBaseWithFallbackUsesCanonicalPayloadAtOnChainHeight: the returned base carries the canonical payload Anys verbatim and the on-chain state_id.TestQueryOnChainExplicitStateBaseWithFallbackRejectsCanonicalHeightDrift: on-chain/canonical height drift is rejected with both heights in the error.go build ./...,go vet ./relay/,go test ./...pass.🤖 Generated with Claude Code