fix(persistent-tee): use Poseidon L1->L2 message hash for Starknet settlement#77
Merged
Conversation
…ttlement `compute_l1_to_l2_msg_hash` hashed L1->L2 messages with the Ethereum `keccak256` StarknetMessaging.sol formula. But saya-tee settles to a Starknet piltover core, whose canonical L1->L2 hash is Poseidon (`compute_message_hash_sn_to_appc`). Katana commits to that Poseidon hash in the appchain attestation's `messages_commitment` (the L1-handler `message_hash` from its Starknet messaging collector). With keccak, piltover's recomputed `messages_commitment` never matches, so any settled block that consumes an L1->L2 message reverts with `'tee: invalid messages'`, and subsequent blocks fail `'invalid block number'` — settlement stalls permanently. This path isn't covered by the persistent-tee e2e test, which only settles plain transfer blocks (no messages). Switch to the Poseidon formula Katana uses, hashing over the L1-handler calldata `[from_address, ...payload]`: Poseidon([from, to, nonce, selector, calldata.len(), ...calldata]) Verified end-to-end against a Katana rollup settling to piltover: L1->L2 purchases (mint L1-handler) now settle, alongside L2->L1 messages. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
kariy
added a commit
to dojoengine/katana
that referenced
this pull request
May 31, 2026
The `test` workflow (and its `saya-tee-e2e` job) is path-filtered to `crates/**`/`bin/**`, so PRs that only touch integration-test crates under `tests/**` (e.g. the saya-tee e2e) never trigger it — every workflow shows as skipped. Add `tests/**/*.rs`, `tests/**/Cargo.toml`, and `Cargo.lock` to both the workflow `paths` filter and the `detect-changes` `broader-rust` filter so those changes run the workspace jobs. Bump the saya pin the `saya-tee-e2e` job builds from `17c0ee0` to `v0.4.1`, which includes the L1->L2 Poseidon message-hash fix (dojoengine/saya#77) the new messaging regression test depends on. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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
compute_l1_to_l2_msg_hash(persistent-tee settlement) hashes L1→L2 messages with the Ethereumkeccak256StarknetMessaging.solformula. Butsaya-teesettles to a Starknet piltover core, whose canonical L1→L2 message hash is Poseidon (compute_message_hash_sn_to_appc). Katana commits to that Poseidon hash in the appchain attestation'smessages_commitment— it stores the L1-handlermessage_hashproduced by its Starknet messaging collector.Because keccak ≠ poseidon, piltover's recomputed
messages_commitmentnever matches Katana's for any settled block that consumes an L1→L2 message (e.g. a relayed L1-handler). piltover reverts with'tee: invalid messages', and every subsequent block then fails'invalid block number'— settlement stalls permanently.This path isn't covered by the persistent-tee e2e test, which only settles plain transfer blocks (no messages), so it slipped through.
Fix
Use the Poseidon formula Katana uses, hashing over the L1-handler calldata
[from_address, ...payload]:(See katana
crates/messaging/src/stream/collector/starknet.rs::compute_starknet_to_appchain_message_hash, whose result becomes the L1-handlermessage_hashfed into the attestation.) Drops the now-unusedsha3import.Verification
Verified end-to-end against a local Katana rollup settling to a piltover core via
saya-tee --mock-prove: blocks that consume an L1→L2 message (amint_gameL1-handler) now settle cleanly, alongside L2→L1 messages — both directions of a cross-chain demo work andsaya-teereports no settlement errors.