Skip to content

feat(spec-msg): add Speculative Messaging primitives#12676

Draft
yrong wants to merge 3 commits into
paritytech:masterfrom
yrong:rk-spec-msg-primitives
Draft

feat(spec-msg): add Speculative Messaging primitives#12676
yrong wants to merge 3 commits into
paritytech:masterfrom
yrong:rk-spec-msg-primitives

Conversation

@yrong

@yrong yrong commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Introduce the parachain-side and relay-visible primitives for Speculative Messaging v0.5 (per PR #12659 design).

Relay-visible (polkadot-primitives::v9):

  • StreamsRoot newtype and RequiresSet
  • UMPSignal::Provides/Requires + CandidateUMPSignals; MAX_UMP_SIGNALS=4 bounds ump_signals(); NodeFeature::SpeculativeMessaging=5.

Parachain-side (cumulus-primitives-spec-messaging):

  • StreamId: frozen 8-byte big-endian canonical encoding
  • mmr: domain-tagged SpecMerge (blake2), peaks-only accumulator matching mmr-lib.
  • streams_root: keyed binary Patricia trie over (StreamId, stream root); keyed membership proofs bind the StreamId.
  • lift: ConsumptionRecord / RequiresLift / MMRExtensionProof and build_requires synthesis (trusted record + untrusted POV lifts, forward-chain stitch).
  • message: fetch protocol (MessagesRequest/Response) + verify_messages_response, leaf_hash, SpecHasher.
  • cumulus-primitives-core: re-exports + SpeculativeOutbox/InboxApi.

Resolves #12346 and #12347

yrong added 3 commits July 17, 2026 21:51
Introduce the parachain-side and relay-visible primitives for Speculative
Messaging v0.5 (per PR paritytech#12659 design).

Relay-visible (polkadot-primitives::v9):
- StreamsRoot newtype and RequiresSet (canonical sorted (ParaId, StreamsRoot)
  set, strictly-increasing ParaId enforced at decode; MAX_SOURCES_PER_BLOCK).
- UMPSignal::Provides/Requires + CandidateUMPSignals; MAX_UMP_SIGNALS=4 bounds
  ump_signals(); NodeFeature::SpeculativeMessaging=5.

Parachain-side (cumulus-primitives-spec-messaging):
- StreamId: frozen 8-byte big-endian canonical encoding, reserved-kind rejection.
- mmr: domain-tagged SpecMerge (blake2), peaks-only accumulator matching mmr-lib.
- streams_root: keyed binary Patricia trie over (StreamId, stream root); keyed
  membership proofs bind the StreamId.
- lift: ConsumptionRecord / RequiresLift / MMRExtensionProof and build_requires
  synthesis (trusted record + untrusted POV lifts, forward-chain stitch).
- message: fetch protocol (MessagesRequest/Response) + verify_messages_response,
  leaf_hash, SpecHasher.
- cumulus-primitives-core: re-exports + SpeculativeOutbox/InboxApi.

Hardening:
- Frozen consensus vectors for the StreamsRoot trie root and MMR root.
- verify_messages_response rejects malformed (start_peaks, base) frontiers
  instead of panicking in Mmr::append; guards base+len overflow.
- Bound StreamProof depth (<= KEY_BITS) and MMRExtensionProof connecting nodes.
Extend the requires-lift PoV harness to cover the design's "Proof Size
Considerations" worst case alongside the empirical measurements, as two
distinct angles:

- Angle 1 (empirical share): a full-source candidate with real measured
  proofs (deepest 100k-message extension + 1024-stream tree_proof) — 3.44%
  of MAX_POV_SIZE, guarded <10%.
- Angle 2 (day-scale worst case): a synthetic ~30-node extension (log2(1e9))
  + one advance-proof gap + tree_proof, per the design's ~4KB/stream +
  ~2KB/gap ceiling. Guards one worst lift <8KB and reframes headroom as the
  authoring-time budget (how many touched streams fit vs the source cap).

Also note in-code that each connecting node is (u64 position, Hash) = 40 B,
~25% above the design's hash-only 32 B count (positions are derivable from
prev_size + new_mmr_size; stripping them is a deferred, consensus-critical
optimization).
Add the wire/encoding types of the v0.5 channel protocol (type primitives
only; pallet logic stays deferred to integration):

- SpecMsgKind { Signal(SpecMsgSignal), Data(Vec<u8>) } — channel-stream leaf
  payload (fills leaf_hash's opaque `payload`; Data bound is the STF constant,
  not a type bound, matching the design's Vec<u8>).
- SpecMsgSignal { OpenChannel{version}, CloseChannel, Upgrade{version} } —
  sender channel lifecycle; OpenChannel is variant index 0 (frozen core).
- Register { version, up_to: MessagePosition, grant: WindowGrant, closed } —
  the receiver's ack-stream leaf payload, read out-of-band.
- WindowGrant { max_messages, max_bytes, max_message_size } — advisory credit.

Frozen-core encoding vectors pin OpenChannel=index 0 and the Register byte
layout (consensus-critical, read cross-chain). MessagePosition gains
MaxEncodedLen + Default (needed by Register). Re-exported via lib.rs and
cumulus-primitives-core.

Deferred to the pallet: ChannelId, OutChannels/InChannels storage, send()
API, window accounting, version enforcement, accept extrinsic.
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.

spec-msg/primitives: Implement Speculative Messaging primitives

1 participant