Skip to content

feat(ismp): model DeliveryConfirmed, the spec 14 delivery proof - #4

Merged
nol4lej merged 1 commit into
mainfrom
feat/ismp-delivery-confirmed
Sep 13, 2026
Merged

nol4lej merged 1 commit into
mainfrom
feat/ismp-delivery-confirmed

Conversation

@nol4lej

@nol4lej nol4lej commented Sep 13, 2026

Copy link
Copy Markdown
Member

What

Adds DeliveryConfirmedEvent and a matching arm on IsmpMessagingEvent, modelling runtime spec 14's ismpMessaging.DeliveryConfirmed { commitment, relayer, height }. Version 0.4.0 → 0.5.0.

Why it exists at all

Until spec 14 the chain had no witness to its own outbound message landing. PostRequestHandled fires on the destination, so from Orbinum's own state a delivered POST and one still in flight were indistinguishable — permanently, not just until some later block.

The protocol offers no way to fix that by asking: upstream #840 removed PostResponse entirely, so a receiving module cannot reply. What the destination does leave behind is a receipt, written before the receiving module runs and deleted again if that module errs — so its presence proves delivered and executed, and being ordinary storage, a GET can prove it. That is what the runtime now does, and this event is the result.

What the event does and does not claim

The receipt read is the coprocessor's, not the final chain's. Hyperbridge's proxy re-dispatches through the same on_accept that writes receipts, so DeliveryConfirmed proves Hyperbridge accepted and forwarded the message. Execution on the far side is one hop further and is not witnessed here — that remains a destination-chain log, which consumers read separately. The doc comment on the type says this explicitly rather than leaving a reader to infer a stronger guarantee than the event carries.

Two field notes worth carrying into any consumer:

  • commitment names the POST being confirmed, not the GET that proved it. Those are different messages with different commitments. Reporting the GET's would produce a value nothing else has seen and join to nothing.
  • relayer is opaque bytes, not necessarily an account — the same caveat RequestHandledEvent.relayer already documents. 32 bytes for a Substrate account, 20 for an EVM relayer, and a self-relaying script may put an ASCII tag there. Rendering arbitrary bytes as an address is a lie in monospace.

height is a u64 and therefore a bigint, consistent with every other height in this file.

Breaking-ness

Not breaking for data shapes — nothing existing changed. It is breaking for exhaustive matching: IsmpMessagingEvent now has eight arms instead of seven, so a consumer with an exhaustive switch over it will fail to compile until it handles the new case. That is the intended loud failure, and it is the reason this is a minor bump rather than a patch.

The union's doc comment claimed "All seven variants the pallet emits are here". Corrected to eight.

Deliberately not included

confirm_delivery (call index 4) is not modelled. IsmpModule is read-only by an explicit, documented decision — "Dispatching a message is an extrinsic … so it is deliberately not exposed here" — and the repo has no call-index model for ISMP at all. Adding one to accommodate a single new extrinsic would open a surface nobody asked for, and the extrinsic is root-gated today anyway.

Verification

pnpm check clean: 866 tests across 36 files, plus lint, format and typecheck.

The new test lives in tests/types/ismp-types.test.ts, which already pins event shapes by runtime spec. It builds a DeliveryConfirmedEvent, places it in the union, and asserts height is a bigint — the field most likely to be silently typed as number by a future edit.

Notes for the reviewer

  • The release fires on merge, not on a tag. release.yml watches package.json on main, so landing this publishes 0.5.0 to npm.
  • Nothing here depends on spec 14 being deployed. These are types; they describe an event that does not fire yet. The event only starts appearing once spec 14 ships and delivery confirmations actually run.
  • Companion changes in the other two consumers of this event: the indexer stores it (no schema migration — commitment, relayer and get_height already exist), and the explorer renders it as a confirmed status kept distinct from executed, since the two carry different evidence and only executed names a transaction.

@nol4lej
nol4lej merged commit 18d690c into main Sep 13, 2026
3 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