From 88d29c94e3c59abcc5d58907ce82847261f0b73b Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Tue, 14 Nov 2023 14:29:58 +0100 Subject: [PATCH 1/3] Handle both stargate and any CosmosMsg variant --- types/msg.go | 39 ++++++++++++++++++++++++++++++++++++++- types/msg_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/types/msg.go b/types/msg.go index ddbce9d14..bc50bec07 100644 --- a/types/msg.go +++ b/types/msg.go @@ -103,10 +103,47 @@ type CosmosMsg struct { Gov *GovMsg `json:"gov,omitempty"` IBC *IBCMsg `json:"ibc,omitempty"` Staking *StakingMsg `json:"staking,omitempty"` - Stargate *StargateMsg `json:"stargate,omitempty"` + Stargate *StargateMsg `json:"any,omitempty"` Wasm *WasmMsg `json:"wasm,omitempty"` } +func (m *CosmosMsg) UnmarshalJSON(data []byte) error { + // We need a custom unmarshaler to parse both the "stargate" and "any" variants + type InternalCosmosMsg struct { + Bank *BankMsg `json:"bank,omitempty"` + Custom json.RawMessage `json:"custom,omitempty"` + Distribution *DistributionMsg `json:"distribution,omitempty"` + Gov *GovMsg `json:"gov,omitempty"` + IBC *IBCMsg `json:"ibc,omitempty"` + Staking *StakingMsg `json:"staking,omitempty"` + Any *StargateMsg `json:"any,omitempty"` + Wasm *WasmMsg `json:"wasm,omitempty"` + Stargate *StargateMsg `json:"stargate,omitempty"` + } + var tmp InternalCosmosMsg + err := json.Unmarshal(data, &tmp) + if err != nil { + return err + } + + // Use "Stargate" for both variants + if tmp.Stargate == nil && tmp.Any != nil { + tmp.Stargate = tmp.Any + } + + *m = CosmosMsg{ + Bank: tmp.Bank, + Custom: tmp.Custom, + Distribution: tmp.Distribution, + Gov: tmp.Gov, + IBC: tmp.IBC, + Staking: tmp.Staking, + Stargate: tmp.Stargate, + Wasm: tmp.Wasm, + } + return nil +} + type BankMsg struct { Send *SendMsg `json:"send,omitempty"` Burn *BurnMsg `json:"burn,omitempty"` diff --git a/types/msg_test.go b/types/msg_test.go index ffd6baa41..cf63a1045 100644 --- a/types/msg_test.go +++ b/types/msg_test.go @@ -1,6 +1,7 @@ package types import ( + "encoding/base64" "encoding/json" "testing" @@ -76,6 +77,35 @@ func TestWasmMsgInstantiate2Serialization(t *testing.T) { require.Equal(t, []byte{0x52, 0x43, 0x95, 0x6b, 0x38, 0x62, 0xc2, 0x8a}, msg.Instantiate2.Salt) } +func TestAnyMsgSerialization(t *testing.T) { + expectedData, err := base64.StdEncoding.DecodeString("5yu/rQ+HrMcxH1zdga7P5hpGMLE=") + require.NoError(t, err) + + // test backwards compatibility with old stargate variant + document1 := []byte(`{"stargate":{"type_url":"/cosmos.foo.v1beta.MsgBar","value":"5yu/rQ+HrMcxH1zdga7P5hpGMLE="}}`) + var res CosmosMsg + err = json.Unmarshal(document1, &res) + require.NoError(t, err) + require.Equal(t, CosmosMsg{ + Stargate: &StargateMsg{ + TypeURL: "/cosmos.foo.v1beta.MsgBar", + Value: expectedData, + }, + }, res) + + // test new any variant + document2 := []byte(`{"any":{"type_url":"/cosmos.foo.v1beta.MsgBar","value":"5yu/rQ+HrMcxH1zdga7P5hpGMLE="}}`) + var res2 CosmosMsg + err = json.Unmarshal(document2, &res2) + require.NoError(t, err) + require.Equal(t, res, res2) + + // serializing should use the new any variant + serialized, err := json.Marshal(res) + require.NoError(t, err) + require.Equal(t, document2, serialized) +} + func TestGovMsgVoteSerialization(t *testing.T) { document := []byte(`{"vote":{"proposal_id":4,"vote":"no_with_veto"}}`) From c401798b4e48fe5b4ec75c9e5f47fa7683b9bbf2 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Wed, 15 Nov 2023 15:51:31 +0100 Subject: [PATCH 2/3] Use Any field for new AnyMsg --- types/msg.go | 18 +++++++++--------- types/msg_test.go | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/types/msg.go b/types/msg.go index bc50bec07..d8ada04d1 100644 --- a/types/msg.go +++ b/types/msg.go @@ -103,7 +103,7 @@ type CosmosMsg struct { Gov *GovMsg `json:"gov,omitempty"` IBC *IBCMsg `json:"ibc,omitempty"` Staking *StakingMsg `json:"staking,omitempty"` - Stargate *StargateMsg `json:"any,omitempty"` + Any *AnyMsg `json:"any,omitempty"` Wasm *WasmMsg `json:"wasm,omitempty"` } @@ -116,9 +116,9 @@ func (m *CosmosMsg) UnmarshalJSON(data []byte) error { Gov *GovMsg `json:"gov,omitempty"` IBC *IBCMsg `json:"ibc,omitempty"` Staking *StakingMsg `json:"staking,omitempty"` - Any *StargateMsg `json:"any,omitempty"` + Any *AnyMsg `json:"any,omitempty"` Wasm *WasmMsg `json:"wasm,omitempty"` - Stargate *StargateMsg `json:"stargate,omitempty"` + Stargate *AnyMsg `json:"stargate,omitempty"` } var tmp InternalCosmosMsg err := json.Unmarshal(data, &tmp) @@ -126,9 +126,9 @@ func (m *CosmosMsg) UnmarshalJSON(data []byte) error { return err } - // Use "Stargate" for both variants - if tmp.Stargate == nil && tmp.Any != nil { - tmp.Stargate = tmp.Any + // Use "Any" for both variants + if tmp.Any == nil && tmp.Stargate != nil { + tmp.Any = tmp.Stargate } *m = CosmosMsg{ @@ -138,7 +138,7 @@ func (m *CosmosMsg) UnmarshalJSON(data []byte) error { Gov: tmp.Gov, IBC: tmp.IBC, Staking: tmp.Staking, - Stargate: tmp.Stargate, + Any: tmp.Any, Wasm: tmp.Wasm, } return nil @@ -309,9 +309,9 @@ type FundCommunityPoolMsg struct { Amount Coins `json:"amount"` } -// StargateMsg is encoded the same way as a protobof [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). +// AnyMsg is encoded the same way as a protobof [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). // This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md) -type StargateMsg struct { +type AnyMsg struct { TypeURL string `json:"type_url"` Value []byte `json:"value"` } diff --git a/types/msg_test.go b/types/msg_test.go index cf63a1045..5da14be4d 100644 --- a/types/msg_test.go +++ b/types/msg_test.go @@ -87,7 +87,7 @@ func TestAnyMsgSerialization(t *testing.T) { err = json.Unmarshal(document1, &res) require.NoError(t, err) require.Equal(t, CosmosMsg{ - Stargate: &StargateMsg{ + Any: &AnyMsg{ TypeURL: "/cosmos.foo.v1beta.MsgBar", Value: expectedData, }, From 97bb4d812425c0b40abe35545a27655e1478d632 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 16 Nov 2023 13:24:44 +0100 Subject: [PATCH 3/3] Error if both any and stargate msg are provided --- types/msg.go | 6 ++++-- types/msg_test.go | 9 +++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/types/msg.go b/types/msg.go index d8ada04d1..7864ba61d 100644 --- a/types/msg.go +++ b/types/msg.go @@ -126,8 +126,10 @@ func (m *CosmosMsg) UnmarshalJSON(data []byte) error { return err } - // Use "Any" for both variants - if tmp.Any == nil && tmp.Stargate != nil { + if tmp.Any != nil && tmp.Stargate != nil { + return fmt.Errorf("invalid CosmosMsg: both 'any' and 'stargate' fields are set") + } else if tmp.Any == nil && tmp.Stargate != nil { + // Use "Any" for both variants tmp.Any = tmp.Stargate } diff --git a/types/msg_test.go b/types/msg_test.go index 5da14be4d..8aec492ea 100644 --- a/types/msg_test.go +++ b/types/msg_test.go @@ -104,6 +104,15 @@ func TestAnyMsgSerialization(t *testing.T) { serialized, err := json.Marshal(res) require.NoError(t, err) require.Equal(t, document2, serialized) + + // test providing both variants is rejected + document3 := []byte(`{ + "stargate":{"type_url":"/cosmos.foo.v1beta.MsgBar","value":"5yu/rQ+HrMcxH1zdga7P5hpGMLE="}, + "any":{"type_url":"/cosmos.foo.v1beta.MsgBar","value":"5yu/rQ+HrMcxH1zdga7P5hpGMLE="} + }`) + var res3 CosmosMsg + err = json.Unmarshal(document3, &res3) + require.Error(t, err) } func TestGovMsgVoteSerialization(t *testing.T) {