feat(ismp): dispatch_get, spec-13 event fields, per-target slot duration, honest GET delivery caveat - #147
Merged
Merged
Conversation
…ion, honest GET delivery caveat
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.
Spec 13 —
dispatch_get, spec-13 event fields, per-target Hyperbridge slot durationspec_version 12 → 13,transaction_versionstays at 3 (events are metadata; addingcall_index(3)leaves indices 0–2 and their encodings untouched, so offline-signed extrinsics still decode). No migration, no storage change.What changes
Every
ismpMessagingevent now carries what the callback already had in hand. Spec 12 made inbound events attributable withcommitment; this adds the rest so no further runtime upgrade is needed for cross-chain observability.RequestDispatchednonce,timeout_timestamp,body_len,kindMessageReceivednonce,timeout_timestampMessageRejectedbody_len,nonce,timeout_timestampGetResponseReceiveddest,height,nonce,timeout_timestampRequestTimedOutkind,nonce,timeout_timestamp,body_lenNew
RequestKind { Post, Get }(1 byte), shared byRequestDispatchedandRequestTimedOut.timeout_timestamp = 0means never expires — upstream's own branch, notnow + 0.New extrinsic
dispatch_get(dest, keys, height, timeout)atcall_index(3), root-only likedispatch_post. It exists because a POST can be refused and a GET cannot:pallet-ismp-demoon Hyperbridge rejects anySubstrate(_)source and the relayer dry-runs before submitting, so our POSTs were dropped silently. A GET has no receiving module — this chain verifies the read against a commitment ofdestit already holds.Guards fail an unanswerable GET at dispatch instead of at expiry: empty
keys(NoKeysRequested), more thanMaxGetKeys = 16(TooManyKeys— each key is a membership proof a remote chain must produce),height == 0(InvalidGetHeight— the response handler compares heights for equality),dest == self(DestinationIsSelf). Weight is not benchmarked: reusesdispatch_post's base with a generous per-key term (over-charges, never under-charges).HYPERBRIDGE_SLOT_DURATION_MSnow follows the build feature: 12000 on Polkadot, 6000 on Paseo (was 6000 for both).ismp-grandpadates every Hyperbridge header asaura_slot × slot_duration; measured live, the old value would have dated every mainnet state commitment ~28 years early. Testnet builds are unchanged.Two caveats, stated in the code rather than discovered later
tesseract/messaging/messaging/src/events.rs:314-336). On this chain the answer is carried byscripts/hyperbridge/relay-get-response.mjs, a legitimate permissionless ISMP relayer: it ferries theGetRequestplus Hyperbridge's own state proof intoIsmp.handle_unsigned; the chain verifies it against the GRANDPA-tracked commitment. The relayer adds no trust.ismp-grandpastoresstate_root = child_trie_root(consensus.rs:142-150), verified live against Gargantua. A GET to Hyperbridge can only prove keys inside:child_storage:default:ISMPv2, with a Keccak proof fromismp_queryChildTrieProof. A GET for a global key can never verify — for any relayer.Verification
cargo test -p pallet-ismp-messaging— 40 (incl.dispatched_fields_rebuild_the_committed_request,a_get_response_closes_out_the_get_it_answers,commitments_hash_the_abi_encoding_not_scalewith vectors shared with the JS harness,a_get_response_is_accepted_without_any_accepted_source)cargo test -p orbinum-runtime— 45 on both targets (slot_duration_follows_the_coprocessorpins the docs' table per feature)scripts/hyperbridge/run-tests.sh allagainst a dev node — e2e 61, security 43 (incl. alldispatch_getguards and no nonce consumed on rejection), roundtrip 24 (two dev nodes;on_responseexecuted on-chain throughhandle_unsignedwith a real state proof, not in the mock)relay-get-response.mjs --bootstrap-local— 28/28: a local spec-13 node seeded with Gargantua's live child-trie root answered a GET with a real proof fetched from Gargantua;GetResponseReceivedwith the requested height,found = 1test-interop-preflight.mjsagainst testnet — 18/19, the only failure isspec ≥ 13(this release); consensus is fresh both ways (Gargantua ≤ 8 blocks behind us, we ≤ 11 behind it), our commitment equals Gargantua's realismp.childTrieRootFindings pinned by tests (so they cannot regress silently)
keccak256(abi.encode(request))— Solidity ABI, not SCALE.Request::encode()is an inherent method that shadows theEncodetrait;source/desttravel as display strings ("SUBSTRATE-orbi"); the GET field order issource, dest, nonce, from, timeoutTimestamp, keys, height, context.ismp-grandpagates state proofs too, not only consensus proofs (state_machine()consultsSupportedStateMachines);validate_unsignedcollapses every failure toBadProof, which prints as "Transaction has a bad signature". Run the node with-l ismp=debugfor the real cause.