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>
This commit is contained in:
parent
da6b7f7755
commit
b219c54c2d
24
CHANGELOG.md
24
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 <subcommand>`
|
||||
* (x/auth) [#7788](https://github.com/cosmos/cosmos-sdk/pull/7788) Remove `tx auth` subcommands, all auth subcommands exist as `tx <subcommand>`
|
||||
|
||||
### 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.
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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 TestAminoMarsharlInterface(t *testing.T) {
|
||||
cdc := codec.NewAminoCodec(createTestCodec())
|
||||
m := interfaceMarshaler{cdc.MarshalInterface, cdc.UnmarshalInterface}
|
||||
testInterfaceMarshaling(require.New(t), m, true)
|
||||
|
||||
m = interfaceMarshaler{cdc.MarshalInterfaceJSON, cdc.UnmarshalInterfaceJSON}
|
||||
testInterfaceMarshaling(require.New(t), m, false)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
testMarshaling(t, codec.NewAminoCodec(createTestCodec()))
|
||||
}
|
||||
|
||||
func TestAminoCodecMarshalJSONIndent(t *testing.T) {
|
||||
|
||||
44
codec/any.go
44
codec/any.go
@ -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)
|
||||
}
|
||||
@ -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"))
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
135
codec/codec_common_test.go
Normal file
135
codec/codec_common_test.go
Normal file
@ -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) })
|
||||
}
|
||||
}
|
||||
@ -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 <nil> value")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -24,102 +24,17 @@ func createTestInterfaceRegistry() types.InterfaceRegistry {
|
||||
return interfaceRegistry
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
cdc := codec.NewProtoCodec(createTestInterfaceRegistry())
|
||||
testMarshaling(t, cdc)
|
||||
}
|
||||
|
||||
type lyingProtoMarshaler struct {
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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:
|
||||
|
||||
|
||||
4
testutil/testdata/animal.go
vendored
4
testutil/testdata/animal.go
vendored
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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 }
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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"))
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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()
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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,
|
||||
},
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user