From b219c54c2d166cc645de7b933655e0cdb3f6981f Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Tue, 8 Dec 2020 10:27:08 +0100 Subject: [PATCH] Move and update codec.MarshalAny functions to codec.Marshaler interface (#8080) * Changelog update * Rename codec.MarshalAny * move codec.MarshalInterface to codec.Marshaler * fix tests * Update amino_codec for compliance with MarshalerInterface * update tests and comments * add tests * change order of args in UnmarshalInterface to a canonical one * uplift MarshalInterface to take ProtoMessage as an argument * wip * add nil check * make tests working * tests cleanup * add support for *JSON methods * Update changelog * linter fixes * fix test types * update evidence genesis_test * adding test * review updates Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- CHANGELOG.md | 24 ++-- codec/amino_codec.go | 46 +++++- codec/amino_codec_test.go | 121 ++-------------- codec/any.go | 44 ------ codec/any_test.go | 20 +-- codec/codec.go | 5 + codec/codec_common_test.go | 135 ++++++++++++++++++ codec/proto_codec.go | 73 +++++++++- codec/proto_codec_test.go | 105 ++------------ .../adr-019-protobuf-state-encoding.md | 19 ++- docs/core/encoding.md | 11 +- testutil/testdata/animal.go | 4 + x/auth/keeper/keeper.go | 18 +-- x/bank/exported/exported.go | 4 + x/bank/keeper/keeper.go | 15 +- x/evidence/exported/evidence.go | 3 + x/evidence/keeper/keeper.go | 15 +- x/evidence/types/genesis_test.go | 7 +- x/ibc/core/02-client/types/encoding.go | 18 +-- x/ibc/core/exported/client.go | 8 +- .../06-solomachine/types/consensus_state.go | 2 +- .../types/misbehaviour_handle.go | 2 +- .../06-solomachine/types/solomachine_test.go | 3 +- .../07-tendermint/types/client_state.go | 4 +- .../07-tendermint/types/client_state_test.go | 10 +- .../07-tendermint/types/upgrade.go | 4 +- x/slashing/keeper/keeper.go | 5 +- x/staking/types/msg_test.go | 8 +- x/upgrade/types/plan.go | 2 +- 29 files changed, 374 insertions(+), 361 deletions(-) delete mode 100644 codec/any.go create mode 100644 codec/codec_common_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 25a486f96f66..99d256e7b061 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,13 +51,20 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (version) [\#7848](https://github.com/cosmos/cosmos-sdk/pull/7848) [\#7941](https://github.com/cosmos/cosmos-sdk/pull/7941) `version --long` output now shows the list of build dependencies and replaced build dependencies. ### State Machine Breaking Changes - -* (x/upgrade) [\#7979](https://github.com/cosmos/cosmos-sdk/pull/7979) keeper pubkey storage serialization migration from bech32 to protobuf. +* (x/upgrade) [\#7979](https://github.com/cosmos/cosmos-sdk/pull/7979) keeper pubkey storage serialization migration from bech32 to protobuf. ### Bug Fixes * (crypto) [\#7966](https://github.com/cosmos/cosmos-sdk/issues/7966) `Bip44Params` `String()` function now correctly returns the absolute HD path by adding the `m/` prefix. + +### API Breaking + +* [\#8080](https://github.com/cosmos/cosmos-sdk/pull/8080) Updated the `codec.Marshaler` interface + * Moved `MarshalAny` and `UnmarshalAny` helper functions to `codec.Marshaler` and renamed to `MarshalInterface` and `UnmarshalInterface` respectively. These functions must take interface as a parameter (not a concrete type nor `Any` object). Underneath they use `Any` wrapping for correct protobuf serialization. + + + ## [v0.40.0-rc3](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.40.0-rc3) - 2020-11-06 ### Client Breaking @@ -74,7 +81,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Client Breaking * (x/upgrade) [#7697](https://github.com/cosmos/cosmos-sdk/pull/7697) Rename flag name "--time" to "--upgrade-time", "--info" to "--upgrade-info", to keep it consistent with help message. -* (x/auth) [#7788](https://github.com/cosmos/cosmos-sdk/pull/7788) Remove `tx auth` subcommands, all auth subcommands exist as `tx ` +* (x/auth) [#7788](https://github.com/cosmos/cosmos-sdk/pull/7788) Remove `tx auth` subcommands, all auth subcommands exist as `tx ` ### API Breaking @@ -93,6 +100,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * All outward facing APIs will now check that capability is not nil and name is not empty before performing any state-machine changes * `SetIndex` has been renamed to `InitializeIndex` + ### Features * (tx) [\#7688](https://github.com/cosmos/cosmos-sdk/pull/7688) Add a new Tx gRPC service with methods `Simulate` and `GetTx` (by hash). @@ -134,7 +142,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features * (modules) [\#7540](https://github.com/cosmos/cosmos-sdk/issues/7540) Protobuf service definitions can now be used for -packing `Msg`s in transactions as defined in [ADR 031](./docs/architecture/adr-031-msg-service.md). All modules now +packing `Msg`s in transactions as defined in [ADR 031](./docs/architecture/adr-031-msg-service.md). All modules now define a `Msg` protobuf service. * (codec) [\#7519](https://github.com/cosmos/cosmos-sdk/pull/7519) `InterfaceRegistry` now inherits `jsonpb.AnyResolver`, and has a `RegisterCustomTypeURL` method to support ADR 031 packing of `Any`s. `AnyResolver` is now a required parameter to `RejectUnknownFields`. * (baseapp) [\#7519](https://github.com/cosmos/cosmos-sdk/pull/7519) Add `ServiceMsgRouter` to BaseApp to handle routing of protobuf service `Msg`s. The two new types defined in ADR 031, `sdk.ServiceMsg` and `sdk.MsgRequest` are introduced with this router. @@ -738,7 +746,7 @@ generalized genesis accounts through the `GenesisAccount` interface. * (sdk) [\#4758](https://github.com/cosmos/cosmos-sdk/issues/4758) update `x/genaccounts` to match module spec * (simulation) [\#4824](https://github.com/cosmos/cosmos-sdk/issues/4824) `PrintAllInvariants` flag will print all failed invariants * (simulation) [\#4490](https://github.com/cosmos/cosmos-sdk/issues/4490) add `InitialBlockHeight` flag to resume a simulation from a given block - + * Support exporting the simulation stats to a given JSON file * (simulation) [\#4847](https://github.com/cosmos/cosmos-sdk/issues/4847), [\#4838](https://github.com/cosmos/cosmos-sdk/pull/4838) and [\#4869](https://github.com/cosmos/cosmos-sdk/pull/4869) `SimApp` and simulation refactors: * Implement `SimulationManager` for executing modules' simulation functionalities in a modularized way @@ -1052,7 +1060,7 @@ that error is that the account doesn't exist. * (simulation) PrintAllInvariants flag will print all failed invariants * (simulation) Add `InitialBlockHeight` flag to resume a simulation from a given block * (simulation) [\#4670](https://github.com/cosmos/cosmos-sdk/issues/4670) Update simulation statistics to JSON format - + - Support exporting the simulation stats to a given JSON file * [\#4775](https://github.com/cosmos/cosmos-sdk/issues/4775) Refactor CI config * Upgrade IAVL to v0.12.4 @@ -1658,9 +1666,9 @@ BREAKING CHANGES FEATURES * Gaia REST API - + * [\#2358](https://github.com/cosmos/cosmos-sdk/issues/2358) Add distribution module REST interface - + * Gaia CLI (`gaiacli`) * [\#3429](https://github.com/cosmos/cosmos-sdk/issues/3429) Support querying for all delegator distribution rewards. diff --git a/codec/amino_codec.go b/codec/amino_codec.go index 21b751e8d13d..3ba7a2feb9b7 100644 --- a/codec/amino_codec.go +++ b/codec/amino_codec.go @@ -1,6 +1,8 @@ package codec -import "github.com/gogo/protobuf/proto" +import ( + "github.com/gogo/protobuf/proto" +) // AminoCodec defines a codec that utilizes Codec for both binary and JSON // encoding. @@ -78,3 +80,45 @@ func (ac *AminoCodec) UnmarshalJSON(bz []byte, ptr proto.Message) error { func (ac *AminoCodec) MustUnmarshalJSON(bz []byte, ptr proto.Message) { ac.LegacyAmino.MustUnmarshalJSON(bz, ptr) } + +// MarshalInterface is a convenience function for amino marshaling interfaces. +// The `i` must be an interface. +// NOTE: to marshal a concrete type, you should use MarshalBinaryBare instead +func (ac *AminoCodec) MarshalInterface(i proto.Message) ([]byte, error) { + if err := assertNotNil(i); err != nil { + return nil, err + } + return ac.LegacyAmino.MarshalBinaryBare(i) +} + +// UnmarshalInterface is a convenience function for amino unmarshaling interfaces. +// `ptr` must be a pointer to an interface. +// NOTE: to unmarshal a concrete type, you should use UnmarshalBinaryBare instead +// +// Example: +// var x MyInterface +// err := cdc.UnmarshalInterface(bz, &x) +func (ac *AminoCodec) UnmarshalInterface(bz []byte, ptr interface{}) error { + return ac.LegacyAmino.UnmarshalBinaryBare(bz, ptr) +} + +// MarshalInterfaceJSON is a convenience function for amino marshaling interfaces. +// The `i` must be an interface. +// NOTE: to marshal a concrete type, you should use MarshalJSON instead +func (ac *AminoCodec) MarshalInterfaceJSON(i proto.Message) ([]byte, error) { + if err := assertNotNil(i); err != nil { + return nil, err + } + return ac.LegacyAmino.MarshalJSON(i) +} + +// UnmarshalInterfaceJSON is a convenience function for amino unmarshaling interfaces. +// `ptr` must be a pointer to an interface. +// NOTE: to unmarshal a concrete type, you should use UnmarshalJSON instead +// +// Example: +// var x MyInterface +// err := cdc.UnmarshalInterfaceJSON(bz, &x) +func (ac *AminoCodec) UnmarshalInterfaceJSON(bz []byte, ptr interface{}) error { + return ac.LegacyAmino.UnmarshalJSON(bz, ptr) +} diff --git a/codec/amino_codec_test.go b/codec/amino_codec_test.go index c36e7a990b88..d9ccdb0496ed 100644 --- a/codec/amino_codec_test.go +++ b/codec/amino_codec_test.go @@ -15,121 +15,26 @@ import ( func createTestCodec() *codec.LegacyAmino { cdc := codec.NewLegacyAmino() - cdc.RegisterInterface((*testdata.Animal)(nil), nil) - cdc.RegisterConcrete(testdata.Dog{}, "testdata/Dog", nil) - cdc.RegisterConcrete(testdata.Cat{}, "testdata/Cat", nil) + // NOTE: since we unmarshal interface using pointers, we need to register a pointer + // types here. + cdc.RegisterConcrete(&testdata.Dog{}, "testdata/Dog", nil) + cdc.RegisterConcrete(&testdata.Cat{}, "testdata/Cat", nil) return cdc } -func TestAminoCodec(t *testing.T) { - any, err := types.NewAnyWithValue(&testdata.Dog{Name: "rufus"}) - require.NoError(t, err) - - testCases := []struct { - name string - codec *codec.AminoCodec - input codec.ProtoMarshaler - recv codec.ProtoMarshaler - marshalErr bool - unmarshalErr bool - }{ - { - "valid encoding and decoding", - codec.NewAminoCodec(createTestCodec()), - &testdata.Dog{Name: "rufus"}, - &testdata.Dog{}, - false, - false, - }, - { - "invalid decode type", - codec.NewAminoCodec(createTestCodec()), - &testdata.Dog{Name: "rufus"}, - &testdata.Cat{}, - false, - true, - }, - { - "any marshaling", - codec.NewAminoCodec(createTestCodec()), - &testdata.HasAnimal{Animal: any}, - &testdata.HasAnimal{Animal: any}, - false, - false, - }, - } - - for _, tc := range testCases { - tc := tc - - t.Run(tc.name, func(t *testing.T) { - bz, err := tc.codec.MarshalBinaryBare(tc.input) - - if tc.marshalErr { - require.Error(t, err) - require.Panics(t, func() { tc.codec.MustMarshalBinaryBare(tc.input) }) - } else { - var bz2 []byte - require.NoError(t, err) - require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalBinaryBare(tc.input) }) - require.Equal(t, bz, bz2) - - err := tc.codec.UnmarshalBinaryBare(bz, tc.recv) - if tc.unmarshalErr { - require.Error(t, err) - require.Panics(t, func() { tc.codec.MustUnmarshalBinaryBare(bz, tc.recv) }) - } else { - require.NoError(t, err) - require.NotPanics(t, func() { tc.codec.MustUnmarshalBinaryBare(bz, tc.recv) }) - require.Equal(t, tc.input, tc.recv) - } - } +func TestAminoMarsharlInterface(t *testing.T) { + cdc := codec.NewAminoCodec(createTestCodec()) + m := interfaceMarshaler{cdc.MarshalInterface, cdc.UnmarshalInterface} + testInterfaceMarshaling(require.New(t), m, true) - bz, err = tc.codec.MarshalBinaryLengthPrefixed(tc.input) - if tc.marshalErr { - require.Error(t, err) - require.Panics(t, func() { tc.codec.MustMarshalBinaryLengthPrefixed(tc.input) }) - } else { - var bz2 []byte - require.NoError(t, err) - require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalBinaryLengthPrefixed(tc.input) }) - require.Equal(t, bz, bz2) - - err := tc.codec.UnmarshalBinaryLengthPrefixed(bz, tc.recv) - if tc.unmarshalErr { - require.Error(t, err) - require.Panics(t, func() { tc.codec.MustUnmarshalBinaryLengthPrefixed(bz, tc.recv) }) - } else { - require.NoError(t, err) - require.NotPanics(t, func() { tc.codec.MustUnmarshalBinaryLengthPrefixed(bz, tc.recv) }) - require.Equal(t, tc.input, tc.recv) - } - } + m = interfaceMarshaler{cdc.MarshalInterfaceJSON, cdc.UnmarshalInterfaceJSON} + testInterfaceMarshaling(require.New(t), m, false) +} - bz, err = tc.codec.MarshalJSON(tc.input) - if tc.marshalErr { - require.Error(t, err) - require.Panics(t, func() { tc.codec.MustMarshalJSON(tc.input) }) - } else { - var bz2 []byte - require.NoError(t, err) - require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalJSON(tc.input) }) - require.Equal(t, bz, bz2) - - err := tc.codec.UnmarshalJSON(bz, tc.recv) - if tc.unmarshalErr { - require.Error(t, err) - require.Panics(t, func() { tc.codec.MustUnmarshalJSON(bz, tc.recv) }) - } else { - require.NoError(t, err) - require.NotPanics(t, func() { tc.codec.MustUnmarshalJSON(bz, tc.recv) }) - require.Equal(t, tc.input, tc.recv) - } - } - }) - } +func TestAminoCodec(t *testing.T) { + testMarshaling(t, codec.NewAminoCodec(createTestCodec())) } func TestAminoCodecMarshalJSONIndent(t *testing.T) { diff --git a/codec/any.go b/codec/any.go deleted file mode 100644 index 075ad727e3e1..000000000000 --- a/codec/any.go +++ /dev/null @@ -1,44 +0,0 @@ -package codec - -import ( - "fmt" - - "github.com/gogo/protobuf/proto" - - "github.com/cosmos/cosmos-sdk/codec/types" -) - -// MarshalAny is a convenience function for packing the provided value in an -// Any and then proto marshaling it to bytes -func MarshalAny(m BinaryMarshaler, x interface{}) ([]byte, error) { - msg, ok := x.(proto.Message) - if !ok { - return nil, fmt.Errorf("can't proto marshal %T", x) - } - - any := &types.Any{} - err := any.Pack(msg) - if err != nil { - return nil, err - } - - return m.MarshalBinaryBare(any) -} - -// UnmarshalAny is a convenience function for proto unmarshaling an Any from -// bz and then unpacking it to the interface pointer passed in as iface using -// the provided AnyUnpacker or returning an error -// -// Ex: -// var x MyInterface -// err := UnmarshalAny(unpacker, &x, bz) -func UnmarshalAny(m BinaryMarshaler, iface interface{}, bz []byte) error { - any := &types.Any{} - - err := m.UnmarshalBinaryBare(bz, any) - if err != nil { - return err - } - - return m.UnpackAny(any, iface) -} diff --git a/codec/any_test.go b/codec/any_test.go index d9ea888c49fb..16e1b7b7788d 100644 --- a/codec/any_test.go +++ b/codec/any_test.go @@ -1,7 +1,6 @@ package codec_test import ( - "errors" "testing" "github.com/stretchr/testify/require" @@ -28,38 +27,29 @@ func TestMarshalAny(t *testing.T) { cdc := codec.NewProtoCodec(registry) kitty := &testdata.Cat{Moniker: "Kitty"} - bz, err := codec.MarshalAny(cdc, kitty) + bz, err := cdc.MarshalInterface(kitty) require.NoError(t, err) var animal testdata.Animal // empty registry should fail - err = codec.UnmarshalAny(cdc, &animal, bz) + err = cdc.UnmarshalInterface(bz, &animal) require.Error(t, err) // wrong type registration should fail registry.RegisterImplementations((*testdata.Animal)(nil), &testdata.Dog{}) - err = codec.UnmarshalAny(cdc, &animal, bz) + err = cdc.UnmarshalInterface(bz, &animal) require.Error(t, err) // should pass registry = NewTestInterfaceRegistry() cdc = codec.NewProtoCodec(registry) - err = codec.UnmarshalAny(cdc, &animal, bz) + err = cdc.UnmarshalInterface(bz, &animal) require.NoError(t, err) require.Equal(t, kitty, animal) // nil should fail registry = NewTestInterfaceRegistry() - err = codec.UnmarshalAny(cdc, nil, bz) + err = cdc.UnmarshalInterface(bz, nil) require.Error(t, err) } - -func TestMarshalAnyNonProtoErrors(t *testing.T) { - registry := types.NewInterfaceRegistry() - cdc := codec.NewProtoCodec(registry) - - _, err := codec.MarshalAny(cdc, 29) - require.Error(t, err) - require.Equal(t, err, errors.New("can't proto marshal int")) -} diff --git a/codec/codec.go b/codec/codec.go index 1cbc78b7fc0e..4746c58b6fae 100644 --- a/codec/codec.go +++ b/codec/codec.go @@ -32,12 +32,17 @@ type ( UnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) error MustUnmarshalBinaryLengthPrefixed(bz []byte, ptr ProtoMarshaler) + MarshalInterface(i proto.Message) ([]byte, error) + UnmarshalInterface(bz []byte, ptr interface{}) error + types.AnyUnpacker } JSONMarshaler interface { MarshalJSON(o proto.Message) ([]byte, error) MustMarshalJSON(o proto.Message) []byte + MarshalInterfaceJSON(i proto.Message) ([]byte, error) + UnmarshalInterfaceJSON(bz []byte, ptr interface{}) error UnmarshalJSON(bz []byte, ptr proto.Message) error MustUnmarshalJSON(bz []byte, ptr proto.Message) diff --git a/codec/codec_common_test.go b/codec/codec_common_test.go new file mode 100644 index 000000000000..12e9bd2224e1 --- /dev/null +++ b/codec/codec_common_test.go @@ -0,0 +1,135 @@ +package codec_test + +import ( + "testing" + + "github.com/gogo/protobuf/proto" + "github.com/stretchr/testify/require" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/testutil/testdata" +) + +type interfaceMarshaler struct { + marshal func(i proto.Message) ([]byte, error) + unmarshal func(bz []byte, ptr interface{}) error +} + +func testInterfaceMarshaling(require *require.Assertions, cdc interfaceMarshaler, isAminoBin bool) { + _, err := cdc.marshal(nil) + require.Error(err, "can't marshal a nil value") + + dog := &testdata.Dog{Name: "rufus"} + var dogI testdata.Animal = dog + bz, err := cdc.marshal(dogI) + require.NoError(err) + + var animal testdata.Animal + if isAminoBin { + require.PanicsWithValue("Unmarshal expects a pointer", func() { + cdc.unmarshal(bz, animal) + }) + } else { + err = cdc.unmarshal(bz, animal) + require.Error(err) + require.Contains(err.Error(), "expects a pointer") + } + require.NoError(cdc.unmarshal(bz, &animal)) + require.Equal(dog, animal) + + // Amino doesn't wrap into Any, so it doesn't need to register self type + if isAminoBin { + var dog2 testdata.Dog + require.NoError(cdc.unmarshal(bz, &dog2)) + require.Equal(*dog, dog2) + } + + var cat testdata.Cat + require.Error(cdc.unmarshal(bz, &cat)) +} + +type mustMarshaler struct { + marshal func(i codec.ProtoMarshaler) ([]byte, error) + mustMarshal func(i codec.ProtoMarshaler) []byte + unmarshal func(bz []byte, ptr codec.ProtoMarshaler) error + mustUnmarshal func(bz []byte, ptr codec.ProtoMarshaler) +} + +type testCase struct { + name string + input codec.ProtoMarshaler + recv codec.ProtoMarshaler + marshalErr bool + unmarshalErr bool +} + +func testMarshalingTestCase(require *require.Assertions, tc testCase, m mustMarshaler) { + bz, err := m.marshal(tc.input) + if tc.marshalErr { + require.Error(err) + require.Panics(func() { m.mustMarshal(tc.input) }) + } else { + var bz2 []byte + require.NoError(err) + require.NotPanics(func() { bz2 = m.mustMarshal(tc.input) }) + require.Equal(bz, bz2) + + err := m.unmarshal(bz, tc.recv) + if tc.unmarshalErr { + require.Error(err) + require.Panics(func() { m.mustUnmarshal(bz, tc.recv) }) + } else { + require.NoError(err) + require.NotPanics(func() { m.mustUnmarshal(bz, tc.recv) }) + require.Equal(tc.input, tc.recv) + } + } +} + +func testMarshaling(t *testing.T, cdc codec.Marshaler) { + any, err := types.NewAnyWithValue(&testdata.Dog{Name: "rufus"}) + require.NoError(t, err) + + testCases := []testCase{ + { + "valid encoding and decoding", + &testdata.Dog{Name: "rufus"}, + &testdata.Dog{}, + false, + false, + }, { + "invalid decode type", + &testdata.Dog{Name: "rufus"}, + &testdata.Cat{}, + false, + true, + }} + if _, ok := cdc.(*codec.AminoCodec); ok { + testCases = append(testCases, testCase{ + "any marshaling", + &testdata.HasAnimal{Animal: any}, + &testdata.HasAnimal{Animal: any}, + false, + false, + }) + } + + for _, tc := range testCases { + tc := tc + m1 := mustMarshaler{cdc.MarshalBinaryBare, cdc.MustMarshalBinaryBare, cdc.UnmarshalBinaryBare, cdc.MustUnmarshalBinaryBare} + m2 := mustMarshaler{cdc.MarshalBinaryLengthPrefixed, cdc.MustMarshalBinaryLengthPrefixed, cdc.UnmarshalBinaryLengthPrefixed, cdc.MustUnmarshalBinaryLengthPrefixed} + m3 := mustMarshaler{ + func(i codec.ProtoMarshaler) ([]byte, error) { return cdc.MarshalJSON(i) }, + func(i codec.ProtoMarshaler) []byte { return cdc.MustMarshalJSON(i) }, + func(bz []byte, ptr codec.ProtoMarshaler) error { return cdc.UnmarshalJSON(bz, ptr) }, + func(bz []byte, ptr codec.ProtoMarshaler) { cdc.MustUnmarshalJSON(bz, ptr) }} + + t.Run(tc.name+"_BinaryBare", + func(t *testing.T) { testMarshalingTestCase(require.New(t), tc, m1) }) + t.Run(tc.name+"_BinaryLengthPrefixed", + func(t *testing.T) { testMarshalingTestCase(require.New(t), tc, m2) }) + t.Run(tc.name+"_JSON", + func(t *testing.T) { testMarshalingTestCase(require.New(t), tc, m3) }) + } +} diff --git a/codec/proto_codec.go b/codec/proto_codec.go index e77409fe4829..38f60ba3ae30 100644 --- a/codec/proto_codec.go +++ b/codec/proto_codec.go @@ -2,13 +2,14 @@ package codec import ( "encoding/binary" + "errors" "fmt" "strings" - "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/gogo/protobuf/jsonpb" "github.com/gogo/protobuf/proto" + + "github.com/cosmos/cosmos-sdk/codec/types" ) // ProtoCodecMarshaler defines an interface for codecs that utilize Protobuf for both @@ -160,6 +161,67 @@ func (pc *ProtoCodec) MustUnmarshalJSON(bz []byte, ptr proto.Message) { } } +// MarshalInterface is a convenience function for proto marshalling interfaces. It packs +// the provided value, which must be an interface, in an Any and then marshals it to bytes. +// NOTE: to marshal a concrete type, you should use MarshalBinaryBare instead +func (pc *ProtoCodec) MarshalInterface(i proto.Message) ([]byte, error) { + if err := assertNotNil(i); err != nil { + return nil, err + } + any, err := types.NewAnyWithValue(i) + if err != nil { + return nil, err + } + + return pc.MarshalBinaryBare(any) +} + +// UnmarshalInterface is a convenience function for proto unmarshaling interfaces. It +// unmarshals an Any from bz bytes and then unpacks it to the `ptr`, which must +// be a pointer to a non empty interface with registered implementations. +// NOTE: to unmarshal a concrete type, you should use UnmarshalBinaryBare instead +// +// Example: +// var x MyInterface +// err := cdc.UnmarshalInterface(bz, &x) +func (pc *ProtoCodec) UnmarshalInterface(bz []byte, ptr interface{}) error { + any := &types.Any{} + err := pc.UnmarshalBinaryBare(bz, any) + if err != nil { + return err + } + + return pc.UnpackAny(any, ptr) +} + +// MarshalInterfaceJSON is a convenience function for proto marshalling interfaces. It +// packs the provided value in an Any and then marshals it to bytes. +// NOTE: to marshal a concrete type, you should use MarshalJSON instead +func (pc *ProtoCodec) MarshalInterfaceJSON(x proto.Message) ([]byte, error) { + any, err := types.NewAnyWithValue(x) + if err != nil { + return nil, err + } + return pc.MarshalJSON(any) +} + +// UnmarshalInterfaceJSON is a convenience function for proto unmarshaling interfaces. +// It unmarshals an Any from bz bytes and then unpacks it to the `iface`, which must +// be a pointer to a non empty interface, implementing proto.Message with registered implementations. +// NOTE: to unmarshal a concrete type, you should use UnmarshalJSON instead +// +// Example: +// var x MyInterface // must implement proto.Message +// err := cdc.UnmarshalInterfaceJSON(&x, bz) +func (pc *ProtoCodec) UnmarshalInterfaceJSON(bz []byte, iface interface{}) error { + any := &types.Any{} + err := pc.UnmarshalJSON(bz, any) + if err != nil { + return err + } + return pc.UnpackAny(any, iface) +} + // UnpackAny implements AnyUnpacker.UnpackAny method, // it unpacks the value in any to the interface pointer passed in as // iface. @@ -170,3 +232,10 @@ func (pc *ProtoCodec) UnpackAny(any *types.Any, iface interface{}) error { func (pc *ProtoCodec) InterfaceRegistry() types.InterfaceRegistry { return pc.interfaceRegistry } + +func assertNotNil(i interface{}) error { + if i == nil { + return errors.New("can't marshal value") + } + return nil +} diff --git a/codec/proto_codec_test.go b/codec/proto_codec_test.go index 734bf1320ba2..706d025d5994 100644 --- a/codec/proto_codec_test.go +++ b/codec/proto_codec_test.go @@ -24,102 +24,17 @@ func createTestInterfaceRegistry() types.InterfaceRegistry { return interfaceRegistry } -func TestProtoCodec(t *testing.T) { - testCases := []struct { - name string - codec codec.Marshaler - input codec.ProtoMarshaler - recv codec.ProtoMarshaler - marshalErr bool - unmarshalErr bool - }{ - { - "valid encoding and decoding", - codec.NewProtoCodec(createTestInterfaceRegistry()), - &testdata.Dog{Name: "rufus"}, - &testdata.Dog{}, - false, - false, - }, - { - "invalid decode type", - codec.NewProtoCodec(createTestInterfaceRegistry()), - &testdata.Dog{Name: "rufus"}, - &testdata.Cat{}, - false, - true, - }, - } - - for _, tc := range testCases { - tc := tc - - t.Run(tc.name, func(t *testing.T) { - bz, err := tc.codec.MarshalBinaryBare(tc.input) - - if tc.marshalErr { - require.Error(t, err) - require.Panics(t, func() { tc.codec.MustMarshalBinaryBare(tc.input) }) - } else { - var bz2 []byte - require.NoError(t, err) - require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalBinaryBare(tc.input) }) - require.Equal(t, bz, bz2) - - err := tc.codec.UnmarshalBinaryBare(bz, tc.recv) - if tc.unmarshalErr { - require.Error(t, err) - require.Panics(t, func() { tc.codec.MustUnmarshalBinaryBare(bz, tc.recv) }) - } else { - require.NoError(t, err) - require.NotPanics(t, func() { tc.codec.MustUnmarshalBinaryBare(bz, tc.recv) }) - require.Equal(t, tc.input, tc.recv) - } - } - - bz, err = tc.codec.MarshalBinaryLengthPrefixed(tc.input) - if tc.marshalErr { - require.Error(t, err) - require.Panics(t, func() { tc.codec.MustMarshalBinaryLengthPrefixed(tc.input) }) - } else { - var bz2 []byte - require.NoError(t, err) - require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalBinaryLengthPrefixed(tc.input) }) - require.Equal(t, bz, bz2) - - err := tc.codec.UnmarshalBinaryLengthPrefixed(bz, tc.recv) - if tc.unmarshalErr { - require.Error(t, err) - require.Panics(t, func() { tc.codec.MustUnmarshalBinaryLengthPrefixed(bz, tc.recv) }) - } else { - require.NoError(t, err) - require.NotPanics(t, func() { tc.codec.MustUnmarshalBinaryLengthPrefixed(bz, tc.recv) }) - require.Equal(t, tc.input, tc.recv) - } - } +func TestProtoMarsharlInterface(t *testing.T) { + cdc := codec.NewProtoCodec(createTestInterfaceRegistry()) + m := interfaceMarshaler{cdc.MarshalInterface, cdc.UnmarshalInterface} + testInterfaceMarshaling(require.New(t), m, false) + m = interfaceMarshaler{cdc.MarshalInterfaceJSON, cdc.UnmarshalInterfaceJSON} + testInterfaceMarshaling(require.New(t), m, false) +} - bz, err = tc.codec.MarshalJSON(tc.input) - if tc.marshalErr { - require.Error(t, err) - require.Panics(t, func() { tc.codec.MustMarshalJSON(tc.input) }) - } else { - var bz2 []byte - require.NoError(t, err) - require.NotPanics(t, func() { bz2 = tc.codec.MustMarshalJSON(tc.input) }) - require.Equal(t, bz, bz2) - - err := tc.codec.UnmarshalJSON(bz, tc.recv) - if tc.unmarshalErr { - require.Error(t, err) - require.Panics(t, func() { tc.codec.MustUnmarshalJSON(bz, tc.recv) }) - } else { - require.NoError(t, err) - require.NotPanics(t, func() { tc.codec.MustUnmarshalJSON(bz, tc.recv) }) - require.Equal(t, tc.input, tc.recv) - } - } - }) - } +func TestProtoCodec(t *testing.T) { + cdc := codec.NewProtoCodec(createTestInterfaceRegistry()) + testMarshaling(t, cdc) } type lyingProtoMarshaler struct { diff --git a/docs/architecture/adr-019-protobuf-state-encoding.md b/docs/architecture/adr-019-protobuf-state-encoding.md index aae56e781484..2a4d8b046258 100644 --- a/docs/architecture/adr-019-protobuf-state-encoding.md +++ b/docs/architecture/adr-019-protobuf-state-encoding.md @@ -6,6 +6,7 @@ - 2020 Feb 24: Updates to handle messages with interface fields - 2020 Apr 27: Convert usages of `oneof` for interfaces to `Any` - 2020 May 15: Describe `cosmos_proto` extensions and amino compatibility +- 2020 Dec 4: Move and rename `MarshalAny` and `UnmarshalAny` into the `codec.Marshaler` interface. ## Status @@ -221,23 +222,20 @@ every module that implements it in order to populate the `InterfaceRegistry`. ### Using `Any` to encode state -The SDK will provide support methods `MarshalAny` and `UnmarshalAny` to allow -easy encoding of state to `Any` in `Codec` implementations. Ex: +The SDK will provide support methods `MarshalInterface` and `UnmarshalInterface` to hide a complexity of wrapping interface types into `Any` and allow easy serialization. ```go import "github.com/cosmos/cosmos-sdk/codec" -func (c *Codec) MarshalEvidence(evidenceI eviexported.Evidence) ([]byte, error) { - return codec.MarshalAny(evidenceI) +// note: eviexported.Evidence is an interface type +func MarshalEvidence(cdc codec.BinaryMarshaler, e eviexported.Evidence) ([]byte, error) { + return cdc.MarshalInterface(e) } -func (c *Codec) UnmarshalEvidence(bz []byte) (eviexported.Evidence, error) { +func UnmarshalEvidence(cdc codec.BinaryMarshaler, bz []byte) (eviexported.Evidence, error) { var evi eviexported.Evidence - err := codec.UnmarshalAny(c.interfaceContext, &evi, bz) - if err != nil { - return nil, err - } - return evi, nil + err := cdc.UnmarshalInterface(&evi, bz) + return err, nil } ``` @@ -375,4 +373,3 @@ seamless. 1. https://github.com/cosmos/cosmos-sdk/issues/4977 2. https://github.com/cosmos/cosmos-sdk/issues/5444 - diff --git a/docs/core/encoding.md b/docs/core/encoding.md index 69059b39c6a0..5f1c0c2578d8 100644 --- a/docs/core/encoding.md +++ b/docs/core/encoding.md @@ -82,7 +82,7 @@ Protobuf types can be defined to encode: - [`Msg`s](../building-modules/messages-and-queries.md#messages) - [Query services](../building-modules/query-services.md) - [genesis](../building-modules/genesis.md) - + **Naming and conventions** We encourage developers to follow industry guidelines: [Protocol Buffers style guide](https://developers.google.com/protocol-buffers/docs/style) @@ -95,11 +95,9 @@ may simply migrate any existing types that are encoded and persisted via their concrete Amino codec to Protobuf (see 1. for further guidelines) and accept a `Marshaler` as the codec which is implemented via the `ProtoCodec` without any further customization. -However, if modules are to handle type interfaces, module-level .proto files should define messages which encode interfaces -using [`google.protobuf.Any`](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). +However, if a module type composes an interface, it must wrap it in the `skd.Any` (from `/types` package) type. To do that, a module-level .proto file must use [`google.protobuf.Any`](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto) for respective message type interface types. -For example, we can define `MsgSubmitEvidence` as follows where `Evidence` is -an interface: +For example, in the `x/evidence` module defines an `Evidence` interface, which is used by the `MsgSubmitEvidence`. The structure definition must use `sdk.Any` to wrap the evidence file. In the proto file we define it as follows: ```protobuf // proto/cosmos/evidence/v1beta1/tx.proto @@ -110,8 +108,7 @@ message MsgSubmitEvidence { } ``` -The SDK provides support methods `MarshalAny` and `UnmarshalAny` to allow -easy encoding of state to `Any`. +The SDK `codec.Marshaler` interface provides support methods `MarshalInterface` and `UnmarshalInterface` to easy encoding of state to `Any`. Module should register interfaces using `InterfaceRegistry` which provides a mechanism for registering interfaces: `RegisterInterface(protoName string, iface interface{})` and implementations: `RegisterImplementations(iface interface{}, impls ...proto.Message)` that can be safely unpacked from Any, similarly to type registration with Amino: diff --git a/testutil/testdata/animal.go b/testutil/testdata/animal.go index aa9344a38fe8..96981a40b9b4 100644 --- a/testutil/testdata/animal.go +++ b/testutil/testdata/animal.go @@ -6,10 +6,14 @@ package testdata import ( "fmt" + "github.com/gogo/protobuf/proto" + "github.com/cosmos/cosmos-sdk/codec/types" ) type Animal interface { + proto.Message + Greet() string } diff --git a/x/auth/keeper/keeper.go b/x/auth/keeper/keeper.go index abc1cdabfc29..92d9f9b76ecb 100644 --- a/x/auth/keeper/keeper.go +++ b/x/auth/keeper/keeper.go @@ -215,23 +215,17 @@ func (ak AccountKeeper) decodeAccount(bz []byte) types.AccountI { return acc } -// MarshalAccount marshals an Account interface. If the given type implements -// the Marshaler interface, it is treated as a Proto-defined message and -// serialized that way. Otherwise, it falls back on the internal Amino codec. -func (ak AccountKeeper) MarshalAccount(accountI types.AccountI) ([]byte, error) { - return codec.MarshalAny(ak.cdc, accountI) +// MarshalAccount protobuf serializes an Account interface +func (ak AccountKeeper) MarshalAccount(accountI types.AccountI) ([]byte, error) { // nolint:interfacer + return ak.cdc.MarshalInterface(accountI) } // UnmarshalAccount returns an Account interface from raw encoded account -// bytes of a Proto-based Account type. An error is returned upon decoding -// failure. +// bytes of a Proto-based Account type func (ak AccountKeeper) UnmarshalAccount(bz []byte) (types.AccountI, error) { var acc types.AccountI - if err := codec.UnmarshalAny(ak.cdc, &acc, bz); err != nil { - return nil, err - } - - return acc, nil + return acc, ak.cdc.UnmarshalInterface(bz, &acc) } +// GetCodec return codec.Marshaler object used by the keeper func (ak AccountKeeper) GetCodec() codec.BinaryMarshaler { return ak.cdc } diff --git a/x/bank/exported/exported.go b/x/bank/exported/exported.go index cee67909f536..ae13d99d5a87 100644 --- a/x/bank/exported/exported.go +++ b/x/bank/exported/exported.go @@ -1,6 +1,8 @@ package exported import ( + "github.com/gogo/protobuf/proto" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -14,6 +16,8 @@ type GenesisBalance interface { // SupplyI defines an inflationary supply interface for modules that handle // token supply. type SupplyI interface { + proto.Message + GetTotal() sdk.Coins SetTotal(total sdk.Coins) diff --git a/x/bank/keeper/keeper.go b/x/bank/keeper/keeper.go index 7661c1d31573..016537221f89 100644 --- a/x/bank/keeper/keeper.go +++ b/x/bank/keeper/keeper.go @@ -403,21 +403,14 @@ func (k BaseKeeper) trackUndelegation(ctx sdk.Context, addr sdk.AccAddress, amt return nil } -// MarshalSupply marshals a Supply interface. If the given type implements -// the Marshaler interface, it is treated as a Proto-defined message and -// serialized that way. Otherwise, it falls back on the internal Amino codec. +// MarshalSupply protobuf serializes a Supply interface func (k BaseKeeper) MarshalSupply(supplyI exported.SupplyI) ([]byte, error) { - return codec.MarshalAny(k.cdc, supplyI) + return k.cdc.MarshalInterface(supplyI) } // UnmarshalSupply returns a Supply interface from raw encoded supply -// bytes of a Proto-based Supply type. An error is returned upon decoding -// failure. +// bytes of a Proto-based Supply type func (k BaseKeeper) UnmarshalSupply(bz []byte) (exported.SupplyI, error) { var evi exported.SupplyI - if err := codec.UnmarshalAny(k.cdc, &evi, bz); err != nil { - return nil, err - } - - return evi, nil + return evi, k.cdc.UnmarshalInterface(bz, &evi) } diff --git a/x/evidence/exported/evidence.go b/x/evidence/exported/evidence.go index 1be263a8703b..8cf00fa6a93c 100644 --- a/x/evidence/exported/evidence.go +++ b/x/evidence/exported/evidence.go @@ -1,6 +1,7 @@ package exported import ( + "github.com/gogo/protobuf/proto" tmbytes "github.com/tendermint/tendermint/libs/bytes" sdk "github.com/cosmos/cosmos-sdk/types" @@ -9,6 +10,8 @@ import ( // Evidence defines the contract which concrete evidence types of misbehavior // must implement. type Evidence interface { + proto.Message + Route() string Type() string String() string diff --git a/x/evidence/keeper/keeper.go b/x/evidence/keeper/keeper.go index 8a2bfa686834..aa660bcff13b 100644 --- a/x/evidence/keeper/keeper.go +++ b/x/evidence/keeper/keeper.go @@ -167,21 +167,14 @@ func (k Keeper) MustMarshalEvidence(evidence exported.Evidence) []byte { return bz } -// MarshalEvidence marshals an Evidence interface. If the given type implements -// the Marshaler interface, it is treated as a Proto-defined message and -// serialized that way. Otherwise, it falls back on the internal Amino codec. +// MarshalEvidence protobuf serializes an Evidence interface func (k Keeper) MarshalEvidence(evidenceI exported.Evidence) ([]byte, error) { - return codec.MarshalAny(k.cdc, evidenceI) + return k.cdc.MarshalInterface(evidenceI) } // UnmarshalEvidence returns an Evidence interface from raw encoded evidence -// bytes of a Proto-based Evidence type. An error is returned upon decoding -// failure. +// bytes of a Proto-based Evidence type func (k Keeper) UnmarshalEvidence(bz []byte) (exported.Evidence, error) { var evi exported.Evidence - if err := codec.UnmarshalAny(k.cdc, &evi, bz); err != nil { - return nil, err - } - - return evi, nil + return evi, k.cdc.UnmarshalInterface(bz, &evi) } diff --git a/x/evidence/types/genesis_test.go b/x/evidence/types/genesis_test.go index d1cd030b9636..339696c82e1f 100644 --- a/x/evidence/types/genesis_test.go +++ b/x/evidence/types/genesis_test.go @@ -32,11 +32,11 @@ func TestNewGenesisState(t *testing.T) { expPass bool }{ { - "cannot proto marshal", + "can proto marshal", func() { evidence = []exported.Evidence{&TestEvidence{}} }, - false, + true, }, } @@ -175,6 +175,9 @@ func (*TestEvidence) String() string { return "test-string" } +func (*TestEvidence) ProtoMessage() {} +func (*TestEvidence) Reset() {} + func (*TestEvidence) Hash() tmbytes.HexBytes { return tmbytes.HexBytes([]byte("test-hash")) } diff --git a/x/ibc/core/02-client/types/encoding.go b/x/ibc/core/02-client/types/encoding.go index 1a56ad9596bd..a912b13abd64 100644 --- a/x/ibc/core/02-client/types/encoding.go +++ b/x/ibc/core/02-client/types/encoding.go @@ -29,11 +29,9 @@ func MustMarshalClientState(cdc codec.BinaryMarshaler, clientState exported.Clie return bz } -// MarshalClientState marshals an ClientState interface. If the given type implements -// the Marshaler interface, it is treated as a Proto-defined message and -// serialized that way. +// MarshalClientState protobuf serializes an ClientState interface func MarshalClientState(cdc codec.BinaryMarshaler, clientStateI exported.ClientState) ([]byte, error) { - return codec.MarshalAny(cdc, clientStateI) + return cdc.MarshalInterface(clientStateI) } // UnmarshalClientState returns an ClientState interface from raw encoded clientState @@ -41,7 +39,7 @@ func MarshalClientState(cdc codec.BinaryMarshaler, clientStateI exported.ClientS // failure. func UnmarshalClientState(cdc codec.BinaryMarshaler, bz []byte) (exported.ClientState, error) { var clientState exported.ClientState - if err := codec.UnmarshalAny(cdc, &clientState, bz); err != nil { + if err := cdc.UnmarshalInterface(bz, &clientState); err != nil { return nil, err } @@ -70,11 +68,9 @@ func MustMarshalConsensusState(cdc codec.BinaryMarshaler, consensusState exporte return bz } -// MarshalConsensusState marshals an ConsensusState interface. If the given type implements -// the Marshaler interface, it is treated as a Proto-defined message and -// serialized that way. -func MarshalConsensusState(cdc codec.BinaryMarshaler, consensusStateI exported.ConsensusState) ([]byte, error) { - return codec.MarshalAny(cdc, consensusStateI) +// MarshalConsensusState protobuf serializes an ConsensusState interface +func MarshalConsensusState(cdc codec.BinaryMarshaler, cs exported.ConsensusState) ([]byte, error) { + return cdc.MarshalInterface(cs) } // UnmarshalConsensusState returns an ConsensusState interface from raw encoded clientState @@ -82,7 +78,7 @@ func MarshalConsensusState(cdc codec.BinaryMarshaler, consensusStateI exported.C // failure. func UnmarshalConsensusState(cdc codec.BinaryMarshaler, bz []byte) (exported.ConsensusState, error) { var consensusState exported.ConsensusState - if err := codec.UnmarshalAny(cdc, &consensusState, bz); err != nil { + if err := cdc.UnmarshalInterface(bz, &consensusState); err != nil { return nil, err } diff --git a/x/ibc/core/exported/client.go b/x/ibc/core/exported/client.go index 0fe26d9f55d3..0bdb5e51bf79 100644 --- a/x/ibc/core/exported/client.go +++ b/x/ibc/core/exported/client.go @@ -2,10 +2,10 @@ package exported import ( ics23 "github.com/confio/ics23/go" - - sdk "github.com/cosmos/cosmos-sdk/types" + proto "github.com/gogo/protobuf/proto" "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" ) const ( @@ -25,6 +25,8 @@ const ( // ClientState defines the required common functions for light clients. type ClientState interface { + proto.Message + ClientType() string GetLatestHeight() Height IsFrozen() bool @@ -160,6 +162,8 @@ type ClientState interface { // ConsensusState is the state of the consensus process type ConsensusState interface { + proto.Message + ClientType() string // Consensus kind // GetRoot returns the commitment root of the consensus state, diff --git a/x/ibc/light-clients/06-solomachine/types/consensus_state.go b/x/ibc/light-clients/06-solomachine/types/consensus_state.go index 1cc95caf08e3..7d6d09cd046b 100644 --- a/x/ibc/light-clients/06-solomachine/types/consensus_state.go +++ b/x/ibc/light-clients/06-solomachine/types/consensus_state.go @@ -9,7 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/core/exported" ) -var _ exported.ConsensusState = ConsensusState{} +var _ exported.ConsensusState = &ConsensusState{} // ClientType returns Solo Machine type. func (ConsensusState) ClientType() string { diff --git a/x/ibc/light-clients/06-solomachine/types/misbehaviour_handle.go b/x/ibc/light-clients/06-solomachine/types/misbehaviour_handle.go index 83335ec59f07..ce5d6351c48f 100644 --- a/x/ibc/light-clients/06-solomachine/types/misbehaviour_handle.go +++ b/x/ibc/light-clients/06-solomachine/types/misbehaviour_handle.go @@ -47,7 +47,7 @@ func (cs ClientState) CheckMisbehaviourAndUpdateState( } cs.FrozenSequence = soloMisbehaviour.Sequence - return cs, nil + return &cs, nil } // verifySignatureAndData verifies that the currently registered public key has signed diff --git a/x/ibc/light-clients/06-solomachine/types/solomachine_test.go b/x/ibc/light-clients/06-solomachine/types/solomachine_test.go index 0d9e72641193..50555e45145a 100644 --- a/x/ibc/light-clients/06-solomachine/types/solomachine_test.go +++ b/x/ibc/light-clients/06-solomachine/types/solomachine_test.go @@ -6,7 +6,6 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" - "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" @@ -53,7 +52,7 @@ func (suite *SoloMachineTestSuite) GetSequenceFromStore() uint64 { suite.Require().NotNil(bz) var clientState exported.ClientState - err := codec.UnmarshalAny(suite.chainA.Codec, &clientState, bz) + err := suite.chainA.Codec.UnmarshalInterface(bz, &clientState) suite.Require().NoError(err) return clientState.GetLatestHeight().GetRevisionHeight() } diff --git a/x/ibc/light-clients/07-tendermint/types/client_state.go b/x/ibc/light-clients/07-tendermint/types/client_state.go index 8425b7419bfd..c2bb5239f5f5 100644 --- a/x/ibc/light-clients/07-tendermint/types/client_state.go +++ b/x/ibc/light-clients/07-tendermint/types/client_state.go @@ -183,7 +183,7 @@ func (cs ClientState) VerifyClientState( return sdkerrors.Wrapf(clienttypes.ErrInvalidClient, "invalid client type %T, expected %T", clientState, &ClientState{}) } - bz, err := codec.MarshalAny(cdc, clientState) + bz, err := cdc.MarshalInterface(clientState) if err != nil { return err } @@ -223,7 +223,7 @@ func (cs ClientState) VerifyClientConsensusState( return sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "invalid consensus type %T, expected %T", consensusState, &ConsensusState{}) } - bz, err := codec.MarshalAny(cdc, consensusState) + bz, err := cdc.MarshalInterface(consensusState) if err != nil { return err } diff --git a/x/ibc/light-clients/07-tendermint/types/client_state_test.go b/x/ibc/light-clients/07-tendermint/types/client_state_test.go index d342c6f74884..744b4729f6ef 100644 --- a/x/ibc/light-clients/07-tendermint/types/client_state_test.go +++ b/x/ibc/light-clients/07-tendermint/types/client_state_test.go @@ -139,7 +139,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { testCases := []struct { name string clientState *types.ClientState - consensusState types.ConsensusState + consensusState *types.ConsensusState prefix commitmenttypes.MerklePrefix proof []byte expPass bool @@ -157,7 +157,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { { name: "ApplyPrefix failed", clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - consensusState: types.ConsensusState{ + consensusState: &types.ConsensusState{ Root: commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), }, prefix: commitmenttypes.MerklePrefix{}, @@ -166,7 +166,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { { name: "latest client height < height", clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - consensusState: types.ConsensusState{ + consensusState: &types.ConsensusState{ Root: commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), }, prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), @@ -175,7 +175,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { { name: "client is frozen", clientState: &types.ClientState{LatestHeight: height, FrozenHeight: clienttypes.NewHeight(height.RevisionNumber, height.RevisionHeight-1)}, - consensusState: types.ConsensusState{ + consensusState: &types.ConsensusState{ Root: commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), }, prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")), @@ -184,7 +184,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { { name: "proof verification failed", clientState: types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), upgradePath, false, false), - consensusState: types.ConsensusState{ + consensusState: &types.ConsensusState{ Root: commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), NextValidatorsHash: suite.valsHash, }, diff --git a/x/ibc/light-clients/07-tendermint/types/upgrade.go b/x/ibc/light-clients/07-tendermint/types/upgrade.go index 074ccc2db8f1..4ccf8b9ebb77 100644 --- a/x/ibc/light-clients/07-tendermint/types/upgrade.go +++ b/x/ibc/light-clients/07-tendermint/types/upgrade.go @@ -76,7 +76,7 @@ func (cs ClientState) VerifyUpgradeAndUpdateState( } // Verify client proof - bz, err := codec.MarshalAny(cdc, upgradedClient) + bz, err := cdc.MarshalInterface(upgradedClient) if err != nil { return nil, nil, sdkerrors.Wrapf(clienttypes.ErrInvalidClient, "could not marshal client state: %v", err) } @@ -87,7 +87,7 @@ func (cs ClientState) VerifyUpgradeAndUpdateState( } // Verify consensus state proof - bz, err = codec.MarshalAny(cdc, upgradedConsState) + bz, err = cdc.MarshalInterface(upgradedConsState) if err != nil { return nil, nil, sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "could not marshal consensus state: %v", err) } diff --git a/x/slashing/keeper/keeper.go b/x/slashing/keeper/keeper.go index cbed27e9a195..69a5e25b4a4c 100644 --- a/x/slashing/keeper/keeper.go +++ b/x/slashing/keeper/keeper.go @@ -41,7 +41,7 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { // AddPubkey sets a address-pubkey relation func (k Keeper) AddPubkey(ctx sdk.Context, pubkey cryptotypes.PubKey) error { - bz, err := codec.MarshalAny(k.cdc, pubkey) + bz, err := k.cdc.MarshalInterface(pubkey) if err != nil { return err } @@ -59,8 +59,7 @@ func (k Keeper) GetPubkey(ctx sdk.Context, a cryptotypes.Address) (cryptotypes.P return nil, fmt.Errorf("address %s not found", sdk.ConsAddress(a)) } var pk cryptotypes.PubKey - err := codec.UnmarshalAny(k.cdc, &pk, bz) - return pk, err + return pk, k.cdc.UnmarshalInterface(bz, &pk) } // Slash attempts to slash a validator. The slash is delegated to the staking diff --git a/x/staking/types/msg_test.go b/x/staking/types/msg_test.go index 3b858a64ddc3..493434527c94 100644 --- a/x/staking/types/msg_test.go +++ b/x/staking/types/msg_test.go @@ -27,10 +27,10 @@ func TestMsgDecode(t *testing.T) { // firstly we start testing the pubkey serialization - pk1bz, err := codec.MarshalAny(cdc, pk1) + pk1bz, err := cdc.MarshalInterface(pk1) require.NoError(t, err) var pkUnmarshaled cryptotypes.PubKey - err = codec.UnmarshalAny(cdc, &pkUnmarshaled, pk1bz) + err = cdc.UnmarshalInterface(pk1bz, &pkUnmarshaled) require.NoError(t, err) require.True(t, pk1.Equals(pkUnmarshaled.(*ed25519.PubKey))) @@ -39,11 +39,11 @@ func TestMsgDecode(t *testing.T) { commission1 := types.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()) msg, err := types.NewMsgCreateValidator(valAddr1, pk1, coinPos, types.Description{}, commission1, sdk.OneInt()) require.NoError(t, err) - msgSerialized, err := codec.MarshalAny(cdc, msg) + msgSerialized, err := cdc.MarshalInterface(msg) require.NoError(t, err) var msgUnmarshaled sdk.Msg - err = codec.UnmarshalAny(cdc, &msgUnmarshaled, msgSerialized) + err = cdc.UnmarshalInterface(msgSerialized, &msgUnmarshaled) require.NoError(t, err) msg2, ok := msgUnmarshaled.(*types.MsgCreateValidator) require.True(t, ok) diff --git a/x/upgrade/types/plan.go b/x/upgrade/types/plan.go index f9f9db15e90d..16feec31d7a7 100644 --- a/x/upgrade/types/plan.go +++ b/x/upgrade/types/plan.go @@ -23,7 +23,7 @@ func (p Plan) String() string { if err != nil { upgradedClientStr = "no upgraded client provided" } else { - upgradedClientStr = fmt.Sprintf("%s", upgradedClient) + upgradedClientStr = upgradedClient.String() } return fmt.Sprintf(`Upgrade Plan Name: %s