Skip to content

Commit

Permalink
feat(codec)!: add get signers to codec + merged proto registry to Int…
Browse files Browse the repository at this point in the history
…erfaceRegistry (#15600)

Co-authored-by: Matt Kocubinski <[email protected]>
  • Loading branch information
aaronc and kocubinski authored Mar 31, 2023
1 parent cdf6471 commit 9332942
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 90 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (crypto) [#15070](https://github.com/cosmos/cosmos-sdk/pull/15070) `GenerateFromPassword` and `Cost` from `bcrypt.go` now take a `uint32` instead of a `int` type.
* (x/capability) [#15344](https://github.com/cosmos/cosmos-sdk/pull/15344) Capability module was removed and is now housed in [IBC-GO](https://github.com/cosmos/ibc-go).
* [#15299](https://github.com/cosmos/cosmos-sdk/pull/15299) remove `StdTx` transaction and signing APIs. No SDK version has actually supported `StdTx` since before Stargate.
* [#15600](https://github.com/cosmos/cosmos-sdk/pull/15600) add support for getting signers to `codec.Codec` and protoregistry support to `InterfaceRegistry`:
* `Codec` is now a private interface and has the methods `InterfaceRegistry`, `GetMsgAnySigners`, `GetMsgV1Signers`, and `GetMsgV2Signers` which will fail when using `AminoCodec`.
All implementations of `Codec` by other users must now embed an official implementation from the `codec` package.
* `InterfaceRegistry` is now a private interface and implements `protodesc.Resolver` plus the `RangeFiles` method
All implementations of `InterfaceRegistry` by other users must now embed the official implementation.
* `AminoCodec` is marked as deprecated.

### Client Breaking Changes

Expand Down
37 changes: 1 addition & 36 deletions client/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"reflect"
"strconv"

proto "github.com/cosmos/gogoproto/proto"
"google.golang.org/grpc/encoding"

"github.com/cosmos/cosmos-sdk/codec"
Expand All @@ -29,7 +28,7 @@ var _ gogogrpc.ClientConn = Context{}
// fallBackCodec is used by Context in case Codec is not set.
// it can process every gRPC type, except the ones which contain
// interfaces in their types.
var fallBackCodec = codec.NewProtoCodec(failingInterfaceRegistry{})
var fallBackCodec = codec.NewProtoCodec(types.NewInterfaceRegistry())

// Invoke implements the grpc ClientConn.Invoke method
func (ctx Context) Invoke(grpcCtx gocontext.Context, method string, req, reply interface{}, opts ...grpc.CallOption) (err error) {
Expand Down Expand Up @@ -144,40 +143,6 @@ func (ctx Context) gRPCCodec() encoding.Codec {
return pc.GRPCCodec()
}

var _ types.InterfaceRegistry = failingInterfaceRegistry{}

// failingInterfaceRegistry is used by the fallback codec
// in case Context's Codec is not set.
type failingInterfaceRegistry struct{}

// errCodecNotSet is return by failingInterfaceRegistry in case there are attempt to decode
// or encode a type which contains an interface field.
var errCodecNotSet = errors.New("client: cannot encode or decode type which requires the application specific codec")

func (f failingInterfaceRegistry) UnpackAny(any *types.Any, iface interface{}) error {
return errCodecNotSet
}

func (f failingInterfaceRegistry) Resolve(typeURL string) (proto.Message, error) {
return nil, errCodecNotSet
}

func (f failingInterfaceRegistry) RegisterInterface(protoName string, iface interface{}, impls ...proto.Message) {
panic("cannot be called")
}

func (f failingInterfaceRegistry) RegisterImplementations(iface interface{}, impls ...proto.Message) {
panic("cannot be called")
}

func (f failingInterfaceRegistry) ListAllInterfaces() []string {
panic("cannot be called")
}

func (f failingInterfaceRegistry) ListImplementations(ifaceTypeURL string) []string {
panic("cannot be called")
}

func (f failingInterfaceRegistry) EnsureRegistered(iface interface{}) error {
panic("cannot be called")
}
31 changes: 0 additions & 31 deletions client/internal_client_test.go

This file was deleted.

31 changes: 28 additions & 3 deletions codec/amino_codec.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
package codec

import (
"fmt"

"github.com/cosmos/gogoproto/proto"
protov2 "google.golang.org/protobuf/proto"

"github.com/cosmos/cosmos-sdk/codec/types"
)

// AminoCodec defines a codec that utilizes Codec for both binary and JSON
// encoding.
// Deprecated: AminoCodec defines a codec that utilizes Codec for both binary and JSON
// encoding. Any usage of amino should be done using the LegacyAmino type directly.
// Usage of amino with the Codec type is not well-supported and may be removed in the future.
type AminoCodec struct {
*LegacyAmino
}

var _ Codec = &AminoCodec{}

// NewAminoCodec returns a reference to a new AminoCodec
// Deprecated: NewAminoCodec returns a reference to a new AminoCodec.
// Use NewLegacyAmino instead.
func NewAminoCodec(codec *LegacyAmino) *AminoCodec {
return &AminoCodec{LegacyAmino: codec}
}
Expand Down Expand Up @@ -124,3 +131,21 @@ func (ac *AminoCodec) MarshalInterfaceJSON(i proto.Message) ([]byte, error) {
func (ac *AminoCodec) UnmarshalInterfaceJSON(bz []byte, ptr interface{}) error {
return ac.LegacyAmino.UnmarshalJSON(bz, ptr)
}

func (ac *AminoCodec) GetMsgAnySigners(*types.Any) ([]string, protov2.Message, error) {
return nil, nil, fmt.Errorf("amino codec does not support getting msg signers")
}

func (ac *AminoCodec) GetMsgV1Signers(proto.Message) ([]string, protov2.Message, error) {
return nil, nil, fmt.Errorf("amino codec does not support getting msg signers")
}

func (ac *AminoCodec) GetMsgV2Signers(protov2.Message) ([]string, error) {
return nil, fmt.Errorf("amino codec does not support getting msg signers")
}

func (ac *AminoCodec) InterfaceRegistry() types.InterfaceRegistry {
panic("amino codec does not support interface registry")
}

func (ac *AminoCodec) mustEmbedCodec() {}
21 changes: 21 additions & 0 deletions codec/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package codec
import (
"github.com/cosmos/gogoproto/proto"
"google.golang.org/grpc/encoding"
protov2 "google.golang.org/protobuf/proto"

"github.com/cosmos/cosmos-sdk/codec/types"
)
Expand All @@ -18,6 +19,26 @@ type (
Codec interface {
BinaryCodec
JSONCodec

// InterfaceRegistry returns the interface registry.
InterfaceRegistry() types.InterfaceRegistry

// GetMsgAnySigners returns the signers of the given message encoded in a protobuf Any
// as well as the decoded google.golang.org/protobuf/proto.Message that was used to
// extract the signers so that this can be used in other contexts.
GetMsgAnySigners(msg *types.Any) ([]string, protov2.Message, error)

// GetMsgV2Signers returns the signers of the given message.
GetMsgV2Signers(msg protov2.Message) ([]string, error)

// GetMsgV1Signers returns the signers of the given message plus the
// decoded google.golang.org/protobuf/proto.Message that was used to extract the
// signers so that this can be used in other contexts.
GetMsgV1Signers(msg proto.Message) ([]string, protov2.Message, error)

// mustEmbedCodec requires that all implementations of Codec embed an official implementation from the codec
// package. This allows new methods to be added to the Codec interface without breaking backwards compatibility.
mustEmbedCodec()
}

BinaryCodec interface {
Expand Down
52 changes: 49 additions & 3 deletions codec/proto_codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import (
"fmt"
"strings"

"github.com/cosmos/cosmos-proto/anyutil"
"github.com/cosmos/gogoproto/jsonpb"
gogoproto "github.com/cosmos/gogoproto/proto"
"google.golang.org/grpc/encoding"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/anypb"

"github.com/cosmos/gogoproto/jsonpb"
gogoproto "github.com/cosmos/gogoproto/proto"
"cosmossdk.io/x/tx/signing"

"github.com/cosmos/cosmos-sdk/codec/types"
)
Expand All @@ -26,6 +29,7 @@ type ProtoCodecMarshaler interface {
// encoding.
type ProtoCodec struct {
interfaceRegistry types.InterfaceRegistry
getSignersCtx *signing.GetSignersContext
}

var (
Expand All @@ -35,7 +39,17 @@ var (

// NewProtoCodec returns a reference to a new ProtoCodec
func NewProtoCodec(interfaceRegistry types.InterfaceRegistry) *ProtoCodec {
return &ProtoCodec{interfaceRegistry: interfaceRegistry}
getSignersCtx, err := signing.NewGetSignersContext(
signing.GetSignersOptions{
ProtoFiles: interfaceRegistry,
})
if err != nil {
panic(err)
}
return &ProtoCodec{
interfaceRegistry: interfaceRegistry,
getSignersCtx: getSignersCtx,
}
}

// Marshal implements BinaryMarshaler.Marshal method.
Expand Down Expand Up @@ -265,11 +279,43 @@ func (pc *ProtoCodec) InterfaceRegistry() types.InterfaceRegistry {
return pc.interfaceRegistry
}

func (pc ProtoCodec) GetMsgAnySigners(msg *types.Any) ([]string, proto.Message, error) {
msgv2, err := anyutil.Unpack(&anypb.Any{
TypeUrl: msg.TypeUrl,
Value: msg.Value,
}, pc.interfaceRegistry, nil)
if err != nil {
return nil, nil, err
}

signers, err := pc.getSignersCtx.GetSigners(msgv2)
return signers, msgv2, err
}

func (pc *ProtoCodec) GetMsgV2Signers(msg proto.Message) ([]string, error) {
return pc.getSignersCtx.GetSigners(msg)
}

func (pc *ProtoCodec) GetMsgV1Signers(msg gogoproto.Message) ([]string, proto.Message, error) {
if msgV2, ok := msg.(proto.Message); ok {
signers, err := pc.getSignersCtx.GetSigners(msgV2)
return signers, msgV2, err
} else {
a, err := types.NewAnyWithValue(msg)
if err != nil {
return nil, nil, err
}
return pc.GetMsgAnySigners(a)
}
}

// GRPCCodec returns the gRPC Codec for this specific ProtoCodec
func (pc *ProtoCodec) GRPCCodec() encoding.Codec {
return &grpcProtoCodec{cdc: pc}
}

func (pc *ProtoCodec) mustEmbedCodec() {}

var errUnknownProtoType = errors.New("codec: unknown proto type") // sentinel error

// grpcProtoCodec is the implementation of the gRPC proto codec.
Expand Down
36 changes: 36 additions & 0 deletions codec/proto_codec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@ import (
"reflect"
"testing"

bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1"
basev1beta1 "cosmossdk.io/api/cosmos/base/v1beta1"
"github.com/cosmos/gogoproto/proto"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/encoding"
"google.golang.org/grpc/status"
protov2 "google.golang.org/protobuf/proto"

"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)

Expand Down Expand Up @@ -168,3 +172,35 @@ func BenchmarkProtoCodecMarshalLengthPrefixed(b *testing.B) {
b.SetBytes(int64(len(blob)))
}
}

func TestGetSigners(t *testing.T) {
interfaceRegistry := types.NewInterfaceRegistry()
cdc := codec.NewProtoCodec(interfaceRegistry)
testAddr := sdk.AccAddress([]byte("test"))
testAddrStr := testAddr.String()
testAddr2 := sdk.AccAddress([]byte("test2"))
testAddrStr2 := testAddr2.String()

msgSendV1 := banktypes.NewMsgSend(testAddr, testAddr2, sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(1))))
msgSendV2 := &bankv1beta1.MsgSend{
FromAddress: testAddrStr,
ToAddress: testAddrStr2,
Amount: []*basev1beta1.Coin{{Denom: "foo", Amount: "1"}},
}

signers, msgSendV2Copy, err := cdc.GetMsgV1Signers(msgSendV1)
require.NoError(t, err)
require.Equal(t, []string{testAddrStr}, signers)
require.True(t, protov2.Equal(msgSendV2, msgSendV2Copy))

signers, err = cdc.GetMsgV2Signers(msgSendV2)
require.NoError(t, err)
require.Equal(t, []string{testAddrStr}, signers)

msgSendAny, err := types.NewAnyWithValue(msgSendV1)
require.NoError(t, err)
signers, msgSendV2Copy, err = cdc.GetMsgAnySigners(msgSendAny)
require.NoError(t, err)
require.Equal(t, []string{testAddrStr}, signers)
require.True(t, protov2.Equal(msgSendV2, msgSendV2Copy))
}
Loading

0 comments on commit 9332942

Please sign in to comment.