Skip to content

Runtime agnostic Xcm Transact #853

@olanod

Description

@olanod

Based on my not in dept observation of the code in the xcm crate, it's my assumption that the Call in a Transact instruction must be crafted for the specific targeted chain, it seems that we either depend on the other chain's runtime to get its Call type to construct the DoubleEncoded call parameter of the Transact instruction or we use the opaque version where the encoded bytes usually come form the client. Either way the bytes encode not only the specific extrinsic of a given pallet but also it's "place" in the runtime represented by a prefix index which is the way SCALE encodes the enum of a runtime's calls.
Example taken from a test in orml:

let call = 
    relay::Call::System(frame_system::Call::<relay::Runtime>::remark_with_event { remark: vec![1, 1, 1] });

The disadvantage I see here is that this transact mechanism kind of encourages coupling among parachains, imagine several parachains have a kittens pallet with a meow extrinsic, also imagine a scare_other_kittens extrinsic that accepts a list of multi-locations used to send a message to several chains to make their kittens meow at the same time, I'd have to know in advance how the kittens pallet was declared in the other runtimes or pass the responsibility to the user of the extrinsic to tell me that, maybe I can query the other chain's metadata to know if they can meow and know the index of the pallet but delegating that to the client seems ugly and error prone, also parachains might just want to send XCM messages without user intervention.

I think a more "generic" Transact would be very useful, instead of calling specific extrinsics in a specific pallet mounted in a specific position it would be nice to just tell the other chain here's the data of the call that follows this interface. Or in practical terms, allow the call to be the bytes of the extrinsic without its index in the runtime and while we are at it maybe also ditch the index of the extrinsic within its pallet(e.g. in the encoded empty remark 0x000100 leave out the 0x0001) and replace those with an "interface identifier". The ID could come from a well known registry of interfaces or simpler can be to use the existing type information of runtimes to encode extrinsic name with the arguments type info that can be hashed to have something unique enough to be able to route the message. Parachain runtimes can generate the hash table that maps extrinsics at compile time, when the extrinsic name is not enough to avoid collisions(initially I think is good enough) an annotation in the extrinsic can help. Over time it can become the way teams "standardize" certain interfaces. e.g. #[interface="RoyalKittenAssociation_meow"] pub fn meow(...) so now we can scare_other_kittens without worrying if the sister chains even have the same meow implementation.

I might be ignoring important details that would make this impossible but anyway I hope others see the potential in solving this problem, it empowers more the community to experiment with potential future "standards" instead of relying on the core set of instructions to be extended which doesn't scale well.

Metadata

Metadata

Assignees

No one assigned

    Labels

    T6-XCMThis PR/Issue is related to XCM.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions