Skip to content

Avoid generic parameter in CosmosMsg<C> #2249

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

Open
chipshort opened this issue Sep 10, 2024 · 3 comments · May be fixed by #2475
Open

Avoid generic parameter in CosmosMsg<C> #2249

chipshort opened this issue Sep 10, 2024 · 3 comments · May be fixed by #2475
Assignees
Labels
Breaking (contracts) Compile-time breaking contracts
Milestone

Comments

@chipshort
Copy link
Collaborator

We still need to support the custom message feature, but having this as a generic is quite annoying for users because it has to be carried through the whole code.

In our meeting, switching to dynamic dispatch with erased_serde / typetag was proposed.

We should make sure that downstream users are not affected by the fact that this makes CosmosMsg no longer Send + Sync and that the custom message type is not necessarily Sized anymore.
This could probably be looked at for something like MultiTest.

@chipshort chipshort added the Breaking (contracts) Compile-time breaking contracts label Sep 10, 2024
@chipshort chipshort added this to the 3.0.0 milestone Sep 10, 2024
@kulikthebird kulikthebird self-assigned this May 9, 2025
@kulikthebird
Copy link
Member

What are the use cases of the generic param in CosmosMsg? As far as I can see the message is added to the response of entry points handlers in smart contracts. In wasmd it is translated from CosmosMsg into []sdk.Msg by a default message encoder:

func DefaultEncoders(unpacker codectypes.AnyUnpacker, portSource types.ICS20TransferPortSource) MessageEncoders {
	return MessageEncoders{
		Bank:         EncodeBankMsg,
		Custom:       NoCustomMsg,
		Distribution: EncodeDistributionMsg,
		IBC:          EncodeIBCMsg(portSource),
		IBC2:         EncodeIBCv2Msg,
		Staking:      EncodeStakingMsg,
		Any:          EncodeAnyMsg(unpacker),
		Wasm:         EncodeWasmMsg,
		Gov:          EncodeGovMsg,
	}
}

where NoCustomMsg is defined as:

func NoCustomMsg(_ sdk.AccAddress, _ json.RawMessage) ([]sdk.Msg, error) {
	return nil, errorsmod.Wrap(types.ErrUnknownMsg, "custom variant not supported")
}

So in other words, if a given blockchain developers does not configure otherwise, smart contracts should not return custom types.

Some blockchains may use the custom msg by implementing their own encoder. The problem is that Rust's type system cannot prevent mistakes related to mismatch between the chain's custom type and the one defined in the contracts.

My proposal is to use Custom(Binary) as a custom field. Contract devs experience would change negligibly - they'd need to serialize the custom message before creating CosmosMsg::Custom. We could add a new method for that:

impl CosmosMsg {
    pub fn new_custom<T: Into<Binary>>(msg: T) -> Self {
        Self::Custom(msg.into())
    }
}

PoC: #2475

@webmaster128
Copy link
Member

use Custom(Binary) as a custom field

This approach is reasonable, but it is pretty much what CosmosMsg::Any already does

@chipshort
Copy link
Collaborator Author

I think the benefits that CosmosMsg::Custom has over CosmosMsg::Anyare:

  • some level of type safety (and chains can provide types for this in their own crates)
  • uses JSON, no need to choose a Protobuf library, get protobuf definitions, etc.

With the Custom(Binary) approach, we lose the first one. And in some sense, also the second one because we no longer have any control over the encoding of the data.
This change also seems to be breaking the contract <-> VM interface, i.e. contracts that use the new way don't work on pre-3.0 chains and the other way around. If we want to solve this issue, we can break the contracts on the source level, but not this interface.

@kulikthebird kulikthebird linked a pull request May 17, 2025 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Breaking (contracts) Compile-time breaking contracts
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants