Add ADR 031 BaseApp and codec infrastructure (#7519)

* Refactor RegisterQueryServices -> RegisterServices

* Cleaner proto files

* Fix tests

* Add MsgServer

* Fix lint

* Remove MsgServer from configurator for now

* Remove useless file

* Fix build

* typo

* Add router

* Fix test

* WIP

* Add router

* Remove test helper

* Add beginning of test

* Move test to simapp?

* ServiceMsg implement sdk.Msg

* Add handler by MsgServiceRouter

* Correct signature

* Add full test

* use TxEncoder

* Update baseapp/msg_service_router.go

Co-authored-by: Aaron Craelius <aaron@regen.network>

* Push changes

* WIP on ServiceMsg unpacking

* Make TestMsgService test pass

* Fix tests

* Tidying up

* Tidying up

* Tidying up

* Add JSON test

* Add comments

* Tidying

* Lint

* Register MsgRequest interface

* Rename

* Fix tests

* RegisterCustomTypeURL

* Add changelog entries

* Put in features

* Update baseapp/msg_service_router.go

Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>

* Update baseapp/msg_service_router.go

Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>

* Update baseapp/msg_service_router.go

Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>

* Update baseapp/msg_service_router.go

Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>

* Update baseapp/msg_service_router.go

Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>

* Update baseapp/msg_service_router.go

Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>

* Update baseapp/msg_service_router.go

Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>

* Address review comments

* Address nit

* Fix lint

* Update codec/types/interface_registry.go

Co-authored-by: Marie Gauthier <marie.gauthier63@gmail.com>

* godoc

Co-authored-by: Aaron Craelius <aaronc@users.noreply.github.com>
Co-authored-by: Aaron Craelius <aaron@regen.network>
Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>
Co-authored-by: Marie Gauthier <marie.gauthier63@gmail.com>
This commit is contained in:
Amaury Martiny 2020-10-15 15:07:59 +02:00 committed by GitHub
parent e6e4a94071
commit 55242a659c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 5274 additions and 3850 deletions

View File

@ -40,6 +40,15 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (x/staking) [\#7499](https://github.com/cosmos/cosmos-sdk/pull/7499) `BondStatus` is now a protobuf `enum` instead of an `int32`, and JSON serialized using its protobuf name, so expect names like `BOND_STATUS_UNBONDING` as opposed to `Unbonding`.
### API Breaking
* (AppModule) [\#7518](https://github.com/cosmos/cosmos-sdk/pull/7518) Rename `AppModule.RegisterQueryServices` to `AppModule.RegisterServices`, as this method now registers multiple services (the gRPC query service and the protobuf Msg service). A `Configurator` struct is used to hold the different services.
### Features
* (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.
### Bug Fixes
* (kvstore) [\#7415](https://github.com/cosmos/cosmos-sdk/pull/7415) Allow new stores to be registered during on-chain upgrades.

View File

@ -688,7 +688,7 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.Res
Result: res,
}
bz, err := codec.ProtoMarshalJSON(simRes)
bz, err := codec.ProtoMarshalJSON(simRes, app.interfaceRegistry)
if err != nil {
return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to JSON encode simulation response"))
}

View File

@ -13,6 +13,7 @@ import (
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/snapshots"
"github.com/cosmos/cosmos-sdk/store"
"github.com/cosmos/cosmos-sdk/store/rootmulti"
@ -45,15 +46,17 @@ type (
// BaseApp reflects the ABCI application implementation.
type BaseApp struct { // nolint: maligned
// initialized on creation
logger log.Logger
name string // application name from abci.Info
db dbm.DB // common DB backend
cms sdk.CommitMultiStore // Main (uncached) state
storeLoader StoreLoader // function to handle store loading, may be overridden with SetStoreLoader()
router sdk.Router // handle any kind of message
queryRouter sdk.QueryRouter // router for redirecting query calls
grpcQueryRouter *GRPCQueryRouter // router for redirecting gRPC query calls
txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx
logger log.Logger
name string // application name from abci.Info
db dbm.DB // common DB backend
cms sdk.CommitMultiStore // Main (uncached) state
storeLoader StoreLoader // function to handle store loading, may be overridden with SetStoreLoader()
router sdk.Router // handle any kind of message
queryRouter sdk.QueryRouter // router for redirecting query calls
grpcQueryRouter *GRPCQueryRouter // router for redirecting gRPC query calls
msgServiceRouter *MsgServiceRouter // router for redirecting Msg service messages
interfaceRegistry types.InterfaceRegistry
txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx
anteHandler sdk.AnteHandler // ante handler for fee and auth
initChainer sdk.InitChainer // initialize state with validators and state blob
@ -136,16 +139,17 @@ func NewBaseApp(
name string, logger log.Logger, db dbm.DB, txDecoder sdk.TxDecoder, options ...func(*BaseApp),
) *BaseApp {
app := &BaseApp{
logger: logger,
name: name,
db: db,
cms: store.NewCommitMultiStore(db),
storeLoader: DefaultStoreLoader,
router: NewRouter(),
queryRouter: NewQueryRouter(),
grpcQueryRouter: NewGRPCQueryRouter(),
txDecoder: txDecoder,
fauxMerkleMode: false,
logger: logger,
name: name,
db: db,
cms: store.NewCommitMultiStore(db),
storeLoader: DefaultStoreLoader,
router: NewRouter(),
queryRouter: NewQueryRouter(),
grpcQueryRouter: NewGRPCQueryRouter(),
msgServiceRouter: NewMsgServiceRouter(),
txDecoder: txDecoder,
fauxMerkleMode: false,
}
for _, option := range options {
@ -176,6 +180,9 @@ func (app *BaseApp) Logger() log.Logger {
return app.logger
}
// MsgServiceRouter returns the MsgServiceRouter of a BaseApp.
func (app *BaseApp) MsgServiceRouter() *MsgServiceRouter { return app.msgServiceRouter }
// MountStores mounts all IAVL or DB stores to the provided keys in the BaseApp
// multistore.
func (app *BaseApp) MountStores(keys ...sdk.StoreKey) {
@ -682,20 +689,38 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (*s
break
}
msgRoute := msg.Route()
handler := app.router.Route(ctx, msgRoute)
var (
msgEvents sdk.Events
msgResult *sdk.Result
msgFqName string
err error
)
if handler == nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized message route: %s; message index: %d", msgRoute, i)
if svcMsg, ok := msg.(sdk.ServiceMsg); ok {
msgFqName = svcMsg.MethodName
handler := app.msgServiceRouter.Handler(msgFqName)
if handler == nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized message service method: %s; message index: %d", msgFqName, i)
}
msgResult, err = handler(ctx, svcMsg.Request)
} else {
// legacy sdk.Msg routing
msgRoute := msg.Route()
msgFqName = msg.Type()
handler := app.router.Route(ctx, msgRoute)
if handler == nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized message route: %s; message index: %d", msgRoute, i)
}
msgResult, err = handler(ctx, msg)
}
msgResult, err := handler(ctx, msg)
if err != nil {
return nil, sdkerrors.Wrapf(err, "failed to execute message; message index: %d", i)
}
msgEvents := sdk.Events{
sdk.NewEvent(sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyAction, msg.Type())),
msgEvents = sdk.Events{
sdk.NewEvent(sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyAction, msgFqName)),
}
msgEvents = msgEvents.AppendEvents(msgResult.GetEvents())

View File

@ -1692,9 +1692,9 @@ func TestQuery(t *testing.T) {
func TestGRPCQuery(t *testing.T) {
grpcQueryOpt := func(bapp *BaseApp) {
testdata.RegisterTestServiceServer(
testdata.RegisterQueryServer(
bapp.GRPCQueryRouter(),
testdata.TestServiceImpl{},
testdata.QueryImpl{},
)
}
@ -1711,7 +1711,7 @@ func TestGRPCQuery(t *testing.T) {
reqQuery := abci.RequestQuery{
Data: reqBz,
Path: "/testdata.TestService/SayHello",
Path: "/testdata.Query/SayHello",
}
resQuery := app.Query(reqQuery)

View File

@ -4,12 +4,11 @@ import (
gocontext "context"
"fmt"
"github.com/cosmos/cosmos-sdk/codec/types"
gogogrpc "github.com/gogo/protobuf/grpc"
abci "github.com/tendermint/tendermint/abci/types"
"google.golang.org/grpc"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
@ -22,6 +21,11 @@ type QueryServiceTestHelper struct {
ctx sdk.Context
}
var (
_ gogogrpc.Server = &QueryServiceTestHelper{}
_ gogogrpc.ClientConn = &QueryServiceTestHelper{}
)
// NewQueryServerTestHelper creates a new QueryServiceTestHelper that wraps
// the provided sdk.Context
func NewQueryServerTestHelper(ctx sdk.Context, interfaceRegistry types.InterfaceRegistry) *QueryServiceTestHelper {
@ -62,6 +66,3 @@ func (q *QueryServiceTestHelper) Invoke(_ gocontext.Context, method string, args
func (q *QueryServiceTestHelper) NewStream(gocontext.Context, *grpc.StreamDesc, string, ...grpc.CallOption) (grpc.ClientStream, error) {
return nil, fmt.Errorf("not supported")
}
var _ gogogrpc.Server = &QueryServiceTestHelper{}
var _ gogogrpc.ClientConn = &QueryServiceTestHelper{}

View File

@ -15,12 +15,12 @@ func TestGRPCRouter(t *testing.T) {
qr := NewGRPCQueryRouter()
interfaceRegistry := testdata.NewTestInterfaceRegistry()
qr.SetInterfaceRegistry(interfaceRegistry)
testdata.RegisterTestServiceServer(qr, testdata.TestServiceImpl{})
testdata.RegisterQueryServer(qr, testdata.QueryImpl{})
helper := &QueryServiceTestHelper{
GRPCQueryRouter: qr,
ctx: sdk.Context{}.WithContext(context.Background()),
}
client := testdata.NewTestServiceClient(helper)
client := testdata.NewQueryClient(helper)
res, err := client.Echo(context.Background(), &testdata.EchoRequest{Message: "hello"})
require.Nil(t, err)

View File

@ -0,0 +1,94 @@
package baseapp
import (
"context"
"fmt"
"github.com/gogo/protobuf/proto"
gogogrpc "github.com/gogo/protobuf/grpc"
"google.golang.org/grpc"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// MsgServiceRouter routes fully-qualified Msg service methods to their handler.
type MsgServiceRouter struct {
interfaceRegistry codectypes.InterfaceRegistry
routes map[string]MsgServiceHandler
}
var _ gogogrpc.Server = &MsgServiceRouter{}
// NewMsgServiceRouter creates a new MsgServiceRouter.
func NewMsgServiceRouter() *MsgServiceRouter {
return &MsgServiceRouter{
routes: map[string]MsgServiceHandler{},
}
}
// MsgServiceHandler defines a function type which handles Msg service message.
type MsgServiceHandler = func(ctx sdk.Context, req sdk.MsgRequest) (*sdk.Result, error)
// Handler returns the MsgServiceHandler for a given query route path or nil
// if not found.
func (msr *MsgServiceRouter) Handler(methodName string) MsgServiceHandler {
return msr.routes[methodName]
}
// RegisterService implements the gRPC Server.RegisterService method. sd is a gRPC
// service description, handler is an object which implements that gRPC service.
func (msr *MsgServiceRouter) RegisterService(sd *grpc.ServiceDesc, handler interface{}) {
// Adds a top-level query handler based on the gRPC service name.
for _, method := range sd.Methods {
fqMethod := fmt.Sprintf("/%s/%s", sd.ServiceName, method.MethodName)
methodHandler := method.Handler
// NOTE: This is how we pull the concrete request type for each handler for registering in the InterfaceRegistry.
// This approach is maybe a bit hacky, but less hacky than reflecting on the handler object itself.
// We use a no-op interceptor to avoid actually calling into the handler itself.
_, _ = methodHandler(nil, context.Background(), func(i interface{}) error {
msg, ok := i.(proto.Message)
if !ok {
// We panic here because there is no other alternative and the app cannot be initialized correctly
// this should only happen if there is a problem with code generation in which case the app won't
// work correctly anyway.
panic(fmt.Errorf("can't register request type %T for service method %s", i, fqMethod))
}
msr.interfaceRegistry.RegisterCustomTypeURL((*sdk.MsgRequest)(nil), fqMethod, msg)
return nil
}, func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
return nil, nil
})
msr.routes[fqMethod] = func(ctx sdk.Context, req sdk.MsgRequest) (*sdk.Result, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
// Call the method handler from the service description with the handler object.
res, err := methodHandler(handler, sdk.WrapSDKContext(ctx), func(_ interface{}) error {
// We don't do any decoding here because the decoding was already done.
return nil
}, func(goCtx context.Context, _ interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
goCtx = context.WithValue(goCtx, sdk.SdkContextKey, ctx)
return handler(goCtx, req)
})
if err != nil {
return nil, err
}
resMsg, ok := res.(proto.Message)
if !ok {
return nil, fmt.Errorf("can't proto encode %T", resMsg)
}
return sdk.WrapServiceResult(ctx, resMsg, err)
}
}
}
// SetInterfaceRegistry sets the interface registry for the router.
func (msr *MsgServiceRouter) SetInterfaceRegistry(interfaceRegistry codectypes.InterfaceRegistry) {
msr.interfaceRegistry = interfaceRegistry
}

View File

@ -0,0 +1,74 @@
package baseapp_test
import (
"os"
"testing"
"github.com/cosmos/cosmos-sdk/baseapp"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
)
func TestMsgService(t *testing.T) {
priv, _, _ := testdata.KeyTestPubAddr()
encCfg := simapp.MakeEncodingConfig()
db := dbm.NewMemDB()
app := baseapp.NewBaseApp("test", log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, encCfg.TxConfig.TxDecoder())
app.SetInterfaceRegistry(encCfg.InterfaceRegistry)
testdata.RegisterMsgServer(
app.MsgServiceRouter(),
testdata.MsgServerImpl{},
)
_ = app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: 1}})
msg := testdata.NewServiceMsgCreateDog(&testdata.MsgCreateDog{Dog: &testdata.Dog{Name: "Spot"}})
txBuilder := encCfg.TxConfig.NewTxBuilder()
txBuilder.SetFeeAmount(testdata.NewTestFeeAmount())
txBuilder.SetGasLimit(testdata.NewTestGasLimit())
err := txBuilder.SetMsgs(msg)
require.NoError(t, err)
// First round: we gather all the signer infos. We use the "set empty
// signature" hack to do that.
sigV2 := signing.SignatureV2{
PubKey: priv.PubKey(),
Data: &signing.SingleSignatureData{
SignMode: encCfg.TxConfig.SignModeHandler().DefaultMode(),
Signature: nil,
},
Sequence: 0,
}
err = txBuilder.SetSignatures(sigV2)
require.NoError(t, err)
// Second round: all signer infos are set, so each signer can sign.
signerData := authsigning.SignerData{
ChainID: "test",
AccountNumber: 0,
Sequence: 0,
}
sigV2, err = tx.SignWithPrivKey(
encCfg.TxConfig.SignModeHandler().DefaultMode(), signerData,
txBuilder, priv, encCfg.TxConfig, 0)
require.NoError(t, err)
err = txBuilder.SetSignatures(sigV2)
require.NoError(t, err)
// Send the tx to the app
txBytes, err := encCfg.TxConfig.TxEncoder()(txBuilder.GetTx())
require.NoError(t, err)
res := app.DeliverTx(abci.RequestDeliverTx{Tx: txBytes})
require.Equal(t, abci.CodeTypeOK, res.Code, "res=%+v", res)
}

View File

@ -6,6 +6,7 @@ import (
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/snapshots"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -221,3 +222,10 @@ func (app *BaseApp) SetSnapshotKeepRecent(snapshotKeepRecent uint32) {
}
app.snapshotKeepRecent = snapshotKeepRecent
}
// SetInterfaceRegistry sets the InterfaceRegistry.
func (app *BaseApp) SetInterfaceRegistry(registry types.InterfaceRegistry) {
app.interfaceRegistry = registry
app.grpcQueryRouter.SetInterfaceRegistry(registry)
app.msgServiceRouter.SetInterfaceRegistry(registry)
}

View File

@ -108,7 +108,7 @@ func TestCLIQueryConn(t *testing.T) {
n := network.New(t, cfg)
defer n.Cleanup()
testClient := testdata.NewTestServiceClient(n.Validators[0].ClientCtx)
testClient := testdata.NewQueryClient(n.Validators[0].ClientCtx)
res, err := testClient.Echo(context.Background(), &testdata.EchoRequest{Message: "hello"})
require.NoError(t, err)
require.Equal(t, "hello", res.Message)

View File

@ -43,7 +43,7 @@ func (s *IntegrationTestSuite) TestGRPCQuery() {
val0 := s.network.Validators[0]
// gRPC query to test service should work
testClient := testdata.NewTestServiceClient(val0.ClientCtx)
testClient := testdata.NewQueryClient(val0.ClientCtx)
testRes, err := testClient.Echo(context.Background(), &testdata.EchoRequest{Message: "hello"})
s.Require().NoError(err)
s.Require().Equal("hello", testRes.Message)

View File

@ -11,10 +11,10 @@ import (
// ProtoMarshalJSON provides an auxiliary function to return Proto3 JSON encoded
// bytes of a message.
func ProtoMarshalJSON(msg proto.Message) ([]byte, error) {
func ProtoMarshalJSON(msg proto.Message, resolver jsonpb.AnyResolver) ([]byte, error) {
// We use the OrigName because camel casing fields just doesn't make sense.
// EmitDefaults is also often the more expected behavior for CLI users
jm := &jsonpb.Marshaler{OrigName: true, EmitDefaults: true}
jm := &jsonpb.Marshaler{OrigName: true, EmitDefaults: true, AnyResolver: resolver}
err := types.UnpackInterfaces(msg, types.ProtoJSONPacker{JSONPBMarshaler: jm})
if err != nil {
return nil, err

View File

@ -14,14 +14,14 @@ import (
// ProtoCodec defines a codec that utilizes Protobuf for both binary and JSON
// encoding.
type ProtoCodec struct {
anyUnpacker types.AnyUnpacker
interfaceRegistry types.InterfaceRegistry
}
var _ Marshaler = &ProtoCodec{}
// NewProtoCodec returns a reference to a new ProtoCodec
func NewProtoCodec(anyUnpacker types.AnyUnpacker) *ProtoCodec {
return &ProtoCodec{anyUnpacker: anyUnpacker}
func NewProtoCodec(interfaceRegistry types.InterfaceRegistry) *ProtoCodec {
return &ProtoCodec{interfaceRegistry: interfaceRegistry}
}
// MarshalBinaryBare implements BinaryMarshaler.MarshalBinaryBare method.
@ -67,7 +67,7 @@ func (pc *ProtoCodec) UnmarshalBinaryBare(bz []byte, ptr ProtoMarshaler) error {
if err != nil {
return err
}
err = types.UnpackInterfaces(ptr, pc.anyUnpacker)
err = types.UnpackInterfaces(ptr, pc.interfaceRegistry)
if err != nil {
return err
}
@ -113,7 +113,7 @@ func (pc *ProtoCodec) MarshalJSON(o proto.Message) ([]byte, error) {
return nil, fmt.Errorf("cannot protobuf JSON encode unsupported type: %T", o)
}
return ProtoMarshalJSON(m)
return ProtoMarshalJSON(m, pc.interfaceRegistry)
}
// MustMarshalJSON implements JSONMarshaler.MustMarshalJSON method,
@ -135,12 +135,13 @@ func (pc *ProtoCodec) UnmarshalJSON(bz []byte, ptr proto.Message) error {
return fmt.Errorf("cannot protobuf JSON decode unsupported type: %T", ptr)
}
err := jsonpb.Unmarshal(strings.NewReader(string(bz)), m)
unmarshaler := jsonpb.Unmarshaler{AnyResolver: pc.interfaceRegistry}
err := unmarshaler.Unmarshal(strings.NewReader(string(bz)), m)
if err != nil {
return err
}
return types.UnpackInterfaces(ptr, pc.anyUnpacker)
return types.UnpackInterfaces(ptr, pc.interfaceRegistry)
}
// MustUnmarshalJSON implements JSONMarshaler.MustUnmarshalJSON method,
@ -155,5 +156,9 @@ func (pc *ProtoCodec) MustUnmarshalJSON(bz []byte, ptr proto.Message) {
// it unpacks the value in any to the interface pointer passed in as
// iface.
func (pc *ProtoCodec) UnpackAny(any *types.Any, iface interface{}) error {
return pc.anyUnpacker.UnpackAny(any, iface)
return pc.interfaceRegistry.UnpackAny(any, iface)
}
func (pc *ProtoCodec) InterfaceRegistry() types.InterfaceRegistry {
return pc.interfaceRegistry
}

View File

@ -4,6 +4,8 @@ import (
"fmt"
"reflect"
"github.com/gogo/protobuf/jsonpb"
"github.com/gogo/protobuf/proto"
)
@ -24,6 +26,7 @@ type AnyUnpacker interface {
// implementations that can be safely unpacked from Any
type InterfaceRegistry interface {
AnyUnpacker
jsonpb.AnyResolver
// RegisterInterface associates protoName as the public name for the
// interface passed in as iface. This is to be used primarily to create
@ -43,6 +46,17 @@ type InterfaceRegistry interface {
// registry.RegisterImplementations((*sdk.Msg)(nil), &MsgSend{}, &MsgMultiSend{})
RegisterImplementations(iface interface{}, impls ...proto.Message)
// RegisterCustomTypeURL allows a protobuf message to be registered as a
// google.protobuf.Any with a custom typeURL (besides its own canonical
// typeURL). iface should be an interface as type, as in RegisterInterface
// and RegisterImplementations.
//
// Ex:
// This will allow us to pack service methods in Any's using the full method name
// as the type URL and the request body as the value, and allow us to unpack
// such packed methods using the normal UnpackAny method for the interface iface.
RegisterCustomTypeURL(iface interface{}, typeURL string, impl proto.Message)
// ListAllInterfaces list the type URLs of all registered interfaces.
ListAllInterfaces() []string
@ -78,6 +92,7 @@ type UnpackInterfacesMessage interface {
type interfaceRegistry struct {
interfaceNames map[string]reflect.Type
interfaceImpls map[reflect.Type]interfaceMap
typeURLMap map[string]reflect.Type
}
type interfaceMap = map[string]reflect.Type
@ -87,6 +102,7 @@ func NewInterfaceRegistry() InterfaceRegistry {
return &interfaceRegistry{
interfaceNames: map[string]reflect.Type{},
interfaceImpls: map[reflect.Type]interfaceMap{},
typeURLMap: map[string]reflect.Type{},
}
}
@ -100,21 +116,31 @@ func (registry *interfaceRegistry) RegisterInterface(protoName string, iface int
}
func (registry *interfaceRegistry) RegisterImplementations(iface interface{}, impls ...proto.Message) {
for _, impl := range impls {
typeURL := "/" + proto.MessageName(impl)
registry.registerImpl(iface, typeURL, impl)
}
}
func (registry *interfaceRegistry) RegisterCustomTypeURL(iface interface{}, typeURL string, impl proto.Message) {
registry.registerImpl(iface, typeURL, impl)
}
func (registry *interfaceRegistry) registerImpl(iface interface{}, typeURL string, impl proto.Message) {
ityp := reflect.TypeOf(iface).Elem()
imap, found := registry.interfaceImpls[ityp]
if !found {
imap = map[string]reflect.Type{}
}
for _, impl := range impls {
implType := reflect.TypeOf(impl)
if !implType.AssignableTo(ityp) {
panic(fmt.Errorf("type %T doesn't actually implement interface %+v", impl, ityp))
}
imap["/"+proto.MessageName(impl)] = implType
implType := reflect.TypeOf(impl)
if !implType.AssignableTo(ityp) {
panic(fmt.Errorf("type %T doesn't actually implement interface %+v", impl, ityp))
}
imap[typeURL] = implType
registry.typeURLMap[typeURL] = implType
registry.interfaceImpls[ityp] = imap
}
@ -198,6 +224,23 @@ func (registry *interfaceRegistry) UnpackAny(any *Any, iface interface{}) error
return nil
}
// Resolve returns the proto message given its typeURL. It works with types
// registered with RegisterInterface/RegisterImplementations, as well as those
// registered with RegisterWithCustomTypeURL.
func (registry *interfaceRegistry) Resolve(typeURL string) (proto.Message, error) {
typ, found := registry.typeURLMap[typeURL]
if !found {
return nil, fmt.Errorf("unable to resolve type URL %s", typeURL)
}
msg, ok := reflect.New(typ.Elem()).Interface().(proto.Message)
if !ok {
return nil, fmt.Errorf("can't resolve type URL %s", typeURL)
}
return msg, nil
}
// UnpackInterfaces is a convenience function that calls UnpackInterfaces
// on x if x implements UnpackInterfacesMessage
func UnpackInterfaces(x interface{}, unpacker AnyUnpacker) error {

View File

@ -1,15 +1,20 @@
package types_test
import (
"context"
"fmt"
"strings"
"testing"
"github.com/gogo/protobuf/grpc"
"github.com/gogo/protobuf/jsonpb"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/gogo/protobuf/proto"
grpc2 "google.golang.org/grpc"
"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"
)
@ -153,3 +158,60 @@ func TestAny_ProtoJSON(t *testing.T) {
require.NoError(t, err)
require.Equal(t, spot, ha2.Animal.GetCachedValue())
}
// this instance of grpc.ClientConn is used to test packing service method
// requests into Any's
type testAnyPackClient struct {
any types.Any
interfaceRegistry types.InterfaceRegistry
}
var _ grpc.ClientConn = &testAnyPackClient{}
func (t *testAnyPackClient) Invoke(_ context.Context, method string, args, _ interface{}, _ ...grpc2.CallOption) error {
reqMsg, ok := args.(proto.Message)
if !ok {
return fmt.Errorf("can't proto marshal %T", args)
}
// registry the method request type with the interface registry
t.interfaceRegistry.RegisterCustomTypeURL((*interface{})(nil), method, reqMsg)
bz, err := proto.Marshal(reqMsg)
if err != nil {
return err
}
t.any.TypeUrl = method
t.any.Value = bz
return nil
}
func (t *testAnyPackClient) NewStream(context.Context, *grpc2.StreamDesc, string, ...grpc2.CallOption) (grpc2.ClientStream, error) {
return nil, fmt.Errorf("not supported")
}
func TestAny_ServiceRequestProtoJSON(t *testing.T) {
interfaceRegistry := types.NewInterfaceRegistry()
anyPacker := &testAnyPackClient{interfaceRegistry: interfaceRegistry}
dogMsgClient := testdata.NewMsgClient(anyPacker)
_, err := dogMsgClient.CreateDog(context.Background(), &testdata.MsgCreateDog{Dog: &testdata.Dog{
Name: "spot",
}})
require.NoError(t, err)
// marshal JSON
cdc := codec.NewProtoCodec(interfaceRegistry)
bz, err := cdc.MarshalJSON(&anyPacker.any)
require.NoError(t, err)
require.Equal(t,
`{"@type":"/testdata.Msg/CreateDog","dog":{"size":"","name":"spot"}}`,
string(bz))
// unmarshal JSON
var any2 types.Any
err = cdc.UnmarshalJSON(bz, &any2)
require.NoError(t, err)
require.Equal(t, anyPacker.any, any2)
}

View File

@ -56,7 +56,7 @@ func benchmarkRejectUnknownFields(b *testing.B, parallel bool) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
n1A := new(testdata.Nested1A)
if err := unknownproto.RejectUnknownFieldsStrict(n1BBlob, n1A); err == nil {
if err := unknownproto.RejectUnknownFieldsStrict(n1BBlob, n1A, unknownproto.DefaultAnyResolver{}); err == nil {
b.Fatal("expected an error")
}
b.SetBytes(int64(len(n1BBlob)))
@ -68,7 +68,7 @@ func benchmarkRejectUnknownFields(b *testing.B, parallel bool) {
for pb.Next() {
// To simulate the conditions of multiple transactions being processed in parallel.
n1A := new(testdata.Nested1A)
if err := unknownproto.RejectUnknownFieldsStrict(n1BBlob, n1A); err == nil {
if err := unknownproto.RejectUnknownFieldsStrict(n1BBlob, n1A, unknownproto.DefaultAnyResolver{}); err == nil {
b.Fatal("expected an error")
}
mu.Lock()

View File

@ -7,8 +7,10 @@ import (
"fmt"
"io/ioutil"
"reflect"
"strings"
"sync"
"github.com/gogo/protobuf/jsonpb"
"github.com/gogo/protobuf/proto"
"github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
"google.golang.org/protobuf/encoding/protowire"
@ -24,8 +26,9 @@ type descriptorIface interface {
// RejectUnknownFieldsStrict rejects any bytes bz with an error that has unknown fields for the provided proto.Message type.
// This function traverses inside of messages nested via google.protobuf.Any. It does not do any deserialization of the proto.Message.
func RejectUnknownFieldsStrict(bz []byte, msg proto.Message) error {
_, err := RejectUnknownFields(bz, msg, false)
// An AnyResolver must be provided for traversing inside google.protobuf.Any's.
func RejectUnknownFieldsStrict(bz []byte, msg proto.Message, resolver jsonpb.AnyResolver) error {
_, err := RejectUnknownFields(bz, msg, false, resolver)
return err
}
@ -34,7 +37,8 @@ func RejectUnknownFieldsStrict(bz []byte, msg proto.Message) error {
// hasUnknownNonCriticals will be set to true if non-critical fields were encountered during traversal. This flag can be
// used to treat a message with non-critical field different in different security contexts (such as transaction signing).
// This function traverses inside of messages nested via google.protobuf.Any. It does not do any deserialization of the proto.Message.
func RejectUnknownFields(bz []byte, msg proto.Message, allowUnknownNonCriticals bool) (hasUnknownNonCriticals bool, err error) {
// An AnyResolver must be provided for traversing inside google.protobuf.Any's.
func RejectUnknownFields(bz []byte, msg proto.Message, allowUnknownNonCriticals bool, resolver jsonpb.AnyResolver) (hasUnknownNonCriticals bool, err error) {
if len(bz) == 0 {
return hasUnknownNonCriticals, nil
}
@ -115,9 +119,12 @@ func RejectUnknownFields(bz []byte, msg proto.Message, allowUnknownNonCriticals
_, o := protowire.ConsumeVarint(fieldBytes)
fieldBytes = fieldBytes[o:]
var msg proto.Message
var err error
if protoMessageName == ".google.protobuf.Any" {
// Firstly typecheck types.Any to ensure nothing snuck in.
hasUnknownNonCriticalsChild, err := RejectUnknownFields(fieldBytes, (*types.Any)(nil), allowUnknownNonCriticals)
hasUnknownNonCriticalsChild, err := RejectUnknownFields(fieldBytes, (*types.Any)(nil), allowUnknownNonCriticals, resolver)
hasUnknownNonCriticals = hasUnknownNonCriticals || hasUnknownNonCriticalsChild
if err != nil {
return hasUnknownNonCriticals, err
@ -129,14 +136,18 @@ func RejectUnknownFields(bz []byte, msg proto.Message, allowUnknownNonCriticals
}
protoMessageName = any.TypeUrl
fieldBytes = any.Value
msg, err = resolver.Resolve(protoMessageName)
if err != nil {
return hasUnknownNonCriticals, err
}
} else {
msg, err = protoMessageForTypeName(protoMessageName[1:])
if err != nil {
return hasUnknownNonCriticals, err
}
}
msg, err := protoMessageForTypeName(protoMessageName[1:])
if err != nil {
return hasUnknownNonCriticals, err
}
hasUnknownNonCriticalsChild, err := RejectUnknownFields(fieldBytes, msg, allowUnknownNonCriticals)
hasUnknownNonCriticalsChild, err := RejectUnknownFields(fieldBytes, msg, allowUnknownNonCriticals, resolver)
hasUnknownNonCriticals = hasUnknownNonCriticals || hasUnknownNonCriticalsChild
if err != nil {
return hasUnknownNonCriticals, err
@ -401,3 +412,23 @@ func getDescriptorInfo(desc descriptorIface, msg proto.Message) (map[int32]*desc
return tagNumToTypeIndex, md, nil
}
// DefaultAnyResolver is a default implementation of AnyResolver which uses
// the default encoding of type URLs as specified by the protobuf specification.
type DefaultAnyResolver struct{}
var _ jsonpb.AnyResolver = DefaultAnyResolver{}
// Resolve is the AnyResolver.Resolve method.
func (d DefaultAnyResolver) Resolve(typeURL string) (proto.Message, error) {
// Only the part of typeURL after the last slash is relevant.
mname := typeURL
if slash := strings.LastIndex(mname, "/"); slash >= 0 {
mname = mname[slash+1:]
}
mt := proto.MessageType(mname)
if mt == nil {
return nil, fmt.Errorf("unknown message type %q", mname)
}
return reflect.New(mt.Elem()).Interface().(proto.Message), nil
}

View File

@ -230,7 +230,7 @@ func TestRejectUnknownFieldsRepeated(t *testing.T) {
if err != nil {
t.Fatal(err)
}
hasUnknownNonCriticals, gotErr := RejectUnknownFields(protoBlob, tt.recv, tt.allowUnknownNonCriticals)
hasUnknownNonCriticals, gotErr := RejectUnknownFields(protoBlob, tt.recv, tt.allowUnknownNonCriticals, DefaultAnyResolver{})
require.Equal(t, tt.wantErr, gotErr)
require.Equal(t, tt.hasUnknownNonCriticals, hasUnknownNonCriticals)
})
@ -289,7 +289,7 @@ func TestRejectUnknownFields_allowUnknownNonCriticals(t *testing.T) {
}
c1 := new(testdata.Customer1)
_, gotErr := RejectUnknownFields(blob, c1, tt.allowUnknownNonCriticals)
_, gotErr := RejectUnknownFields(blob, c1, tt.allowUnknownNonCriticals, DefaultAnyResolver{})
if !reflect.DeepEqual(gotErr, tt.wantErr) {
t.Fatalf("Error mismatch\nGot:\n%s\n\nWant:\n%s", gotErr, tt.wantErr)
}
@ -490,7 +490,7 @@ func TestRejectUnknownFieldsNested(t *testing.T) {
if err != nil {
t.Fatal(err)
}
gotErr := RejectUnknownFieldsStrict(protoBlob, tt.recv)
gotErr := RejectUnknownFieldsStrict(protoBlob, tt.recv, DefaultAnyResolver{})
if !reflect.DeepEqual(gotErr, tt.wantErr) {
t.Fatalf("Error mismatch\nGot:\n%s\n\nWant:\n%s", gotErr, tt.wantErr)
}
@ -643,7 +643,7 @@ func TestRejectUnknownFieldsFlat(t *testing.T) {
}
c1 := new(testdata.Customer1)
gotErr := RejectUnknownFieldsStrict(blob, c1)
gotErr := RejectUnknownFieldsStrict(blob, c1, DefaultAnyResolver{})
if !reflect.DeepEqual(gotErr, tt.wantErr) {
t.Fatalf("Error mismatch\nGot:\n%s\n\nWant:\n%s", gotErr, tt.wantErr)
}
@ -660,7 +660,7 @@ func TestPackedEncoding(t *testing.T) {
require.NoError(t, err)
unmarshalled := &testdata.TestRepeatedUints{}
_, err = RejectUnknownFields(marshalled, unmarshalled, false)
_, err = RejectUnknownFields(marshalled, unmarshalled, false, DefaultAnyResolver{})
require.NoError(t, err)
}

View File

@ -22,7 +22,7 @@ done
# generate codec/testdata proto code
protoc -I "proto" -I "third_party/proto" -I "testutil/testdata" --gocosmos_out=plugins=interfacetype+grpc,\
Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types:. ./testutil/testdata/proto.proto
Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types:. ./testutil/testdata/*.proto
# move proto files to the right places
cp -r github.com/cosmos/cosmos-sdk/* ./

View File

@ -50,7 +50,7 @@ func (s *IntegrationTestSuite) TestGRPCServer() {
s.Require().NoError(err)
// gRPC query to test service should work
testClient := testdata.NewTestServiceClient(conn)
testClient := testdata.NewQueryClient(conn)
testRes, err := testClient.Echo(context.Background(), &testdata.EchoRequest{Message: "hello"})
s.Require().NoError(err)
s.Require().Equal("hello", testRes.Message)

View File

@ -114,6 +114,7 @@ var (
upgrade.AppModuleBasic{},
evidence.AppModuleBasic{},
transfer.AppModuleBasic{},
vesting.AppModuleBasic{},
)
// module account permissions
@ -202,7 +203,7 @@ func NewSimApp(
bApp := baseapp.NewBaseApp(appName, logger, db, encodingConfig.TxConfig.TxDecoder(), baseAppOptions...)
bApp.SetCommitMultiStoreTracer(traceStore)
bApp.SetAppVersion(version.Version)
bApp.GRPCQueryRouter().SetInterfaceRegistry(interfaceRegistry)
bApp.SetInterfaceRegistry(interfaceRegistry)
bApp.GRPCQueryRouter().RegisterSimulateService(bApp.Simulate, interfaceRegistry)
keys := sdk.NewKVStoreKeys(
@ -362,7 +363,7 @@ func NewSimApp(
app.mm.RegisterServices(module.NewConfigurator(app.GRPCQueryRouter()))
// add test gRPC service for testing gRPC queries in isolation
testdata.RegisterTestServiceServer(app.GRPCQueryRouter(), testdata.TestServiceImpl{})
testdata.RegisterQueryServer(app.GRPCQueryRouter(), testdata.QueryImpl{})
// create the simulation manager and define the order of the modules for deterministic simulations
//

View File

@ -6,14 +6,12 @@ import (
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
vesting "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
)
// RegisterLegacyAminoCodec registers types with the Amino codec.
func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
sdk.RegisterLegacyAminoCodec(cdc)
cryptocodec.RegisterCrypto(cdc)
vesting.RegisterLegacyAminoCodec(cdc)
}
// RegisterInterfaces registers Interfaces from sdk/types, vesting, crypto, tx.
@ -21,5 +19,4 @@ func RegisterInterfaces(interfaceRegistry types.InterfaceRegistry) {
sdk.RegisterInterfaces(interfaceRegistry)
txtypes.RegisterInterfaces(interfaceRegistry)
cryptocodec.RegisterInterfaces(interfaceRegistry)
vesting.RegisterInterfaces(interfaceRegistry)
}

View File

@ -4,10 +4,18 @@ import (
amino "github.com/tendermint/go-amino"
"github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
func NewTestInterfaceRegistry() types.InterfaceRegistry {
registry := types.NewInterfaceRegistry()
RegisterInterfaces(registry)
return registry
}
func RegisterInterfaces(registry types.InterfaceRegistry) {
registry.RegisterImplementations((*sdk.Msg)(nil), &TestMsg{})
registry.RegisterInterface("Animal", (*Animal)(nil))
registry.RegisterImplementations(
(*Animal)(nil),
@ -22,7 +30,6 @@ func NewTestInterfaceRegistry() types.InterfaceRegistry {
(*HasHasAnimalI)(nil),
&HasHasAnimal{},
)
return registry
}
func NewTestAmino() *amino.Codec {

View File

@ -9,9 +9,11 @@ import (
"github.com/cosmos/cosmos-sdk/codec/types"
)
type TestServiceImpl struct{}
type QueryImpl struct{}
func (e TestServiceImpl) TestAny(_ context.Context, request *TestAnyRequest) (*TestAnyResponse, error) {
var _ QueryServer = QueryImpl{}
func (e QueryImpl) TestAny(_ context.Context, request *TestAnyRequest) (*TestAnyResponse, error) {
animal, ok := request.AnyAnimal.GetCachedValue().(Animal)
if !ok {
return nil, fmt.Errorf("expected Animal")
@ -28,17 +30,15 @@ func (e TestServiceImpl) TestAny(_ context.Context, request *TestAnyRequest) (*T
}}, nil
}
func (e TestServiceImpl) Echo(_ context.Context, req *EchoRequest) (*EchoResponse, error) {
func (e QueryImpl) Echo(_ context.Context, req *EchoRequest) (*EchoResponse, error) {
return &EchoResponse{Message: req.Message}, nil
}
func (e TestServiceImpl) SayHello(_ context.Context, request *SayHelloRequest) (*SayHelloResponse, error) {
func (e QueryImpl) SayHello(_ context.Context, request *SayHelloRequest) (*SayHelloResponse, error) {
greeting := fmt.Sprintf("Hello %s!", request.Name)
return &SayHelloResponse{Greeting: greeting}, nil
}
var _ TestServiceServer = TestServiceImpl{}
var _ types.UnpackInterfacesMessage = &TestAnyRequest{}
func (m *TestAnyRequest) UnpackInterfaces(unpacker types.AnyUnpacker) error {

16
testutil/testdata/msg_server.go vendored Normal file
View File

@ -0,0 +1,16 @@
package testdata
import (
"context"
)
type MsgServerImpl struct{}
var _ MsgServer = MsgServerImpl{}
// CreateDog implements the MsgServer interface.
func (m MsgServerImpl) CreateDog(_ context.Context, msg *MsgCreateDog) (*MsgCreateDogResponse, error) {
return &MsgCreateDogResponse{
Name: msg.Dog.Name,
}, nil
}

1371
testutil/testdata/query.pb.go vendored Normal file

File diff suppressed because it is too large Load Diff

39
testutil/testdata/query.proto vendored Normal file
View File

@ -0,0 +1,39 @@
syntax = "proto3";
package testdata;
import "google/protobuf/any.proto";
import "testdata.proto";
option go_package = "github.com/cosmos/cosmos-sdk/testutil/testdata";
// Query tests the protobuf Query service as defined in
// https://github.com/cosmos/cosmos-sdk/issues/5921.
service Query {
rpc Echo(EchoRequest) returns (EchoResponse);
rpc SayHello(SayHelloRequest) returns (SayHelloResponse);
rpc TestAny(TestAnyRequest) returns (TestAnyResponse);
}
message EchoRequest {
string message = 1;
}
message EchoResponse {
string message = 1;
}
message SayHelloRequest {
string name = 1;
}
message SayHelloResponse {
string greeting = 1;
}
message TestAnyRequest {
google.protobuf.Any any_animal = 1;
}
message TestAnyResponse {
testdata.HasAnimal has_animal = 1;
}

1412
testutil/testdata/testdata.pb.go vendored Normal file

File diff suppressed because it is too large Load Diff

37
testutil/testdata/testdata.proto vendored Normal file
View File

@ -0,0 +1,37 @@
syntax = "proto3";
package testdata;
import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";
option go_package = "github.com/cosmos/cosmos-sdk/testutil/testdata";
message Dog {
string size = 1;
string name = 2;
}
message Cat {
string moniker = 1;
int32 lives = 2;
}
message HasAnimal {
google.protobuf.Any animal = 1;
int64 x = 2;
}
message HasHasAnimal {
google.protobuf.Any has_animal = 1;
}
message HasHasHasAnimal {
google.protobuf.Any has_has_animal = 1;
}
// bad MultiSignature with extra fields
message BadMultiSignature {
option (gogoproto.goproto_unrecognized) = true;
repeated bytes signatures = 1;
bytes malicious_field = 5;
}

View File

@ -65,3 +65,15 @@ func (msg *TestMsg) GetSigners() []sdk.AccAddress {
return addrs
}
func (msg *TestMsg) ValidateBasic() error { return nil }
var _ sdk.MsgRequest = &MsgCreateDog{}
func (msg *MsgCreateDog) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{} }
func (msg *MsgCreateDog) ValidateBasic() error { return nil }
func NewServiceMsgCreateDog(msg *MsgCreateDog) sdk.Msg {
return sdk.ServiceMsg{
MethodName: "/testdata.Msg/CreateDog",
Request: msg,
}
}

764
testutil/testdata/tx.pb.go vendored Normal file
View File

@ -0,0 +1,764 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: tx.proto
package testdata
import (
context "context"
fmt "fmt"
_ "github.com/gogo/protobuf/gogoproto"
grpc1 "github.com/gogo/protobuf/grpc"
proto "github.com/gogo/protobuf/proto"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
io "io"
math "math"
math_bits "math/bits"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
type MsgCreateDog struct {
Dog *Dog `protobuf:"bytes,1,opt,name=dog,proto3" json:"dog,omitempty"`
}
func (m *MsgCreateDog) Reset() { *m = MsgCreateDog{} }
func (m *MsgCreateDog) String() string { return proto.CompactTextString(m) }
func (*MsgCreateDog) ProtoMessage() {}
func (*MsgCreateDog) Descriptor() ([]byte, []int) {
return fileDescriptor_0fd2153dc07d3b5c, []int{0}
}
func (m *MsgCreateDog) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *MsgCreateDog) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_MsgCreateDog.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *MsgCreateDog) XXX_Merge(src proto.Message) {
xxx_messageInfo_MsgCreateDog.Merge(m, src)
}
func (m *MsgCreateDog) XXX_Size() int {
return m.Size()
}
func (m *MsgCreateDog) XXX_DiscardUnknown() {
xxx_messageInfo_MsgCreateDog.DiscardUnknown(m)
}
var xxx_messageInfo_MsgCreateDog proto.InternalMessageInfo
func (m *MsgCreateDog) GetDog() *Dog {
if m != nil {
return m.Dog
}
return nil
}
type MsgCreateDogResponse struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
}
func (m *MsgCreateDogResponse) Reset() { *m = MsgCreateDogResponse{} }
func (m *MsgCreateDogResponse) String() string { return proto.CompactTextString(m) }
func (*MsgCreateDogResponse) ProtoMessage() {}
func (*MsgCreateDogResponse) Descriptor() ([]byte, []int) {
return fileDescriptor_0fd2153dc07d3b5c, []int{1}
}
func (m *MsgCreateDogResponse) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *MsgCreateDogResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_MsgCreateDogResponse.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *MsgCreateDogResponse) XXX_Merge(src proto.Message) {
xxx_messageInfo_MsgCreateDogResponse.Merge(m, src)
}
func (m *MsgCreateDogResponse) XXX_Size() int {
return m.Size()
}
func (m *MsgCreateDogResponse) XXX_DiscardUnknown() {
xxx_messageInfo_MsgCreateDogResponse.DiscardUnknown(m)
}
var xxx_messageInfo_MsgCreateDogResponse proto.InternalMessageInfo
func (m *MsgCreateDogResponse) GetName() string {
if m != nil {
return m.Name
}
return ""
}
// TestMsg is msg type for testing protobuf message using any, as defined in
// https://github.com/cosmos/cosmos-sdk/issues/6213.
type TestMsg struct {
Signers []string `protobuf:"bytes,1,rep,name=signers,proto3" json:"signers,omitempty"`
}
func (m *TestMsg) Reset() { *m = TestMsg{} }
func (m *TestMsg) String() string { return proto.CompactTextString(m) }
func (*TestMsg) ProtoMessage() {}
func (*TestMsg) Descriptor() ([]byte, []int) {
return fileDescriptor_0fd2153dc07d3b5c, []int{2}
}
func (m *TestMsg) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *TestMsg) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_TestMsg.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *TestMsg) XXX_Merge(src proto.Message) {
xxx_messageInfo_TestMsg.Merge(m, src)
}
func (m *TestMsg) XXX_Size() int {
return m.Size()
}
func (m *TestMsg) XXX_DiscardUnknown() {
xxx_messageInfo_TestMsg.DiscardUnknown(m)
}
var xxx_messageInfo_TestMsg proto.InternalMessageInfo
func init() {
proto.RegisterType((*MsgCreateDog)(nil), "testdata.MsgCreateDog")
proto.RegisterType((*MsgCreateDogResponse)(nil), "testdata.MsgCreateDogResponse")
proto.RegisterType((*TestMsg)(nil), "testdata.TestMsg")
}
func init() { proto.RegisterFile("tx.proto", fileDescriptor_0fd2153dc07d3b5c) }
var fileDescriptor_0fd2153dc07d3b5c = []byte{
// 258 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x28, 0xa9, 0xd0, 0x2b,
0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x28, 0x49, 0x2d, 0x2e, 0x49, 0x49, 0x2c, 0x49, 0x94, 0x12,
0x49, 0xcf, 0x4f, 0xcf, 0x07, 0x0b, 0xea, 0x83, 0x58, 0x10, 0x79, 0x29, 0x3e, 0x98, 0x3c, 0x84,
0xaf, 0xa4, 0xcf, 0xc5, 0xe3, 0x5b, 0x9c, 0xee, 0x5c, 0x94, 0x9a, 0x58, 0x92, 0xea, 0x92, 0x9f,
0x2e, 0x24, 0xcf, 0xc5, 0x9c, 0x92, 0x9f, 0x2e, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0x6d, 0xc4, 0xab,
0x07, 0x57, 0xed, 0x92, 0x9f, 0x1e, 0x04, 0x92, 0x51, 0xd2, 0xe2, 0x12, 0x41, 0xd6, 0x10, 0x94,
0x5a, 0x5c, 0x90, 0x9f, 0x57, 0x9c, 0x2a, 0x24, 0xc4, 0xc5, 0x92, 0x97, 0x98, 0x9b, 0x0a, 0xd6,
0xc9, 0x19, 0x04, 0x66, 0x2b, 0x69, 0x72, 0xb1, 0x87, 0xa4, 0x16, 0x97, 0xf8, 0x16, 0xa7, 0x0b,
0x49, 0x70, 0xb1, 0x17, 0x67, 0xa6, 0xe7, 0xa5, 0x16, 0x15, 0x4b, 0x30, 0x2a, 0x30, 0x6b, 0x70,
0x06, 0xc1, 0xb8, 0x56, 0x2c, 0x1d, 0x0b, 0xe4, 0x19, 0x8c, 0xbc, 0xb8, 0x98, 0x41, 0xca, 0x9c,
0xb9, 0x38, 0x11, 0x6e, 0x11, 0x43, 0x58, 0x8f, 0x6c, 0xa5, 0x94, 0x1c, 0x76, 0x71, 0x98, 0x53,
0x9c, 0x3c, 0x4e, 0x3c, 0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09,
0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0x4a, 0x2f, 0x3d, 0xb3,
0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, 0x3f, 0x57, 0x3f, 0x39, 0xbf, 0x38, 0x37, 0xbf, 0x18, 0x4a,
0xe9, 0x16, 0xa7, 0x64, 0xeb, 0x83, 0x4c, 0x2d, 0x2d, 0xc9, 0xcc, 0xd1, 0x87, 0x19, 0x9f, 0xc4,
0x06, 0x0e, 0x24, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0x15, 0x63, 0x9a, 0x1b, 0x60, 0x01,
0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// MsgClient is the client API for Msg service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type MsgClient interface {
CreateDog(ctx context.Context, in *MsgCreateDog, opts ...grpc.CallOption) (*MsgCreateDogResponse, error)
}
type msgClient struct {
cc grpc1.ClientConn
}
func NewMsgClient(cc grpc1.ClientConn) MsgClient {
return &msgClient{cc}
}
func (c *msgClient) CreateDog(ctx context.Context, in *MsgCreateDog, opts ...grpc.CallOption) (*MsgCreateDogResponse, error) {
out := new(MsgCreateDogResponse)
err := c.cc.Invoke(ctx, "/testdata.Msg/CreateDog", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// MsgServer is the server API for Msg service.
type MsgServer interface {
CreateDog(context.Context, *MsgCreateDog) (*MsgCreateDogResponse, error)
}
// UnimplementedMsgServer can be embedded to have forward compatible implementations.
type UnimplementedMsgServer struct {
}
func (*UnimplementedMsgServer) CreateDog(ctx context.Context, req *MsgCreateDog) (*MsgCreateDogResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CreateDog not implemented")
}
func RegisterMsgServer(s grpc1.Server, srv MsgServer) {
s.RegisterService(&_Msg_serviceDesc, srv)
}
func _Msg_CreateDog_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(MsgCreateDog)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(MsgServer).CreateDog(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/testdata.Msg/CreateDog",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(MsgServer).CreateDog(ctx, req.(*MsgCreateDog))
}
return interceptor(ctx, in, info, handler)
}
var _Msg_serviceDesc = grpc.ServiceDesc{
ServiceName: "testdata.Msg",
HandlerType: (*MsgServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "CreateDog",
Handler: _Msg_CreateDog_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "tx.proto",
}
func (m *MsgCreateDog) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *MsgCreateDog) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *MsgCreateDog) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if m.Dog != nil {
{
size, err := m.Dog.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintTx(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *MsgCreateDogResponse) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *MsgCreateDogResponse) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *MsgCreateDogResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.Name) > 0 {
i -= len(m.Name)
copy(dAtA[i:], m.Name)
i = encodeVarintTx(dAtA, i, uint64(len(m.Name)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func (m *TestMsg) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *TestMsg) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *TestMsg) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.Signers) > 0 {
for iNdEx := len(m.Signers) - 1; iNdEx >= 0; iNdEx-- {
i -= len(m.Signers[iNdEx])
copy(dAtA[i:], m.Signers[iNdEx])
i = encodeVarintTx(dAtA, i, uint64(len(m.Signers[iNdEx])))
i--
dAtA[i] = 0xa
}
}
return len(dAtA) - i, nil
}
func encodeVarintTx(dAtA []byte, offset int, v uint64) int {
offset -= sovTx(v)
base := offset
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return base
}
func (m *MsgCreateDog) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if m.Dog != nil {
l = m.Dog.Size()
n += 1 + l + sovTx(uint64(l))
}
return n
}
func (m *MsgCreateDogResponse) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.Name)
if l > 0 {
n += 1 + l + sovTx(uint64(l))
}
return n
}
func (m *TestMsg) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if len(m.Signers) > 0 {
for _, s := range m.Signers {
l = len(s)
n += 1 + l + sovTx(uint64(l))
}
}
return n
}
func sovTx(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
func sozTx(x uint64) (n int) {
return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *MsgCreateDog) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTx
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: MsgCreateDog: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: MsgCreateDog: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Dog", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTx
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthTx
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthTx
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.Dog == nil {
m.Dog = &Dog{}
}
if err := m.Dog.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipTx(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthTx
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthTx
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *MsgCreateDogResponse) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTx
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: MsgCreateDogResponse: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: MsgCreateDogResponse: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTx
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthTx
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthTx
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Name = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipTx(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthTx
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthTx
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *TestMsg) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTx
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: TestMsg: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: TestMsg: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Signers", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTx
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthTx
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthTx
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Signers = append(m.Signers, string(dAtA[iNdEx:postIndex]))
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipTx(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthTx
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthTx
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipTx(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
depth := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowTx
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowTx
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
case 1:
iNdEx += 8
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowTx
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if length < 0 {
return 0, ErrInvalidLengthTx
}
iNdEx += length
case 3:
depth++
case 4:
if depth == 0 {
return 0, ErrUnexpectedEndOfGroupTx
}
depth--
case 5:
iNdEx += 4
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
if iNdEx < 0 {
return 0, ErrInvalidLengthTx
}
if depth == 0 {
return iNdEx, nil
}
}
return 0, io.ErrUnexpectedEOF
}
var (
ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowTx = fmt.Errorf("proto: integer overflow")
ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group")
)

28
testutil/testdata/tx.proto vendored Normal file
View File

@ -0,0 +1,28 @@
syntax = "proto3";
package testdata;
import "gogoproto/gogo.proto";
import "testdata.proto";
option go_package = "github.com/cosmos/cosmos-sdk/testutil/testdata";
// Msg tests the Protobuf message service as defined in
// https://github.com/cosmos/cosmos-sdk/issues/7500.
service Msg {
rpc CreateDog(MsgCreateDog) returns (MsgCreateDogResponse);
}
message MsgCreateDog {
testdata.Dog dog = 1;
}
message MsgCreateDogResponse {
string name = 1;
}
// TestMsg is msg type for testing protobuf message using any, as defined in
// https://github.com/cosmos/cosmos-sdk/issues/6213.
message TestMsg {
option (gogoproto.goproto_getters) = false;
repeated string signers = 1;
}

File diff suppressed because it is too large Load Diff

View File

@ -7,72 +7,6 @@ import "cosmos/tx/v1beta1/tx.proto";
option go_package = "github.com/cosmos/cosmos-sdk/testutil/testdata";
message Dog {
string size = 1;
string name = 2;
}
message Cat {
string moniker = 1;
int32 lives = 2;
}
message HasAnimal {
google.protobuf.Any animal = 1;
int64 x = 2;
}
message HasHasAnimal {
google.protobuf.Any has_animal = 1;
}
message HasHasHasAnimal {
google.protobuf.Any has_has_animal = 1;
}
service TestService {
rpc Echo(EchoRequest) returns (EchoResponse);
rpc SayHello(SayHelloRequest) returns (SayHelloResponse);
rpc TestAny(TestAnyRequest) returns (TestAnyResponse);
}
message EchoRequest {
string message = 1;
}
message EchoResponse {
string message = 1;
}
message SayHelloRequest {
string name = 1;
}
message SayHelloResponse {
string greeting = 1;
}
message TestAnyRequest {
google.protobuf.Any any_animal = 1;
}
message TestAnyResponse {
HasAnimal has_animal = 1;
}
// msg type for testing
message TestMsg {
option (gogoproto.goproto_getters) = false;
repeated string signers = 1;
}
// bad MultiSignature with extra fields
message BadMultiSignature {
option (gogoproto.goproto_unrecognized) = true;
repeated bytes signatures = 1;
bytes malicious_field = 5;
}
message Customer1 {
int32 id = 1;
string name = 2;

View File

@ -14,4 +14,7 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
// RegisterInterfaces registers the sdk message type.
func RegisterInterfaces(registry types.InterfaceRegistry) {
registry.RegisterInterface("cosmos.base.v1beta1.Msg", (*Msg)(nil))
// the interface name for MsgRequest is ServiceMsg because this is most useful for clients
// to understand - it will be the way for clients to introspect on available Msg service methods
registry.RegisterInterface("cosmos.base.v1beta1.ServiceMsg", (*MsgRequest)(nil))
}

58
types/service_msg.go Normal file
View File

@ -0,0 +1,58 @@
package types
import (
"github.com/gogo/protobuf/proto"
)
// MsgRequest is the interface a transaction message, defined as a proto
// service method, must fulfill.
type MsgRequest interface {
proto.Message
// ValidateBasic does a simple validation check that
// doesn't require access to any other information.
ValidateBasic() error
// Signers returns the addrs of signers that must sign.
// CONTRACT: All signatures must be present to be valid.
// CONTRACT: Returns addrs in some deterministic order.
GetSigners() []AccAddress
}
// ServiceMsg is the struct into which an Any whose typeUrl matches a service
// method format (ex. `/cosmos.gov.Msg/SubmitProposal`) unpacks.
type ServiceMsg struct {
// MethodName is the fully-qualified service method name.
MethodName string
// Request is the request payload.
Request MsgRequest
}
var _ Msg = ServiceMsg{}
func (msg ServiceMsg) ProtoMessage() {}
func (msg ServiceMsg) Reset() {}
func (msg ServiceMsg) String() string { return "ServiceMsg" }
// Route implements Msg.Route method.
func (msg ServiceMsg) Route() string {
return msg.MethodName
}
// ValidateBasic implements Msg.ValidateBasic method.
func (msg ServiceMsg) ValidateBasic() error {
return msg.Request.ValidateBasic()
}
// GetSignBytes implements Msg.GetSignBytes method.
func (msg ServiceMsg) GetSignBytes() []byte {
panic("ServiceMsg does not have a GetSignBytes method")
}
// GetSigners implements Msg.GetSigners method.
func (msg ServiceMsg) GetSigners() []AccAddress {
return msg.Request.GetSigners()
}
// Type implements Msg.Type method.
func (msg ServiceMsg) Type() string {
return msg.MethodName
}

View File

@ -5,6 +5,10 @@ package tx
import (
fmt "fmt"
io "io"
math "math"
math_bits "math/bits"
types "github.com/cosmos/cosmos-sdk/codec/types"
types1 "github.com/cosmos/cosmos-sdk/crypto/types"
github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types"
@ -12,9 +16,6 @@ import (
signing "github.com/cosmos/cosmos-sdk/types/tx/signing"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
io "io"
math "math"
math_bits "math/bits"
)
// Reference imports to suppress errors if they are not otherwise used.

View File

@ -1,7 +1,8 @@
package tx
import (
fmt "fmt"
"fmt"
"strings"
"github.com/tendermint/tendermint/crypto"
@ -26,7 +27,15 @@ func (t *Tx) GetMsgs() []sdk.Msg {
anys := t.Body.Messages
res := make([]sdk.Msg, len(anys))
for i, any := range anys {
msg := any.GetCachedValue().(sdk.Msg)
var msg sdk.Msg
if isServiceMsg(any.TypeUrl) {
msg = sdk.ServiceMsg{
MethodName: any.TypeUrl,
Request: any.GetCachedValue().(sdk.MsgRequest),
}
} else {
msg = any.GetCachedValue().(sdk.Msg)
}
res[i] = msg
}
return res
@ -138,12 +147,23 @@ func (t *Tx) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
// UnpackInterfaces implements the UnpackInterfaceMessages.UnpackInterfaces method
func (m *TxBody) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
for _, any := range m.Messages {
var msg sdk.Msg
err := unpacker.UnpackAny(any, &msg)
if err != nil {
return err
// If the any's typeUrl contains 2 slashes, then we unpack the any into
// a ServiceMsg struct as per ADR-031.
if isServiceMsg(any.TypeUrl) {
var req sdk.MsgRequest
err := unpacker.UnpackAny(any, &req)
if err != nil {
return err
}
} else {
var msg sdk.Msg
err := unpacker.UnpackAny(any, &msg)
if err != nil {
return err
}
}
}
return nil
}
@ -168,3 +188,9 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
registry.RegisterInterface("cosmos.tx.v1beta1.Tx", (*sdk.Tx)(nil))
registry.RegisterImplementations((*sdk.Tx)(nil), &Tx{})
}
// isServiceMsg checks if a type URL corresponds to a service method name,
// i.e. /cosmos.bank.Msg/Send vs /cosmos.bank.MsgSend
func isServiceMsg(typeURL string) bool {
return strings.Count(typeURL, "/") >= 2
}

View File

@ -54,8 +54,9 @@ func (suite *AnteTestSuite) SetupTest(isCheckTx bool) {
// Set up TxConfig.
encodingConfig := simapp.MakeEncodingConfig()
// We're using TestMsg amino encoding in some tests, so register it here.
// We're using TestMsg encoding in some tests, so register it here.
encodingConfig.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil)
testdata.RegisterInterfaces(encodingConfig.InterfaceRegistry)
suite.clientCtx = client.Context{}.
WithTxConfig(encodingConfig.TxConfig)

View File

@ -31,7 +31,7 @@ func TestParseQueryResponse(t *testing.T) {
Result: &sdk.Result{Data: []byte("tx data"), Log: "log"},
}
bz, err := codec.ProtoMarshalJSON(simRes)
bz, err := codec.ProtoMarshalJSON(simRes, nil)
require.NoError(t, err)
res, err := authclient.ParseQueryResponse(bz)

View File

@ -205,10 +205,27 @@ func (w *wrapper) SetMsgs(msgs ...sdk.Msg) error {
for i, msg := range msgs {
var err error
anys[i], err = codectypes.NewAnyWithValue(msg)
if err != nil {
return err
switch msg := msg.(type) {
case sdk.ServiceMsg:
{
bz, err := proto.Marshal(msg.Request)
if err != nil {
return err
}
anys[i] = &codectypes.Any{
TypeUrl: msg.MethodName,
Value: bz,
}
}
default:
{
anys[i], err = codectypes.NewAnyWithValue(msg)
if err != nil {
return err
}
}
}
}
w.tx.Body.Messages = anys

View File

@ -29,7 +29,7 @@ func NewTxConfig(protoCodec *codec.ProtoCodec, enabledSignModes []signingtypes.S
decoder: DefaultTxDecoder(protoCodec),
encoder: DefaultTxEncoder(),
jsonDecoder: DefaultJSONTxDecoder(protoCodec),
jsonEncoder: DefaultJSONTxEncoder(),
jsonEncoder: DefaultJSONTxEncoder(protoCodec),
protoCodec: protoCodec,
}
}

View File

@ -14,7 +14,7 @@ func DefaultTxDecoder(cdc *codec.ProtoCodec) sdk.TxDecoder {
var raw tx.TxRaw
// reject all unknown proto fields in the root TxRaw
err := unknownproto.RejectUnknownFieldsStrict(txBytes, &raw)
err := unknownproto.RejectUnknownFieldsStrict(txBytes, &raw, cdc.InterfaceRegistry())
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
}
@ -27,7 +27,7 @@ func DefaultTxDecoder(cdc *codec.ProtoCodec) sdk.TxDecoder {
var body tx.TxBody
// allow non-critical unknown fields in TxBody
txBodyHasUnknownNonCriticals, err := unknownproto.RejectUnknownFields(raw.BodyBytes, &body, true)
txBodyHasUnknownNonCriticals, err := unknownproto.RejectUnknownFields(raw.BodyBytes, &body, true, cdc.InterfaceRegistry())
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
}
@ -40,7 +40,7 @@ func DefaultTxDecoder(cdc *codec.ProtoCodec) sdk.TxDecoder {
var authInfo tx.AuthInfo
// reject all unknown proto fields in AuthInfo
err = unknownproto.RejectUnknownFieldsStrict(raw.AuthInfoBytes, &authInfo)
err = unknownproto.RejectUnknownFieldsStrict(raw.AuthInfoBytes, &authInfo, cdc.InterfaceRegistry())
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
}

View File

@ -15,7 +15,6 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
)
func TestDefaultTxDecoderError(t *testing.T) {
@ -32,9 +31,9 @@ func TestDefaultTxDecoderError(t *testing.T) {
require.NoError(t, err)
_, err = decoder(txBz)
require.EqualError(t, err, "no registered implementations of type types.Msg: tx parse error")
require.EqualError(t, err, "unable to resolve type URL /testdata.TestMsg: tx parse error")
registry.RegisterImplementations((*sdk.Msg)(nil), &testdata.TestMsg{})
testdata.RegisterInterfaces(registry)
_, err = decoder(txBz)
require.NoError(t, err)
}

View File

@ -29,16 +29,16 @@ func DefaultTxEncoder() sdk.TxEncoder {
}
// DefaultJSONTxEncoder returns a default protobuf JSON TxEncoder using the provided Marshaler.
func DefaultJSONTxEncoder() sdk.TxEncoder {
func DefaultJSONTxEncoder(cdc *codec.ProtoCodec) sdk.TxEncoder {
return func(tx sdk.Tx) ([]byte, error) {
txWrapper, ok := tx.(*wrapper)
if ok {
return codec.ProtoMarshalJSON(txWrapper.tx)
return cdc.MarshalJSON(txWrapper.tx)
}
protoTx, ok := tx.(*txtypes.Tx)
if ok {
return codec.ProtoMarshalJSON(protoTx)
return cdc.MarshalJSON(protoTx)
}
return nil, fmt.Errorf("expected %T, got %T", &wrapper{}, tx)

View File

@ -125,7 +125,7 @@ func (g config) MarshalSignatureJSON(sigs []signing.SignatureV2) ([]byte, error)
toJSON := &signing.SignatureDescriptors{Signatures: descs}
return codec.ProtoMarshalJSON(toJSON)
return codec.ProtoMarshalJSON(toJSON, nil)
}
func (g config) UnmarshalSignatureJSON(bz []byte) ([]signing.SignatureV2, error) {

View File

@ -30,7 +30,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) {
)
registry.RegisterInterface(
"cosmos.auth.GenesisAccount",
"cosmos.auth.v1beta1.GenesisAccount",
(*GenesisAccount)(nil),
&BaseAccount{},
&ModuleAccount{},

View File

@ -31,6 +31,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) {
registry.RegisterImplementations(
(*authtypes.AccountI)(nil),
&BaseVestingAccount{},
&DelayedVestingAccount{},
&ContinuousVestingAccount{},
&PeriodicVestingAccount{},
@ -38,6 +39,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) {
registry.RegisterImplementations(
(*authtypes.GenesisAccount)(nil),
&BaseVestingAccount{},
&DelayedVestingAccount{},
&ContinuousVestingAccount{},
&PeriodicVestingAccount{},

View File

@ -70,6 +70,7 @@ func (m *MsgSend) XXX_DiscardUnknown() {
var xxx_messageInfo_MsgSend proto.InternalMessageInfo
// MsgSendResponse defines the Msg/Send response type.
type MsgSendResponse struct {
}
@ -159,6 +160,7 @@ func (m *MsgMultiSend) GetOutputs() []Output {
return nil
}
// MsgMultiSendResponse defines the Msg/MultiSend response type.
type MsgMultiSendResponse struct {
}
@ -248,7 +250,9 @@ const _ = grpc.SupportPackageIsVersion4
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type MsgClient interface {
// Send defines a method for sending coins from one account to another account.
Send(ctx context.Context, in *MsgSend, opts ...grpc.CallOption) (*MsgSendResponse, error)
// MultiSend defines a method for sending coins from some accounts to other accounts.
MultiSend(ctx context.Context, in *MsgMultiSend, opts ...grpc.CallOption) (*MsgMultiSendResponse, error)
}
@ -280,7 +284,9 @@ func (c *msgClient) MultiSend(ctx context.Context, in *MsgMultiSend, opts ...grp
// MsgServer is the server API for Msg service.
type MsgServer interface {
// Send defines a method for sending coins from one account to another account.
Send(context.Context, *MsgSend) (*MsgSendResponse, error)
// MultiSend defines a method for sending coins from some accounts to other accounts.
MultiSend(context.Context, *MsgMultiSend) (*MsgMultiSendResponse, error)
}