-
Notifications
You must be signed in to change notification settings - Fork 1.1k
PubSub Mechanism - Addresses #606 #9994
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
69f4973 to
a2544f8
Compare
a2544f8 to
503080b
Compare
cc150d3 to
8289eda
Compare
886d52f to
9b70059
Compare
9b70059 to
68edfac
Compare
bkchr
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are several issues with the pull request:
- You introduce a
Subscribemessage. This was never part of the issue and also makes no real sense. Subscription should be handled totally local on the parachain, no one outside the parachain (besides the collator) needs to know this. - We should probably store the roots of the published parachain data in a map. So, we only need to include the roots in the storage proof we are interested in.
- I probably did not make this explicit enough, but right now you are forcing every parachain to include all the roots from all the parachains and you also have no way to find out which parachains you are interested in. There should be a runtime api introduced that
KeyToIncludeInRelayProofthat returns a list of keys. These keys would be for example the key to the root of the published data of one parachain and then the keys into the child trie for exactly the data we are interested in. Then on the collator side we can fetch these keys from the runtime and do not need theretrieve_subscribed_published_datamethod. - There is no way to subscribe to data in the runtime right now, especially no kind of hook that will inform you when this data changed.
| let mut p = 0u32; | ||
| let mut k = 0u32; | ||
| let mut v = 0u32; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please more expressive names.
| pub MaxPalletsInfo: u32 = 64; | ||
| pub MaxAssetTransferFilters: u32 = 6; | ||
| pub MaxPublishItems: u32 = 16; | ||
| pub MaxPublishKeyLength: u32 = 32; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Key should be directly a Hash and not generic.
Total size should be probably something like 2KiB, aka not that much crazy data.
| mod tests; | ||
|
|
||
| #[frame_support::pallet] | ||
| pub mod pallet { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no logic that cleans up the data after a parachain got off-boarded.
We probably also request that parachains first need to register themselves for publishing data (if they are not a system chain) and require a deposit for the ~2KiB of data.
hey @bkchr, thanks for the comments and review I have already addressed moving the subscriptions to the parachain, exposed them to the collator via an API and storing the roots in a storage map instead of a vec, however I would like to share with you the following: I’m exploring the path of not only adding the keys of the published data to the storage proof, but also including the data itself inside the proof so that I have done some progress but before moving deeper into that direction which would require adding some code to the relay chain interface, I would like to clarify one thing on the feedback provided, because I don’t understand whether you expect the whole relay API to be removed, or whether a relay API that only serves the relevant child-trie data would be acceptable. This is what I mean and how I would implement it: The subscriptions are handled by This second approach would still satisfy the requirement to move subscription tracking to the parachain, avoid adding all roots to the proof and I would really appreciate your input on this topic as I might be missing or misunderstanding something, thanks! |
The problem is that this doesn't work for use case of the published data. Because you can not proof that the data inside So, you just put everything in to the relay chain storage proof. Also we are maybe just interested in one of the published fields, which works better with the storage proof. |
|
Closing this PR now, re design based on feedback presented on #10679 |
This PR implements a complete publish-subscribe mechanism for parachains, addressing issue #606.
Implemented:
Review Focus
This is a design proposal and architectural review.
Please focus your attention on:
Context: Issue #606
The original issue identified the challenge of expensive inter-parachain communication. Current methods (XCM messages, off-chain protocols) are complex and inefficient for broadcasting data across multiple parachains.
The proposed solution from the discussion:
(key, value)data to the relay chain via XCM instructionThis PR implements the core publishing mechanism as discussed, following the our best interpretation of XCM Publish instruction pattern suggested by @bkchr in the issue thread.
Architecture Overview
Publishing Flow
Subscribing Flow
Components Implemented
1. XCM v5 Publish & Subscribe Instructions
Location:
polkadot/xcm/src/v5/mod.rsPublish { data: PublishData }Allows parachains to publish bounded key-value data to the relay chain.
PublishData = BoundedVec<(BoundedVec<u8, 32>, BoundedVec<u8, 1024>), 16>Subscribe { publishers: BoundedVec<u32, 100> }Allows parachains to subscribe to specific publisher parachains.
BoundedVec<u32, 100>- List of ParaIds to subscribe toNote: The instruction is temporarily added to XCM v5. Final placement (potentially XCM v6) should be discussed during the review process.
The instruction is intended to be called via
pallet-xcmsendwith the proper execution buy instructions.2. Broadcaster Pallet (Relay Chain)
Location:
polkadot/runtime/parachains/src/broadcaster/Core pallet managing published data on the relay chain.
Key features:
(ChildInfo::new_default(b"pubsub" + para_id.encode()))ParaId=>Vec<publisher ParaIds>PublishedKeysstorage tracks all keys published by each parachain for enumerationStorage:
PublisherExists: Tracks which parachains have published dataPublishedKeys: Tracks all keys per publisher (for enumeration)Subscriptions: Tracks subscription relationships (subscriber => [publishers])PublishedDataRoots: Aggregated child trie roots (exposed via well-known key for state proofs)Traits:
PublishSubscribe: Used for exposing publish and subscribe operations for pallets to implement. Intended forpallet-broadcasterbut provided a trait for possible future integrations.Main function:
pub fn handle_publish(origin_para_id: ParaId, data: Vec<(Vec<u8>, Vec<u8>)>) -> DispatchResultpub fn handle_subscribe(subscriber_para_id: ParaId, publishers: Vec<ParaId>) -> DispatchResult3. BroadcastHandler Trait & Adapter
Location:
polkadot/xcm/xcm-executor/src/traits/broadcast_handler.rspolkadot/xcm/xcm-builder/src/broadcast_adapter.rsBroadcastHandlertrait:ParachainBroadcastAdapter:ParaIdfrom XCMLocation4. XCM Executor Integration
Location:
polkadot/xcm/xcm-executor/src/lib.rsThe executor processes both
PublishandSubscribeinstructions by calling:Config::BroadcastHandler::handle_publish()Config::BroadcastHandler::handle_subscribe()5. XCM Executor Config Trait Extension
Location:
polkadot/xcm/xcm-executor/src/config.rsAdded
BroadcastHandlerto the executor's Config trait:This requires all XCM executors to specify their broadcast handler implementation. Provided
()implementation.6. ParachainHost Runtime API
Location:
API definition:
polkadot/primitives/src/runtime_api.rsThe ParachainHost runtime API was bumped to v16 with the addition of:
The
get_subscribed_datamethod is the primary method used by collators to fetch filtered data for their parachain.7. Well-Known Key for Data Roots
Location:
polkadot/primitives/src/v9/mod.rsAdded well-known key for inclusion in relay chain state proofs:
This key is included in relay chain state proofs, allowing parachains to verify data roots and detect changes.
8. Relay Chain Interface Extension
Location:
cumulus/client/relay-chain-interface/src/lib.rsExtended the RelayChainInterface trait with:
Implementations:
RelayChainInProcessInterface- Direct runtime API callRelayChainRpcInterface- RPC client call to relay chain nodeThis interface is used by collators in
cumulus/client/parachain-inherent/src/lib.rsto fetch published data when building inherent data.9. ParachainInherentData Extension
Location:
cumulus/primitives/parachain-inherent/src/lib.rsAdded
published_datafield toParachainInherentData:Design rationale: This follows the same pattern as existing message types
(downward_messages, horizontal_messages). A direct field in the inherent data structure.10. InboundPublishedData Wrapper
Location:
cumulus/pallets/parachain-system/src/parachain_inherent.rsWrapper type for published data validation:
Purpose: Aligns with the SDK's pattern of wrapping inbound data types (InboundDownwardMessage, InboundHrmpMessage) for consistency and future extensibility.
11. Parachain-System Integration
Location:
cumulus/pallets/parachain-system/src/lib.rsStorage:
PublishedData: Double map storing received data (publisher ParaId, key) => valuePreviousPublishedDataRoots: Tracks previous block's data roots for change detectionInherent creation (
set_validation_data):published_datafrom collator via inherentBROADCASTER_PUBLISHED_DATA_ROOTS)process_published_data()with root comparisonChange Detection Logic (
process_published_data):PreviousPublishedDataRoots11. Collator-Side Fetching Logic
Location:
cumulus/client/parachain-inherent/src/lib.rsCollators fetch published data when building inherent data:
This data is then included in the
ParachainInherentDatapassed to the parachain runtime.12. Rococo Integration (Testing Purposes)
Location:
polkadot/runtime/rococo/src/A full demo integration of the Broadcaster pallet and Xcm related config can be found at:
https://github.com/blockdeep/polkadot-sdk/tree/feat/pubsub-root
Rationale: Enables reviewers to test the complete flow using Zombienet (config provided in pubsub-dev/zombienet.toml).
Testing
Relevant testing following SDK patterns have been provided to the newly added components.
It is recommended to run this test on the testing branch as it has both tooling and the Broadcaster pallet setup on Rococo. However it can be used as reference on any other integration.
Local Testing with Zombienet
A Zombienet configuration is provided in pubsub-dev/ for local testing:
cd pubsub-dev./build.sh # Build polkadot and polkadot-parachainzombienet spawn zombienet.tomlThis spins up:
Note: The pubsub-dev/ directory is for review testing only and will be removed after the review process.
Extrinsics:
Sovereign Account:0x04030070617261e80300000000000000000000000000000000000000000000000000000b00407a10f35apallet-xcmsendcall:0x02003300050100050c000400000002286bee1300000002286bee0035e8030000pallet-xcmsendcall:0x02003300050100050c000400000002286bee1300000002286bee003404143078313233143078313233Known Behavior
Closure
Please share any concerns, suggestions, or alternative approaches. This is an early-stage proposal and we welcome all input to align with the SDK's architecture and design principles.
Related: #606