Remove ServiceMsgs from ADR-031 (#9139)

* wip

* wip

* wip

* wip on refactoring adr 031 type URLs

* Fix msg_service_router

* Fix gov client queries

* Fix some modules tests

* Remove all instances of "*.Msg/*"

* Uncomment code

* Remove commented code

* // simulation.NewWeightedOperation(

* Fix CopyTx

* Fix more tests

* Fix x/gov test

* proto.MessageName->sdk.MsgName

* Fix authz tests

* Use MsgRoute in feegrant and staking/authz

* Fix more tests

* Fix sims?

* Add norace tag

* Add CL

* rebuild rosetta api test data

* Update ADR

* Rename MsgRoute -> MsgTypeURL

* Fix codec registration

* Remove sdk.GetLegacySignBytes

* Update types/tx_msg.go

* Update x/authz/simulation/operations.go

* Move LegacyMsg to legacytx

* Update CHANGELOG.md

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

* Remove NewAnyWithCustomTypeURL

* Keep support for ServiceMsgs

* Fix TxBody UnpackInterfaces

* Fix test

* Address review

* Remove support for ServiceMsg typeURLs

* Fix lint

* Update changelog

* Fix tests

* Use sdk.MsgTypeURL everywhere

* Fix tests

* Fix rosetta, run make rosetta-data

* Fix rosetta thanks to froydi

* Address reviews

* Fix test

* Remove stray log

* Update CL

Co-authored-by: Aaron Craelius <aaronc@users.noreply.github.com>
Co-authored-by: Alessio Treglia <alessio@tendermint.com>
Co-authored-by: Aaron Craelius <aaron@regen.network>
This commit is contained in:
Amaury 2021-04-30 13:00:47 +02:00 committed by GitHub
parent 6fbded9664
commit dfe3e7a8d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 428 additions and 903 deletions

View File

@ -37,7 +37,8 @@ Ref: https://keepachangelog.com/en/1.0.0/
## [Unreleased]
* [\#9205](https://github.com/cosmos/cosmos-sdk/pull/9205) Improve readability in `abci` handleQueryP2P
## Features
### Features
* [\#8965](https://github.com/cosmos/cosmos-sdk/pull/8965) cosmos reflection now provides more information on the application such as: deliverable msgs, sdk.Config info etc (still in alpha stage).
* [\#8559](https://github.com/cosmos/cosmos-sdk/pull/8559) Added Protobuf compatible secp256r1 ECDSA signatures.
* [\#8786](https://github.com/cosmos/cosmos-sdk/pull/8786) Enabled secp256r1 in x/auth.
@ -48,6 +49,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (x/staking) [\#9214](https://github.com/cosmos/cosmos-sdk/pull/9214) Added `new_shares` attribute inside `EventTypeDelegate` event.
### Client Breaking Changes
* [\#8363](https://github.com/cosmos/cosmos-sdk/pull/8363) Addresses no longer have a fixed 20-byte length. From the SDK modules' point of view, any 1-255 bytes-long byte array is a valid address.
* [\#8346](https://github.com/cosmos/cosmos-sdk/pull/8346) All CLI `tx` commands generate ServiceMsgs by default. Graceful Amino support has been added to ServiceMsgs to support signing legacy Msgs.
* (crypto/ed25519) [\#8690] Adopt zip1215 ed2559 verification rules.
@ -59,6 +61,10 @@ Ref: https://keepachangelog.com/en/1.0.0/
* CLI: removed `--text` flag from `show-node-id` command; the text format for public keys is not used any more - instead we use ProtoJSON.
* (types) [\#9079](https://github.com/cosmos/cosmos-sdk/issues/9079) Add `AddAmount`/`SubAmount` methods to `sdk.Coin`.
* [\#8628](https://github.com/cosmos/cosmos-sdk/issues/8628) Commands no longer print outputs using `stderr` by default
* [\#9139](https://github.com/cosmos/cosmos-sdk/pull/9139) Querying events:
* via `ServiceMsg` TypeURLs (e.g. `message.action='/cosmos.bank.v1beta1.Msg/Send'`) does not work anymore,
* via legacy `msg.Type()` (e.g. `message.action='send'`) is being deprecated, new `Msg`s won't emit these events.
* Please use concrete `Msg` TypeURLs instead (e.g. `message.action='/cosmos.bank.v1beta1.MsgSend'`).
### API Breaking Changes
@ -92,6 +98,10 @@ Ref: https://keepachangelog.com/en/1.0.0/
* `codec.JSONMarshaler``codec.JSONCodec`
* Removed `BinaryBare` suffix from `BinaryCodec` methods (`MarshalBinaryBare`, `UnmarshalBinaryBare`, ...)
* Removed `Binary` infix from `BinaryCodec` methods (`MarshalBinaryLengthPrefixed`, `UnmarshalBinaryLengthPrefixed`, ...)
* [\#9139](https://github.com/cosmos/cosmos-sdk/pull/9139) `ServiceMsg` TypeURLs (e.g. `/cosmos.bank.v1beta1.Msg/Send`) have been removed, as they don't comply to the Probobuf `Any` spec. Please use `Msg` type TypeURLs (e.g. `/cosmos.bank.v1beta1.MsgSend`). This has multiple consequences:
* The `sdk.ServiceMsg` struct has been removed.
* `sdk.Msg` now only contains `ValidateBasic` and `GetSigners` methods. The remaining methods `GetSignBytes`, `Route` and `Type` are moved to `legacytx.LegacyMsg`.
* The `RegisterCustomTypeURL` function and the `cosmos.base.v1beta1.ServiceMsg` interface have been removed from the interface registry.

View File

@ -19,6 +19,7 @@ import (
"github.com/cosmos/cosmos-sdk/store/rootmulti"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
)
const (
@ -703,37 +704,39 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (*s
}
var (
msgEvents sdk.Events
msgResult *sdk.Result
msgFqName string
err error
msgResult *sdk.Result
eventMsgName string // name to use as value in event `message.action`
err error
)
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 {
if handler := app.msgServiceRouter.Handler(msg); handler != nil {
// ADR 031 request type routing
msgResult, err = handler(ctx, msg)
eventMsgName = sdk.MsgTypeURL(msg)
} else if legacyMsg, ok := msg.(legacytx.LegacyMsg); ok {
// legacy sdk.Msg routing
msgRoute := msg.Route()
msgFqName = msg.Type()
// Assuming that the app developer has migrated all their Msgs to
// proto messages and has registered all `Msg services`, then this
// path should never be called, because all those Msgs should be
// registered within the `msgServiceRouter` already.
msgRoute := legacyMsg.Route()
eventMsgName = legacyMsg.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)
} else {
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "can't route message %+v", 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, msgFqName)),
msgEvents := sdk.Events{
sdk.NewEvent(sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyAction, eventMsgName)),
}
msgEvents = msgEvents.AppendEvents(msgResult.GetEvents())
@ -743,7 +746,7 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (*s
// separate each result.
events = events.AppendEvents(msgEvents)
txMsgData.Data = append(txMsgData.Data, &sdk.MsgData{MsgType: msg.Type(), Data: msgResult.Data})
txMsgData.Data = append(txMsgData.Data, &sdk.MsgData{MsgType: sdk.MsgTypeURL(msg), Data: msgResult.Data})
msgLogs = append(msgLogs, sdk.NewABCIMessageLog(uint32(i), msgResult.Log, msgEvents))
}

View File

@ -29,12 +29,17 @@ func NewMsgServiceRouter() *MsgServiceRouter {
}
// MsgServiceHandler defines a function type which handles Msg service message.
type MsgServiceHandler = func(ctx sdk.Context, req sdk.MsgRequest) (*sdk.Result, error)
type MsgServiceHandler = func(ctx sdk.Context, req sdk.Msg) (*sdk.Result, error)
// Handler returns the MsgServiceHandler for a given query route path or nil
// Handler returns the MsgServiceHandler for a given msg or nil if not found.
func (msr *MsgServiceRouter) Handler(msg sdk.Msg) MsgServiceHandler {
return msr.routes[sdk.MsgTypeURL(msg)]
}
// HandlerbyTypeURL 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]
func (msr *MsgServiceRouter) HandlerbyTypeURL(typeURL string) MsgServiceHandler {
return msr.routes[typeURL]
}
// RegisterService implements the gRPC Server.RegisterService method. sd is a gRPC
@ -50,20 +55,38 @@ func (msr *MsgServiceRouter) RegisterService(sd *grpc.ServiceDesc, handler inter
fqMethod := fmt.Sprintf("/%s/%s", sd.ServiceName, method.MethodName)
methodHandler := method.Handler
var requestTypeName string
// 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.(sdk.Msg)
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))
}
requestTypeName = sdk.MsgTypeURL(msg)
return nil
}, noopInterceptor)
// Check that the service Msg fully-qualified method name has already
// been registered (via RegisterInterfaces). If the user registers a
// service without registering according service Msg type, there might be
// some unexpected behavior down the road. Since we can't return an error
// (`Server.RegisterService` interface restriction) we panic (at startup).
serviceMsg, err := msr.interfaceRegistry.Resolve(fqMethod)
if err != nil || serviceMsg == nil {
reqType, err := msr.interfaceRegistry.Resolve(requestTypeName)
if err != nil || reqType == nil {
panic(
fmt.Errorf(
"type_url %s has not been registered yet. "+
"Before calling RegisterService, you must register all interfaces by calling the `RegisterInterfaces` "+
"method on module.BasicManager. Each module should call `msgservice.RegisterMsgServiceDesc` inside its "+
"`RegisterInterfaces` method with the `_Msg_serviceDesc` generated by proto-gen",
fqMethod,
requestTypeName,
),
)
}
@ -72,7 +95,7 @@ func (msr *MsgServiceRouter) RegisterService(sd *grpc.ServiceDesc, handler inter
// registered more than once, then we should error. Since we can't
// return an error (`Server.RegisterService` interface restriction) we
// panic (at startup).
_, found := msr.routes[fqMethod]
_, found := msr.routes[requestTypeName]
if found {
panic(
fmt.Errorf(
@ -83,7 +106,7 @@ func (msr *MsgServiceRouter) RegisterService(sd *grpc.ServiceDesc, handler inter
)
}
msr.routes[fqMethod] = func(ctx sdk.Context, req sdk.MsgRequest) (*sdk.Result, error) {
msr.routes[requestTypeName] = func(ctx sdk.Context, req sdk.Msg) (*sdk.Result, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
interceptor := func(goCtx context.Context, _ interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
goCtx = context.WithValue(goCtx, sdk.SdkContextKey, ctx)
@ -112,3 +135,6 @@ func (msr *MsgServiceRouter) SetInterfaceRegistry(interfaceRegistry codectypes.I
}
func noopDecoder(_ interface{}) error { return nil }
func noopInterceptor(_ context.Context, _ interface{}, _ *grpc.UnaryServerInfo, _ grpc.UnaryHandler) (interface{}, error) {
return nil, nil
}

View File

@ -80,11 +80,11 @@ func TestMsgService(t *testing.T) {
)
_ = app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: 1}})
msg := testdata.NewServiceMsgCreateDog(&testdata.MsgCreateDog{Dog: &testdata.Dog{Name: "Spot"}})
msg := testdata.MsgCreateDog{Dog: &testdata.Dog{Name: "Spot"}}
txBuilder := encCfg.TxConfig.NewTxBuilder()
txBuilder.SetFeeAmount(testdata.NewTestFeeAmount())
txBuilder.SetGasLimit(testdata.NewTestGasLimit())
err := txBuilder.SetMsgs(msg)
err := txBuilder.SetMsgs(&msg)
require.NoError(t, err)
// First round: we gather all the signer infos. We use the "set empty

View File

@ -13,7 +13,6 @@ import (
"github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
"github.com/cosmos/cosmos-sdk/types"
sdk "github.com/cosmos/cosmos-sdk/types"
signing2 "github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
@ -39,10 +38,7 @@ var (
},
}
msg0 = banktypes.NewMsgSend(addr1, addr2, types.NewCoins(types.NewInt64Coin("wack", 1)))
msg1 = sdk.ServiceMsg{
MethodName: "/cosmos.bank.v1beta1.Msg/Send",
Request: banktypes.NewMsgSend(addr1, addr2, types.NewCoins(types.NewInt64Coin("wack", 2))),
}
msg1 = banktypes.NewMsgSend(addr1, addr2, types.NewCoins(types.NewInt64Coin("wack", 2)))
)
func buildTestTx(t *testing.T, builder client.TxBuilder) {
@ -88,7 +84,7 @@ func (s *TestSuite) TestCopyTx() {
s.Require().Equal(sigsV2_1, sigsV2_2)
s.Require().Equal(protoBuilder.GetTx().GetSigners(), protoBuilder2.GetTx().GetSigners())
s.Require().Equal(protoBuilder.GetTx().GetMsgs()[0], protoBuilder2.GetTx().GetMsgs()[0])
s.Require().Equal(protoBuilder.GetTx().GetMsgs()[1].(sdk.ServiceMsg).Request, protoBuilder2.GetTx().GetMsgs()[1]) // We lose the "ServiceMsg" information
s.Require().Equal(protoBuilder.GetTx().GetMsgs()[1], protoBuilder2.GetTx().GetMsgs()[1])
// amino -> proto -> amino
aminoBuilder = s.aminoCfg.NewTxBuilder()
@ -120,7 +116,7 @@ func (s *TestSuite) TestConvertTxToStdTx() {
s.Require().Equal(gas, stdTx.Fee.Gas)
s.Require().Equal(fee, stdTx.Fee.Amount)
s.Require().Equal(msg0, stdTx.Msgs[0])
s.Require().Equal(msg1.Request, stdTx.Msgs[1])
s.Require().Equal(msg1, stdTx.Msgs[1])
s.Require().Equal(timeoutHeight, stdTx.TimeoutHeight)
s.Require().Equal(sig.PubKey, stdTx.Signatures[0].PubKey)
s.Require().Equal(sig.Data.(*signing2.SingleSignatureData).Signature, stdTx.Signatures[0].Signature)
@ -140,7 +136,7 @@ func (s *TestSuite) TestConvertTxToStdTx() {
s.Require().Equal(gas, stdTx.Fee.Gas)
s.Require().Equal(fee, stdTx.Fee.Amount)
s.Require().Equal(msg0, stdTx.Msgs[0])
s.Require().Equal(msg1.Request, stdTx.Msgs[1])
s.Require().Equal(msg1, stdTx.Msgs[1])
s.Require().Equal(timeoutHeight, stdTx.TimeoutHeight)
s.Require().Empty(stdTx.Signatures)

View File

@ -64,20 +64,14 @@ func NewAnyWithValue(v proto.Message) (*Any, error) {
if v == nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrPackAny, "Expecting non nil value to create a new Any")
}
return NewAnyWithCustomTypeURL(v, "/"+proto.MessageName(v))
}
// NewAnyWithCustomTypeURL same as NewAnyWithValue, but sets a custom type url, instead
// using the one from proto.Message.
// NOTE: This functions should be only used for types with additional logic bundled
// into the protobuf Any serialization. For simple marshaling you should use NewAnyWithValue.
func NewAnyWithCustomTypeURL(v proto.Message, typeURL string) (*Any, error) {
bz, err := proto.Marshal(v)
if err != nil {
return nil, err
}
return &Any{
TypeUrl: typeURL,
TypeUrl: "/" + proto.MessageName(v),
Value: bz,
cachedValue: v,
}, nil

View File

@ -23,8 +23,6 @@ func (eom *errOnMarshal) XXX_Marshal(b []byte, deterministic bool) ([]byte, erro
return nil, errAlways
}
const fauxURL = "/anyhere"
var eom = &errOnMarshal{}
// Ensure that returning an error doesn't suddenly allocate and waste bytes.
@ -32,7 +30,7 @@ var eom = &errOnMarshal{}
func TestNewAnyWithCustomTypeURLWithErrorNoAllocation(t *testing.T) {
var ms1, ms2 runtime.MemStats
runtime.ReadMemStats(&ms1)
any, err := types.NewAnyWithCustomTypeURL(eom, fauxURL)
any, err := types.NewAnyWithValue(eom)
runtime.ReadMemStats(&ms2)
// Ensure that no fresh allocation was made.
if diff := ms2.HeapAlloc - ms1.HeapAlloc; diff > 0 {
@ -52,7 +50,7 @@ func BenchmarkNewAnyWithCustomTypeURLWithErrorReturned(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
any, err := types.NewAnyWithCustomTypeURL(eom, fauxURL)
any, err := types.NewAnyWithValue(eom)
if err == nil {
b.Fatal("err wasn't returned")
}

View File

@ -46,17 +46,6 @@ 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

View File

@ -1,18 +1,13 @@
package types_test
import (
"context"
"fmt"
"strings"
"testing"
"github.com/gogo/protobuf/grpc"
"github.com/gogo/protobuf/jsonpb"
"github.com/gogo/protobuf/proto"
"github.com/stretchr/testify/require"
grpc2 "google.golang.org/grpc"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
)
@ -185,60 +180,3 @@ 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

@ -83,7 +83,7 @@ transfer(3){
transfer.operations = [
{
"operation_identifier":{"index":0},
"type":"cosmos.bank.v1beta1.MsgSend",
"type":"/cosmos.bank.v1beta1.MsgSend",
"account":{{sender.account_identifier}},
"metadata": {
"amount": [

Binary file not shown.

View File

@ -3,6 +3,7 @@
## Changelog
- 2020-10-05: Initial Draft
- 2021-04-21: Remove `ServiceMsg`s to follow Protobuf `Any`'s spec, see [#9063](https://github.com/cosmos/cosmos-sdk/issues/9063).
## Status
@ -96,71 +97,28 @@ On the client side, developers could take advantage of this by creating RPC impl
logic. Protobuf libraries that use asynchronous callbacks, like [protobuf.js](https://github.com/protobufjs/protobuf.js#using-services)
could use this to register callbacks for specific messages even for transactions that include multiple `Msg`s.
For backwards compatibility, existing `Msg` types should be used as the request parameter
for `service` definitions. Newer `Msg` types which only support `service` definitions
should use the more canonical `Msg...Request` names.
Each `Msg` service method should have exactly one request parameter: its corresponding `Msg` type. For example, the `Msg` service method `/cosmos.gov.v1beta1.Msg/SubmitProposal` above has exactly one request parameter, namely the `Msg` type `/cosmos.gov.v1beta1.MsgSubmitProposal`. It is important the reader understands clearly the nomenclature difference between a `Msg` service (a Protobuf service) and a `Msg` type (a Protobuf message), and the differences in their fully-qualified name.
This convention has been decided over the more canonical `Msg...Request` names mainly for backwards compatibility, but also for better readability in `TxBody.messages` (see [Encoding section](#encoding) below): transactions containing `/cosmos.gov.MsgSubmitProposal` read better than those containing `/cosmos.gov.v1beta1.MsgSubmitProposalRequest`.
One consequence of this convention is that each `Msg` type can be the request parameter of only one `Msg` service method. However, we consider this limitation a good practice in explicitness.
### Encoding
Currently, we are encoding `Msg`s as `Any` in `Tx`s which involves packing the
Encoding of transactions generated with `Msg` services do not differ from current Protobuf transaction encoding as defined in [ADR-020](./adr-020-protobuf-transaction-encoding.md). We are encoding `Msg` types (which are exactly `Msg` service methods' request parameters) as `Any` in `Tx`s which involves packing the
binary-encoded `Msg` with its type URL.
The type URL for `MsgSubmitProposal` based on the proto3 spec is `/cosmos.gov.MsgSubmitProposal`.
The fully-qualified name for the `SubmitProposal` service method above (also
based on the proto3 and gRPC specs) is `/cosmos.gov.Msg/SubmitProposal` which varies
by a single `/` character. The generated `.pb.go` files for protobuf `service`s
include names of this form and any compliant protobuf/gRPC code generator will
generate the same name.
In order to encode service methods in transactions, we encode them as `Any`s in
the same `TxBody.messages` field as other `Msg`s. We simply set `Any.type_url`
to the full-qualified method name (ex. `/cosmos.gov.Msg/SubmitProposal`) and
set `Any.value` to the protobuf encoding of the request message
(`MsgSubmitProposal` in this case).
### Decoding
When decoding, `TxBody.UnpackInterfaces` will need a special case
to detect if `Any` type URLs match the service method format (ex. `/cosmos.gov.Msg/SubmitProposal`)
by checking for two `/` characters. Messages that are method names plus request parameters
instead of a normal `Any` messages will get unpacked into the `ServiceMsg` struct:
```go
type ServiceMsg struct {
// MethodName is the fully-qualified service name
MethodName string
// Request is the request payload
Request MsgRequest
}
```
Since `Msg` types are packed into `Any`, decoding transactions messages are done by unpacking `Any`s into `Msg` types. For more information, please refer to [ADR-020](./adr-020-protobuf-transaction-encoding.md#transactions).
### Routing
In the future, `service` definitions may become the primary method for defining
`Msg`s. As a starting point, we need to integrate with the SDK's existing routing
and `Msg` interface.
We propose to add a `msg_service_router` in BaseApp. This router is a key/value map which maps `Msg` types' `type_url`s to their corresponding `Msg` service method handler. Since there is a 1-to-1 mapping between `Msg` types and `Msg` service method, the `msg_service_router` has exactly one entry per `Msg` service method.
To do this, `ServiceMsg` implements the `sdk.Msg` interface and its handler does the
actual method routing, allowing this feature to be added incrementally on top of
existing functionality.
When a transaction is processed by BaseApp (in CheckTx or in DeliverTx), its `TxBody.messages` are decoded as `Msg`s. Each `Msg`'s `type_url` is matched against an entry in the `msg_service_router`, and the respective `Msg` service method handler is called.
### `MsgRequest` interface
All request messages will need to implement the `MsgRequest` interface which is a
simplified version of `Msg`, without `Route()`, `Type()` and `GetSignBytes()` which
are no longer needed:
```go
type MsgRequest interface {
proto.Message
ValidateBasic() error
GetSigners() []AccAddress
}
```
`ServiceMsg` will forward its `ValidateBasic` and `GetSigners` methods to the `MsgRequest`
methods.
For backward compatability, the old handlers are not removed yet. If BaseApp receives a legacy `Msg` with no correspoding entry in the `msg_service_router`, it will be routed via its legacy `Route()` method into the legacy handler.
### Module Configuration
@ -192,8 +150,8 @@ The `RegisterServices` method and the `Configurator` interface are intended to
evolve to satisfy the use cases discussed in [\#7093](https://github.com/cosmos/cosmos-sdk/issues/7093)
and [\#7122](https://github.com/cosmos/cosmos-sdk/issues/7421).
When `Msg` services are registered, the framework _should_ verify that all `Msg...Request` types
implement the `MsgRequest` interface described above and throw an error during initialization rather
When `Msg` services are registered, the framework _should_ verify that all `Msg` types
implement the `sdk.Msg` interface and throw an error during initialization rather
than later when transactions are processed.
### `Msg` Service Implementation
@ -211,8 +169,7 @@ func (k Keeper) SubmitProposal(goCtx context.Context, params *types.MsgSubmitPro
}
```
The `sdk.Context` should have an `EventManager` already attached by the `ServiceMsg`
router.
The `sdk.Context` should have an `EventManager` already attached by BaseApp's `msg_service_router`.
Separate handler definition is no longer needed with this approach.
@ -232,8 +189,6 @@ Finally, closing a module to client API opens desirable OCAP patterns discussed
- dramatically reduces and simplifies the code
### Cons
- supporting both this and the current concrete `Msg` type approach simultaneously could be confusing
(we could choose to deprecate the current approach)
- using `service` definitions outside the context of gRPC could be confusing (but doesnt violate the proto3 spec)

View File

@ -169,12 +169,12 @@ func newTxDescriptor(ir codectypes.InterfaceRegistry) (*TxDescriptor, error) {
return nil, fmt.Errorf("unable to get *tx.Tx protobuf name")
}
// get msgs
svcMsgImplementers := ir.ListImplementations(sdk.ServiceMsgInterfaceProtoName)
sdkMsgImplementers := ir.ListImplementations(sdk.MsgInterfaceProtoName)
msgsDesc := make([]*MsgDescriptor, 0, len(svcMsgImplementers))
msgsDesc := make([]*MsgDescriptor, 0, len(sdkMsgImplementers))
// process sdk.ServiceMsg
for _, svcMsg := range svcMsgImplementers {
for _, svcMsg := range sdkMsgImplementers {
resolved, err := ir.Resolve(svcMsg)
if err != nil {
return nil, fmt.Errorf("unable to resolve sdk.ServiceMsg %s: %w", svcMsg, err)

View File

@ -16,7 +16,9 @@ import (
"google.golang.org/grpc/metadata"
rpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha"
"github.com/cosmos/cosmos-sdk/client"
reflectionv1 "github.com/cosmos/cosmos-sdk/client/grpc/reflection"
clienttx "github.com/cosmos/cosmos-sdk/client/tx"
reflectionv2 "github.com/cosmos/cosmos-sdk/server/grpc/reflection/v2alpha1"
"github.com/cosmos/cosmos-sdk/testutil/network"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
@ -24,7 +26,8 @@ import (
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
"github.com/cosmos/cosmos-sdk/types/tx"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
@ -95,6 +98,7 @@ func (s *IntegrationTestSuite) TestGRPCServer_BankBalance() {
&banktypes.QueryBalanceRequest{Address: val0.Address.String(), Denom: denom},
grpc.Header(&header),
)
s.Require().NoError(err)
blockHeight = header.Get(grpctypes.GRPCBlockHeightHeader)
s.Require().NotEmpty(blockHeight[0]) // blockHeight is []string, first element is block height.
}
@ -161,9 +165,20 @@ func (s *IntegrationTestSuite) TestGRPCServer_GetTxsEvent() {
func (s *IntegrationTestSuite) TestGRPCServer_BroadcastTx() {
val0 := s.network.Validators[0]
grpcRes, err := banktestutil.LegacyGRPCProtoMsgSend(val0.ClientCtx,
val0.Moniker, val0.Address, val0.Address,
sdk.Coins{sdk.NewInt64Coin(s.cfg.BondDenom, 10)}, sdk.Coins{sdk.NewInt64Coin(s.cfg.BondDenom, 10)},
txBuilder := s.mkTxBuilder()
txBytes, err := val0.ClientCtx.TxConfig.TxEncoder()(txBuilder.GetTx())
s.Require().NoError(err)
// Broadcast the tx via gRPC.
queryClient := txtypes.NewServiceClient(s.conn)
grpcRes, err := queryClient.BroadcastTx(
context.Background(),
&txtypes.BroadcastTxRequest{
Mode: txtypes.BroadcastMode_BROADCAST_MODE_SYNC,
TxBytes: txBytes,
},
)
s.Require().NoError(err)
s.Require().Equal(uint32(0), grpcRes.TxResponse.Code)
@ -174,7 +189,6 @@ func (s *IntegrationTestSuite) TestGRPCServer_BroadcastTx() {
// See issue https://github.com/cosmos/cosmos-sdk/issues/7662.
func (s *IntegrationTestSuite) TestGRPCServerInvalidHeaderHeights() {
t := s.T()
val0 := s.network.Validators[0]
// We should reject connections with invalid block heights off the bat.
invalidHeightStrs := []struct {
@ -189,13 +203,7 @@ func (s *IntegrationTestSuite) TestGRPCServerInvalidHeaderHeights() {
}
for _, tt := range invalidHeightStrs {
t.Run(tt.value, func(t *testing.T) {
conn, err := grpc.Dial(
val0.AppConfig.GRPC.Address,
grpc.WithInsecure(), // Or else we get "no transport security set"
)
defer conn.Close()
testClient := testdata.NewQueryClient(conn)
testClient := testdata.NewQueryClient(s.conn)
ctx := metadata.AppendToOutgoingContext(context.Background(), grpctypes.GRPCBlockHeightHeader, tt.value)
testRes, err := testClient.Echo(ctx, &testdata.EchoRequest{Message: "hello"})
require.Error(t, err)
@ -205,6 +213,40 @@ func (s *IntegrationTestSuite) TestGRPCServerInvalidHeaderHeights() {
}
}
// mkTxBuilder creates a TxBuilder containing a signed tx from validator 0.
func (s IntegrationTestSuite) mkTxBuilder() client.TxBuilder {
val := s.network.Validators[0]
s.Require().NoError(s.network.WaitForNextBlock())
// prepare txBuilder with msg
txBuilder := val.ClientCtx.TxConfig.NewTxBuilder()
feeAmount := sdk.Coins{sdk.NewInt64Coin(s.cfg.BondDenom, 10)}
gasLimit := testdata.NewTestGasLimit()
s.Require().NoError(
txBuilder.SetMsgs(&banktypes.MsgSend{
FromAddress: val.Address.String(),
ToAddress: val.Address.String(),
Amount: sdk.Coins{sdk.NewInt64Coin(s.cfg.BondDenom, 10)},
}),
)
txBuilder.SetFeeAmount(feeAmount)
txBuilder.SetGasLimit(gasLimit)
txBuilder.SetMemo("foobar")
// setup txFactory
txFactory := clienttx.Factory{}.
WithChainID(val.ClientCtx.ChainID).
WithKeybase(val.ClientCtx.Keyring).
WithTxConfig(val.ClientCtx.TxConfig).
WithSignMode(signing.SignMode_SIGN_MODE_DIRECT)
// Sign Tx.
err := authclient.SignTx(txFactory, val.ClientCtx, val.Moniker, txBuilder, false, true)
s.Require().NoError(err)
return txBuilder
}
func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
}

View File

@ -6,7 +6,6 @@ import (
"encoding/hex"
"fmt"
"strconv"
"strings"
"time"
"github.com/cosmos/cosmos-sdk/version"
@ -71,7 +70,7 @@ func NewClient(cfg *Config) (*Client, error) {
}
if _, ok := resolvedMsg.(sdk.Msg); ok {
supportedOperations = append(supportedOperations, strings.TrimLeft(ii, "/"))
supportedOperations = append(supportedOperations, ii)
}
}

View File

@ -18,7 +18,6 @@ import (
"github.com/cosmos/cosmos-sdk/types/tx/signing"
rosettatypes "github.com/coinbase/rosetta-sdk-go/types"
"github.com/gogo/protobuf/proto"
crgerrs "github.com/tendermint/cosmos-rosetta-gateway/errors"
abci "github.com/tendermint/tendermint/abci/types"
tmtypes "github.com/tendermint/tendermint/types"
@ -147,7 +146,7 @@ func (c converter) UnsignedTx(ops []*rosettatypes.Operation) (tx authsigning.Tx,
for i := 0; i < len(ops); i++ {
op := ops[i]
protoMessage, err := c.ir.Resolve("/" + op.Type)
protoMessage, err := c.ir.Resolve(op.Type)
if err != nil {
return nil, crgerrs.WrapError(crgerrs.ErrBadArgument, "operation not found: "+op.Type)
}
@ -241,31 +240,7 @@ func (c converter) Meta(msg sdk.Msg) (meta map[string]interface{}, err error) {
// with the message proto name as type, and the raw fields
// as metadata
func (c converter) Ops(status string, msg sdk.Msg) ([]*rosettatypes.Operation, error) {
opName := proto.MessageName(msg)
// in case proto does not recognize the message name
// then we should try to cast it to service msg, to
// check if it was wrapped or not, in case the cast
// from sdk.ServiceMsg to sdk.Msg fails, then a
// codec error is returned
if opName == "" {
unwrappedMsg, ok := msg.(sdk.ServiceMsg)
if !ok {
return nil, crgerrs.WrapError(crgerrs.ErrCodec, fmt.Sprintf("unrecognized message type: %T", msg))
}
msg, ok = unwrappedMsg.Request.(sdk.Msg)
if !ok {
return nil, crgerrs.WrapError(
crgerrs.ErrCodec,
fmt.Sprintf("unable to cast %T to sdk.Msg, method: %s", unwrappedMsg.Request, unwrappedMsg.MethodName),
)
}
opName = proto.MessageName(msg)
if opName == "" {
return nil, crgerrs.WrapError(crgerrs.ErrCodec, fmt.Sprintf("unrecognized message type: %T", msg))
}
}
opName := sdk.MsgTypeURL(msg)
meta, err := c.Meta(msg)
if err != nil {

View File

@ -77,14 +77,7 @@ func (msg *TestMsg) GetSigners() []sdk.AccAddress {
}
func (msg *TestMsg) ValidateBasic() error { return nil }
var _ sdk.MsgRequest = &MsgCreateDog{}
var _ sdk.Msg = &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,
}
}

View File

@ -8,8 +8,6 @@ import (
const (
// MsgInterfaceProtoName defines the protobuf name of the cosmos Msg interface
MsgInterfaceProtoName = "cosmos.base.v1beta1.Msg"
// ServiceMsgInterfaceProtoName defines the protobuf name of the cosmos MsgRequest interface
ServiceMsgInterfaceProtoName = "cosmos.base.v1beta1.ServiceMsg"
)
// RegisterLegacyAminoCodec registers the sdk message type.
@ -21,7 +19,4 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
// RegisterInterfaces registers the sdk message type.
func RegisterInterfaces(registry types.InterfaceRegistry) {
registry.RegisterInterface(MsgInterfaceProtoName, (*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(ServiceMsgInterfaceProtoName, (*MsgRequest)(nil))
}

View File

@ -3,9 +3,7 @@ package msgservice
import (
"context"
"fmt"
"strings"
"github.com/gogo/protobuf/proto"
"google.golang.org/grpc"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
@ -24,7 +22,7 @@ func RegisterMsgServiceDesc(registry codectypes.InterfaceRegistry, sd *grpc.Serv
// 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)
msg, ok := i.(sdk.Msg)
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
@ -32,7 +30,8 @@ func RegisterMsgServiceDesc(registry codectypes.InterfaceRegistry, sd *grpc.Serv
panic(fmt.Errorf("can't register request type %T for service method %s", i, fqMethod))
}
registry.RegisterCustomTypeURL((*sdk.MsgRequest)(nil), fqMethod, msg)
registry.RegisterImplementations((*sdk.Msg)(nil), msg)
return nil
}, noopInterceptor)
@ -43,9 +42,3 @@ func RegisterMsgServiceDesc(registry codectypes.InterfaceRegistry, sd *grpc.Serv
func noopInterceptor(_ context.Context, _ interface{}, _ *grpc.UnaryServerInfo, _ grpc.UnaryHandler) (interface{}, error) {
return nil, nil
}
// 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

@ -20,10 +20,10 @@ type ServiceMsgClientConn struct {
}
// Invoke implements the grpc ClientConn.Invoke method
func (t *ServiceMsgClientConn) Invoke(_ context.Context, method string, args, _ interface{}, _ ...grpc.CallOption) error {
req, ok := args.(sdk.MsgRequest)
func (t *ServiceMsgClientConn) Invoke(_ context.Context, _ string, args, _ interface{}, _ ...grpc.CallOption) error {
req, ok := args.(sdk.Msg)
if !ok {
return fmt.Errorf("%T should implement %T", args, (*sdk.MsgRequest)(nil))
return fmt.Errorf("%T should implement %T", args, (*sdk.Msg)(nil))
}
err := req.ValidateBasic()
@ -31,10 +31,7 @@ func (t *ServiceMsgClientConn) Invoke(_ context.Context, method string, args, _
return err
}
t.msgs = append(t.msgs, sdk.ServiceMsg{
MethodName: method,
Request: req,
})
t.msgs = append(t.msgs, req)
return nil
}

View File

@ -1,70 +0,0 @@
package types
import (
"fmt"
"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.v1beta1.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 {
// Here, we're gracefully supporting Amino JSON for service
// Msgs.
// ref: https://github.com/cosmos/cosmos-sdk/issues/8346
// If `msg` is a service Msg, then we cast its `Request` to a sdk.Msg
// and call GetSignBytes on the `Request`.
msgRequest, ok := msg.Request.(Msg)
if !ok {
panic(fmt.Errorf("cannot convert ServiceMsg request to sdk.Msg, got %T", msgRequest))
}
return msgRequest.GetSignBytes()
}
// 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

@ -2,14 +2,13 @@ package simulation
import (
"encoding/json"
"fmt"
"math/rand"
"reflect"
"time"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
)
type WeightedProposalContent interface {
@ -78,16 +77,14 @@ func NewOperationMsgBasic(route, name, comment string, ok bool, msg []byte) Oper
// NewOperationMsg - create a new operation message from sdk.Msg
func NewOperationMsg(msg sdk.Msg, ok bool, comment string, cdc *codec.ProtoCodec) OperationMsg {
if reflect.TypeOf(msg) == reflect.TypeOf(sdk.ServiceMsg{}) {
srvMsg, ok := msg.(sdk.ServiceMsg)
if !ok {
panic(fmt.Sprintf("Expecting %T to implement sdk.ServiceMsg", msg))
}
bz := cdc.MustMarshalJSON(srvMsg.Request)
return NewOperationMsgBasic(srvMsg.MethodName, srvMsg.MethodName, comment, ok, bz)
if legacyMsg, okType := msg.(legacytx.LegacyMsg); okType {
return NewOperationMsgBasic(legacyMsg.Route(), legacyMsg.Type(), comment, ok, legacyMsg.GetSignBytes())
}
return NewOperationMsgBasic(msg.Route(), msg.Type(), comment, ok, msg.GetSignBytes())
bz := cdc.MustMarshalJSON(msg)
return NewOperationMsgBasic(sdk.MsgTypeURL(msg), sdk.MsgTypeURL(msg), comment, ok, bz)
}
// NoOpMsg - create a no-operation message

View File

@ -7,7 +7,6 @@ import (
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/msgservice"
)
// MaxGasWanted defines the max gas allowed.
@ -26,20 +25,11 @@ func (t *Tx) GetMsgs() []sdk.Msg {
anys := t.Body.Messages
res := make([]sdk.Msg, len(anys))
for i, any := range anys {
var msg sdk.Msg
if msgservice.IsServiceMsg(any.TypeUrl) {
req := any.GetCachedValue()
if req == nil {
panic("Any cached value is nil. Transaction messages must be correctly packed Any values.")
}
msg = sdk.ServiceMsg{
MethodName: any.TypeUrl,
Request: any.GetCachedValue().(sdk.MsgRequest),
}
} else {
msg = any.GetCachedValue().(sdk.Msg)
cached := any.GetCachedValue()
if cached == nil {
panic("Any cached value is nil. Transaction messages must be correctly packed Any values.")
}
res[i] = msg
res[i] = cached.(sdk.Msg)
}
return res
}
@ -181,20 +171,10 @@ 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 {
// If the any's typeUrl contains 2 slashes, then we unpack the any into
// a ServiceMsg struct as per ADR-031.
if msgservice.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
}
var msg sdk.Msg
err := unpacker.UnpackAny(any, &msg)
if err != nil {
return err
}
}

View File

@ -1,6 +1,8 @@
package types
import (
fmt "fmt"
"github.com/gogo/protobuf/proto"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
@ -11,21 +13,10 @@ type (
Msg interface {
proto.Message
// Return the message type.
// Must be alphanumeric or empty.
Route() string
// Returns a human-readable string for the message, intended for utilization
// within tags
Type() string
// ValidateBasic does a simple validation check that
// doesn't require access to any other information.
ValidateBasic() error
// Get the canonical byte representation of the Msg.
GetSignBytes() []byte
// 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.
@ -85,3 +76,8 @@ type TxDecoder func(txBytes []byte) (Tx, error)
// TxEncoder marshals transaction to bytes
type TxEncoder func(tx Tx) ([]byte, error)
// MsgTypeURL returns the TypeURL of a `sdk.Msg`.
func MsgTypeURL(msg Msg) string {
return fmt.Sprintf("/%s", proto.MessageName(msg))
}

View File

@ -251,19 +251,7 @@ func (s *IntegrationTestSuite) TestCLIQueryTxCmd() {
sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10)
// Send coins, try both with legacy Msg and with Msg service.
// Legacy proto Msg.
legacyTxRes, err := bankcli.LegacyGRPCProtoMsgSend(
val.ClientCtx, val.Moniker,
val.Address,
account2.GetAddress(),
sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))),
sdk.NewCoins(sendTokens),
)
s.Require().NoError(err)
s.Require().NoError(s.network.WaitForNextBlock())
// Service Msg.
// Send coins.
out, err := s.createBankMsg(
val, account2.GetAddress(),
sdk.NewCoins(sendTokens),
@ -292,16 +280,10 @@ func (s *IntegrationTestSuite) TestCLIQueryTxCmd() {
"",
},
{
"happy case (legacy Msg)",
[]string{legacyTxRes.TxResponse.TxHash, fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
false,
"",
},
{
"happy case (service Msg)",
"happy case",
[]string{txRes.TxHash, fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
false,
"/cosmos.bank.v1beta1.Msg/Send",
"/cosmos.bank.v1beta1.MsgSend",
},
}

View File

@ -16,6 +16,24 @@ import (
"github.com/cosmos/cosmos-sdk/types/tx/signing"
)
// LegacyMsg defines the old interface a message must fulfill, containing
// Amino signing method and legacy router info.
// Deprecated: Please use `Msg` instead.
type LegacyMsg interface {
sdk.Msg
// Get the canonical byte representation of the Msg.
GetSignBytes() []byte
// Return the message type.
// Must be alphanumeric or empty.
Route() string
// Returns a human-readable string for the message, intended for utilization
// within tags
Type() string
}
// StdSignDoc is replay-prevention structure.
// It includes the result of msg.GetSignBytes(),
// as well as the ChainID (prevent cross chain replay)
@ -38,7 +56,7 @@ func StdSignBytes(chainID string, accnum, sequence, timeout uint64, fee StdFee,
// If msg is a legacy Msg, then GetSignBytes is implemented.
// If msg is a ServiceMsg, then GetSignBytes has graceful support of
// calling GetSignBytes from its underlying Msg.
msgsBytes = append(msgsBytes, json.RawMessage(msg.GetSignBytes()))
msgsBytes = append(msgsBytes, json.RawMessage(msg.(LegacyMsg).GetSignBytes()))
}
bz, err := legacy.Cdc.MarshalJSON(StdSignDoc{

View File

@ -29,25 +29,7 @@ func (s *StdTxBuilder) GetTx() authsigning.Tx {
// SetMsgs implements TxBuilder.SetMsgs
func (s *StdTxBuilder) SetMsgs(msgs ...sdk.Msg) error {
stdTxMsgs := make([]sdk.Msg, len(msgs))
for i, msg := range msgs {
switch msg := msg.(type) {
case sdk.ServiceMsg:
// Since ServiceMsg isn't registered with amino, we unpack msg.Request
// into a Msg so that it's handled gracefully for the legacy
// GET /txs/{hash} and /txs endpoints.
sdkMsg, ok := msg.Request.(sdk.Msg)
if !ok {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "Expecting %T at %d to implement sdk.Msg", msg.Request, i)
}
stdTxMsgs[i] = sdkMsg
default:
// legacy sdk.Msg
stdTxMsgs[i] = msg
}
}
s.Msgs = stdTxMsgs
s.Msgs = msgs
return nil
}

View File

@ -204,12 +204,7 @@ func (w *wrapper) SetMsgs(msgs ...sdk.Msg) error {
for i, msg := range msgs {
var err error
switch msg := msg.(type) {
case sdk.ServiceMsg:
anys[i], err = codectypes.NewAnyWithCustomTypeURL(msg.Request, msg.MethodName)
default:
anys[i], err = codectypes.NewAnyWithValue(msg)
}
anys[i], err = codectypes.NewAnyWithValue(msg)
if err != nil {
return err
}

View File

@ -32,6 +32,8 @@ import (
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
var bankMsgSendEventAction = fmt.Sprintf("message.action='%s'", sdk.MsgTypeURL(&banktypes.MsgSend{}))
type IntegrationTestSuite struct {
suite.Suite
@ -192,7 +194,7 @@ func (s IntegrationTestSuite) TestGetTxEvents_GRPC() {
{
"request with order-by",
&tx.GetTxsEventRequest{
Events: []string{"message.action='/cosmos.bank.v1beta1.Msg/Send'"},
Events: []string{bankMsgSendEventAction},
OrderBy: tx.OrderBy_ORDER_BY_ASC,
},
false, "",
@ -200,14 +202,14 @@ func (s IntegrationTestSuite) TestGetTxEvents_GRPC() {
{
"without pagination",
&tx.GetTxsEventRequest{
Events: []string{"message.action='/cosmos.bank.v1beta1.Msg/Send'"},
Events: []string{bankMsgSendEventAction},
},
false, "",
},
{
"with pagination",
&tx.GetTxsEventRequest{
Events: []string{"message.action='/cosmos.bank.v1beta1.Msg/Send'"},
Events: []string{bankMsgSendEventAction},
Pagination: &query.PageRequest{
CountTotal: false,
Offset: 0,
@ -219,7 +221,7 @@ func (s IntegrationTestSuite) TestGetTxEvents_GRPC() {
{
"with multi events",
&tx.GetTxsEventRequest{
Events: []string{"message.action='/cosmos.bank.v1beta1.Msg/Send'", "message.module='bank'"},
Events: []string{bankMsgSendEventAction, "message.module='bank'"},
},
false, "",
},
@ -262,43 +264,43 @@ func (s IntegrationTestSuite) TestGetTxEvents_GRPCGateway() {
},
{
"without pagination",
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s", val.APIAddress, "message.action='/cosmos.bank.v1beta1.Msg/Send'"),
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s", val.APIAddress, bankMsgSendEventAction),
false,
"",
},
{
"with pagination",
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s&pagination.offset=%d&pagination.limit=%d", val.APIAddress, "message.action='/cosmos.bank.v1beta1.Msg/Send'", 0, 10),
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s&pagination.offset=%d&pagination.limit=%d", val.APIAddress, bankMsgSendEventAction, 0, 10),
false,
"",
},
{
"valid request: order by asc",
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s&events=%s&order_by=ORDER_BY_ASC", val.APIAddress, "message.action='/cosmos.bank.v1beta1.Msg/Send'", "message.module='bank'"),
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s&events=%s&order_by=ORDER_BY_ASC", val.APIAddress, bankMsgSendEventAction, "message.module='bank'"),
false,
"",
},
{
"valid request: order by desc",
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s&events=%s&order_by=ORDER_BY_DESC", val.APIAddress, "message.action='/cosmos.bank.v1beta1.Msg/Send'", "message.module='bank'"),
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s&events=%s&order_by=ORDER_BY_DESC", val.APIAddress, bankMsgSendEventAction, "message.module='bank'"),
false,
"",
},
{
"invalid request: invalid order by",
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s&events=%s&order_by=invalid_order", val.APIAddress, "message.action='/cosmos.bank.v1beta1.Msg/Send'", "message.module='bank'"),
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s&events=%s&order_by=invalid_order", val.APIAddress, bankMsgSendEventAction, "message.module='bank'"),
true,
"is not a valid tx.OrderBy",
},
{
"expect pass with multiple-events",
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s&events=%s", val.APIAddress, "message.action='/cosmos.bank.v1beta1.Msg/Send'", "message.module='bank'"),
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s&events=%s", val.APIAddress, bankMsgSendEventAction, "message.module='bank'"),
false,
"",
},
{
"expect pass with escape event",
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s", val.APIAddress, "message.action%3D'%2Fcosmos.bank.v1beta1.Msg%2FSend'"),
fmt.Sprintf("%s/cosmos/tx/v1beta1/txs?events=%s", val.APIAddress, "message.action%3D'/cosmos.bank.v1beta1.MsgSend'"),
false,
"",
},
@ -584,6 +586,7 @@ func (s IntegrationTestSuite) mkTxBuilder() client.TxBuilder {
)
txBuilder.SetFeeAmount(feeAmount)
txBuilder.SetGasLimit(gasLimit)
txBuilder.SetMemo("foobar")
// setup txFactory
txFactory := clienttx.Factory{}.

View File

@ -60,7 +60,7 @@ func NewCmdGrantAuthorization() *cobra.Command {
Examples:
$ %s tx %s grant cosmos1skjw.. send %s --spend-limit=1000stake --from=cosmos1skl..
$ %s tx %s grant cosmos1skjw.. generic --msg-type=/cosmos.gov.v1beta1.Msg/Vote --from=cosmos1sk..
$ %s tx %s grant cosmos1skjw.. generic --msg-type=/cosmos.gov.v1beta1.MsgVote --from=cosmos1sk..
`, version.AppName, types.ModuleName, bank.SendAuthorization{}.MethodName(), version.AppName, types.ModuleName),
),
Args: cobra.ExactArgs(2),
@ -254,17 +254,7 @@ Example:
if err != nil {
return err
}
msgs := theTx.GetMsgs()
serviceMsgs := make([]sdk.ServiceMsg, len(msgs))
for i, msg := range msgs {
srvMsg, ok := msg.(sdk.ServiceMsg)
if !ok {
return fmt.Errorf("tx contains %T which is not a sdk.ServiceMsg", msg)
}
serviceMsgs[i] = srvMsg
}
msg := types.NewMsgExecAuthorized(grantee, serviceMsgs)
msg := types.NewMsgExecAuthorized(grantee, theTx.GetMsgs())
svcMsgClientConn := &msgservice.ServiceMsgClientConn{}
msgClient := types.NewMsgClient(svcMsgClientConn)
_, err = msgClient.ExecAuthorized(context.Background(), &msg)

View File

@ -20,6 +20,7 @@ import (
types "github.com/cosmos/cosmos-sdk/x/authz/types"
banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
)
type IntegrationTestSuite struct {
@ -30,7 +31,7 @@ type IntegrationTestSuite struct {
}
var typeMsgSend = banktypes.SendAuthorization{}.MethodName()
var typeMsgVote = "/cosmos.gov.v1beta1.Msg/Vote"
var typeMsgVote = sdk.MsgTypeURL(&govtypes.MsgVote{})
func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up integration test suite")
@ -48,7 +49,7 @@ func (s *IntegrationTestSuite) SetupSuite() {
newAddr := sdk.AccAddress(info.GetPubKey().Address())
// Send some funds to the new account.
_, err = banktestutil.MsgSendExec(
out, err := banktestutil.MsgSendExec(
val.ClientCtx,
val.Address,
newAddr,
@ -57,9 +58,10 @@ func (s *IntegrationTestSuite) SetupSuite() {
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
)
s.Require().NoError(err)
s.Require().Contains(out.String(), `"code":0`)
// grant authorization
_, err = authztestutil.ExecGrantAuthorization(val, []string{
out, err = authztestutil.ExecGrantAuthorization(val, []string{
newAddr.String(),
"send",
fmt.Sprintf("--%s=100steak", cli.FlagSpendLimit),
@ -70,6 +72,7 @@ func (s *IntegrationTestSuite) SetupSuite() {
fmt.Sprintf("--%s=%d", cli.FlagExpiration, time.Now().Add(time.Minute*time.Duration(120)).Unix()),
})
s.Require().NoError(err)
s.Require().Contains(out.String(), `"code":0`)
s.grantee = newAddr
_, err = s.network.WaitForHeight(1)
@ -185,10 +188,9 @@ func (s *IntegrationTestSuite) TestQueryAuthorizationsGRPC() {
fmt.Sprintf("%s/cosmos/authz/v1beta1/granters/%s/grantees/%s/grants", baseURL, val.Address.String(), s.grantee.String()),
false,
"",
func() {
},
func() {},
func(authorizations *types.QueryAuthorizationsResponse) {
s.Require().Equal(len(authorizations.Authorizations), 1)
s.Require().Len(authorizations.Authorizations), 1)
},
},
{

View File

@ -5,25 +5,22 @@ import (
"time"
"github.com/gogo/protobuf/proto"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/testutil"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/authz/client/cli"
banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
bank "github.com/cosmos/cosmos-sdk/x/bank/types"
govcli "github.com/cosmos/cosmos-sdk/x/gov/client/cli"
govtestutil "github.com/cosmos/cosmos-sdk/x/gov/client/testutil"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
stakingcli "github.com/cosmos/cosmos-sdk/x/staking/client/cli"
banktestutil "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
bank "github.com/cosmos/cosmos-sdk/x/bank/types"
)
type IntegrationTestSuite struct {
@ -81,7 +78,7 @@ func (s *IntegrationTestSuite) TearDownSuite() {
}
var typeMsgSend = bank.SendAuthorization{}.MethodName()
var typeMsgVote = "/cosmos.gov.v1beta1.Msg/Vote"
var typeMsgVote = sdk.MsgTypeURL(&govtypes.MsgVote{})
func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() {
val := s.network.Validators[0]
@ -93,7 +90,6 @@ func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() {
testCases := []struct {
name string
args []string
respType proto.Message
expectedCode uint32
expectErr bool
}{
@ -107,7 +103,6 @@ func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() {
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
},
nil,
0,
true,
},
@ -121,7 +116,7 @@ func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() {
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
},
nil, 0,
0,
true,
},
{
@ -134,7 +129,7 @@ func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() {
fmt.Sprintf("--%s=true", flags.FlagGenerateOnly),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, pastHour),
},
nil, 0,
0,
true,
},
{
@ -149,8 +144,8 @@ func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() {
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
fmt.Sprintf("--%s=%d", cli.FlagExpiration, twoHours),
},
nil, 0,
true,
0x1d,
false,
},
{
"failed with error both validators not allowed",
@ -166,7 +161,7 @@ func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() {
fmt.Sprintf("--%s=%s", cli.FlagDenyValidators, val.ValAddress.String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
nil, 0,
0,
true,
},
{
@ -182,7 +177,7 @@ func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() {
fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
&sdk.TxResponse{}, 0,
0,
false,
},
{
@ -198,7 +193,7 @@ func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() {
fmt.Sprintf("--%s=%s", cli.FlagDenyValidators, val.ValAddress.String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
&sdk.TxResponse{}, 0,
0,
false,
},
{
@ -214,7 +209,7 @@ func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() {
fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
&sdk.TxResponse{}, 0,
0,
false,
},
{
@ -230,7 +225,7 @@ func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() {
fmt.Sprintf("--%s=%s", cli.FlagAllowedValidators, val.ValAddress.String()),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
&sdk.TxResponse{}, 0,
0,
false,
},
{
@ -245,7 +240,7 @@ func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() {
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
&sdk.TxResponse{}, 0,
0,
false,
},
{
@ -260,7 +255,7 @@ func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() {
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
&sdk.TxResponse{}, 0,
0,
false,
},
}
@ -276,9 +271,9 @@ func (s *IntegrationTestSuite) TestCLITxGrantAuthorization() {
if tc.expectErr {
s.Require().Error(err)
} else {
var txResp sdk.TxResponse
s.Require().NoError(err)
s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), tc.respType), out.String())
txResp := tc.respType.(*sdk.TxResponse)
s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &txResp), out.String())
s.Require().Equal(tc.expectedCode, txResp.Code, out.String())
}
})
@ -427,7 +422,7 @@ func (s *IntegrationTestSuite) TestExecAuthorizationWithExpiration() {
)
s.Require().NoError(err)
// msg vote
voteTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.gov.v1beta1.Msg/Vote","proposal_id":"1","voter":"%s","option":"VOTE_OPTION_YES"}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String())
voteTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.gov.v1beta1.MsgVote","proposal_id":"1","voter":"%s","option":"VOTE_OPTION_YES"}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String())
execMsg := testutil.WriteToNewTempFile(s.T(), voteTx)
// waiting for authorization to expires
@ -468,7 +463,7 @@ func (s *IntegrationTestSuite) TestNewExecGenericAuthorized() {
s.Require().NoError(err)
// msg vote
voteTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.gov.v1beta1.Msg/Vote","proposal_id":"1","voter":"%s","option":"VOTE_OPTION_YES"}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String())
voteTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.gov.v1beta1.MsgVote","proposal_id":"1","voter":"%s","option":"VOTE_OPTION_YES"}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String())
execMsg := testutil.WriteToNewTempFile(s.T(), voteTx)
testCases := []struct {
@ -646,7 +641,7 @@ func (s *IntegrationTestSuite) TestExecDelegateAuthorization() {
sdk.NewCoin("stake", sdk.NewInt(50)),
)
delegateTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.Msg/Delegate","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%s"}}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String(), val.ValAddress.String(),
delegateTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.MsgDelegate","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%s"}}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String(), val.ValAddress.String(),
tokens.GetDenomByIndex(0), tokens[0].Amount)
execMsg := testutil.WriteToNewTempFile(s.T(), delegateTx)
@ -736,7 +731,7 @@ func (s *IntegrationTestSuite) TestExecDelegateAuthorization() {
sdk.NewCoin("stake", sdk.NewInt(50)),
)
delegateTx = fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.Msg/Delegate","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%s"}}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String(), val.ValAddress.String(),
delegateTx = fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.MsgDelegate","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%s"}}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String(), val.ValAddress.String(),
tokens.GetDenomByIndex(0), tokens[0].Amount)
execMsg = testutil.WriteToNewTempFile(s.T(), delegateTx)
@ -822,7 +817,6 @@ func (s *IntegrationTestSuite) TestExecDelegateAuthorization() {
out, err := clitestutil.ExecTestCLICmd(val.ClientCtx, cmd, args)
s.Require().NoError(err)
s.Contains(out.String(), fmt.Sprintf("cannot delegate/undelegate to %s validator", val.ValAddress.String()))
}
func (s *IntegrationTestSuite) TestExecUndelegateAuthorization() {
@ -865,7 +859,7 @@ func (s *IntegrationTestSuite) TestExecUndelegateAuthorization() {
sdk.NewCoin("stake", sdk.NewInt(50)),
)
undelegateTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.Msg/Undelegate","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%s"}}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String(), val.ValAddress.String(),
undelegateTx := fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.MsgUndelegate","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%s"}}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String(), val.ValAddress.String(),
tokens.GetDenomByIndex(0), tokens[0].Amount)
execMsg := testutil.WriteToNewTempFile(s.T(), undelegateTx)
@ -955,7 +949,7 @@ func (s *IntegrationTestSuite) TestExecUndelegateAuthorization() {
sdk.NewCoin("stake", sdk.NewInt(50)),
)
undelegateTx = fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.Msg/Undelegate","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%s"}}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String(), val.ValAddress.String(),
undelegateTx = fmt.Sprintf(`{"body":{"messages":[{"@type":"/cosmos.staking.v1beta1.MsgUndelegate","delegator_address":"%s","validator_address":"%s","amount":{"denom":"%s","amount":"%s"}}],"memo":"","timeout_height":"0","extension_options":[],"non_critical_extension_options":[]},"auth_info":{"signer_infos":[],"fee":{"amount":[],"gas_limit":"200000","payer":"","granter":""}},"signatures":[]}`, val.Address.String(), val.ValAddress.String(),
tokens.GetDenomByIndex(0), tokens[0].Amount)
execMsg = testutil.WriteToNewTempFile(s.T(), undelegateTx)

View File

@ -15,7 +15,7 @@ type Authorization interface {
// Accept determines whether this grant permits the provided sdk.ServiceMsg to be performed, and if
// so provides an upgraded authorization instance.
Accept(ctx sdk.Context, msg sdk.ServiceMsg) (updated Authorization, delete bool, err error)
Accept(ctx sdk.Context, msg sdk.Msg) (updated Authorization, delete bool, err error)
// ValidateBasic does a simple validation check that
// doesn't require access to any other information.

View File

@ -73,26 +73,29 @@ func (k Keeper) update(ctx sdk.Context, grantee sdk.AccAddress, granter sdk.AccA
// DispatchActions attempts to execute the provided messages via authorization
// grants from the message signer to the grantee.
func (k Keeper) DispatchActions(ctx sdk.Context, grantee sdk.AccAddress, serviceMsgs []sdk.ServiceMsg) (*sdk.Result, error) {
func (k Keeper) DispatchActions(ctx sdk.Context, grantee sdk.AccAddress, msgs []sdk.Msg) (*sdk.Result, error) {
var msgResult *sdk.Result
var err error
for _, serviceMsg := range serviceMsgs {
signers := serviceMsg.GetSigners()
for _, msg := range msgs {
signers := msg.GetSigners()
if len(signers) != 1 {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "authorization can be given to msg with only one signer")
}
granter := signers[0]
if !granter.Equals(grantee) {
authorization, _ := k.GetOrRevokeAuthorization(ctx, grantee, granter, serviceMsg.MethodName)
authorization, _ := k.GetOrRevokeAuthorization(ctx, grantee, granter, sdk.MsgTypeURL(msg))
if authorization == nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "authorization not found")
}
updated, del, err := authorization.Accept(ctx, serviceMsg)
updated, del, err := authorization.Accept(ctx, msg)
if err != nil {
return nil, err
}
if del {
k.Revoke(ctx, grantee, granter, serviceMsg.Type())
err = k.Revoke(ctx, grantee, granter, sdk.MsgTypeURL(msg))
if err != nil {
return nil, err
}
} else if updated != nil {
err = k.update(ctx, grantee, granter, updated)
if err != nil {
@ -100,15 +103,15 @@ func (k Keeper) DispatchActions(ctx sdk.Context, grantee sdk.AccAddress, service
}
}
}
handler := k.router.Handler(serviceMsg.Route())
handler := k.router.Handler(msg)
if handler == nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized message route: %s", serviceMsg.Route())
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized message route: %s", sdk.MsgTypeURL(msg))
}
msgResult, err = handler(ctx, serviceMsg.Request)
msgResult, err = handler(ctx, msg)
if err != nil {
return nil, sdkerrors.Wrapf(err, "failed to execute message; message %s", serviceMsg.MethodName)
return nil, sdkerrors.Wrapf(err, "failed to execute message; message %v", msg)
}
}

View File

@ -4,15 +4,11 @@ import (
"testing"
"time"
proto "github.com/gogo/protobuf/proto"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/stretchr/testify/suite"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/authz/types"
@ -42,7 +38,6 @@ func (s *TestSuite) SetupTest() {
s.ctx = ctx
s.queryClient = queryClient
s.addrs = simapp.AddTestAddrsIncremental(app, ctx, 3, sdk.NewInt(30000000))
}
func (s *TestSuite) TestKeeper() {
@ -76,7 +71,7 @@ func (s *TestSuite) TestKeeper() {
s.Require().Equal(authorization.MethodName(), banktypes.SendAuthorization{}.MethodName())
s.T().Log("verify fetching authorization with wrong msg type fails")
authorization, _ = app.AuthzKeeper.GetOrRevokeAuthorization(ctx, granteeAddr, granterAddr, proto.MessageName(&banktypes.MsgMultiSend{}))
authorization, _ = app.AuthzKeeper.GetOrRevokeAuthorization(ctx, granteeAddr, granterAddr, sdk.MsgTypeURL(&banktypes.MsgMultiSend{}))
s.Require().Nil(authorization)
s.T().Log("verify fetching authorization with wrong grantee fails")
@ -139,21 +134,18 @@ func (s *TestSuite) TestKeeperFees() {
smallCoin := sdk.NewCoins(sdk.NewInt64Coin("steak", 20))
someCoin := sdk.NewCoins(sdk.NewInt64Coin("steak", 123))
msgs := types.NewMsgExecAuthorized(granteeAddr, []sdk.ServiceMsg{
{
MethodName: banktypes.SendAuthorization{}.MethodName(),
Request: &banktypes.MsgSend{
Amount: sdk.NewCoins(sdk.NewInt64Coin("steak", 2)),
FromAddress: granterAddr.String(),
ToAddress: recipientAddr.String(),
},
msgs := types.NewMsgExecAuthorized(granteeAddr, []sdk.Msg{
&banktypes.MsgSend{
Amount: sdk.NewCoins(sdk.NewInt64Coin("steak", 2)),
FromAddress: granterAddr.String(),
ToAddress: recipientAddr.String(),
},
})
s.Require().NoError(msgs.UnpackInterfaces(app.AppCodec()))
s.T().Log("verify dispatch fails with invalid authorization")
executeMsgs, err := msgs.GetServiceMsgs()
executeMsgs, err := msgs.GetMessages()
s.Require().NoError(err)
result, err := app.AuthzKeeper.DispatchActions(s.ctx, granteeAddr, executeMsgs)
@ -169,7 +161,7 @@ func (s *TestSuite) TestKeeperFees() {
s.Require().Equal(authorization.MethodName(), banktypes.SendAuthorization{}.MethodName())
executeMsgs, err = msgs.GetServiceMsgs()
executeMsgs, err = msgs.GetMessages()
s.Require().NoError(err)
result, err = app.AuthzKeeper.DispatchActions(s.ctx, granteeAddr, executeMsgs)
@ -182,19 +174,16 @@ func (s *TestSuite) TestKeeperFees() {
s.T().Log("verify dispatch fails with overlimit")
// grant authorization
msgs = types.NewMsgExecAuthorized(granteeAddr, []sdk.ServiceMsg{
{
MethodName: banktypes.SendAuthorization{}.MethodName(),
Request: &banktypes.MsgSend{
Amount: someCoin,
FromAddress: granterAddr.String(),
ToAddress: recipientAddr.String(),
},
msgs = types.NewMsgExecAuthorized(granteeAddr, []sdk.Msg{
&banktypes.MsgSend{
Amount: someCoin,
FromAddress: granterAddr.String(),
ToAddress: recipientAddr.String(),
},
})
s.Require().NoError(msgs.UnpackInterfaces(app.AppCodec()))
executeMsgs, err = msgs.GetServiceMsgs()
executeMsgs, err = msgs.GetMessages()
s.Require().NoError(err)
result, err = app.AuthzKeeper.DispatchActions(s.ctx, granteeAddr, executeMsgs)

View File

@ -24,7 +24,7 @@ func (k Keeper) GrantAuthorization(goCtx context.Context, msg *types.MsgGrantAut
authorization := msg.GetGrantAuthorization()
// If the granted service Msg doesn't exist, we throw an error.
if k.router.Handler(authorization.MethodName()) == nil {
if k.router.HandlerbyTypeURL(authorization.MethodName()) == nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "%s doesn't exist.", authorization.MethodName())
}
@ -63,7 +63,7 @@ func (k Keeper) ExecAuthorized(goCtx context.Context, msg *types.MsgExecAuthoriz
if err != nil {
return nil, err
}
msgs, err := msg.GetServiceMsgs()
msgs, err := msg.GetMessages()
if err != nil {
return nil, err
}

View File

@ -20,10 +20,12 @@ import (
)
// authz message types
const (
TypeMsgGrantAuthorization = "/cosmos.authz.v1beta1.Msg/GrantAuthorization"
TypeMsgRevokeAuthorization = "/cosmos.authz.v1beta1.Msg/RevokeAuthorization"
TypeMsgExecDelegated = "/cosmos.authz.v1beta1.Msg/ExecAuthorized"
var (
// TODO Remove `Request` suffix
// https://github.com/cosmos/cosmos-sdk/issues/9114
TypeMsgGrantAuthorization = sdk.MsgTypeURL(&types.MsgGrantAuthorizationRequest{})
TypeMsgRevokeAuthorization = sdk.MsgTypeURL(&types.MsgRevokeAuthorizationRequest{})
TypeMsgExecDelegated = sdk.MsgTypeURL(&types.MsgExecAuthorizedRequest{})
)
// Simulation operation weights constants
@ -130,7 +132,7 @@ func SimulateMsgGrantAuthorization(ak types.AccountKeeper, bk types.BankKeeper,
_, _, err = app.Deliver(txGen.TxEncoder(), tx)
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, svcMsgClientConn.GetMsgs()[0].Type(), "unable to deliver tx"), nil, err
return simtypes.NoOpMsg(types.ModuleName, sdk.MsgTypeURL(svcMsgClientConn.GetMsgs()[0]), "unable to deliver tx"), nil, err
}
return simtypes.NewOperationMsg(svcMsgClientConn.GetMsgs()[0], true, "", protoCdc), nil, err
}
@ -242,16 +244,13 @@ func SimulateMsgExecuteAuthorized(ak types.AccountKeeper, bk types.BankKeeper, k
}
sendCoins := sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(10)))
execMsg := sdk.ServiceMsg{
MethodName: banktype.SendAuthorization{}.MethodName(),
Request: banktype.NewMsgSend(
granterAddr,
granteeAddr,
sendCoins,
),
}
execMsg := banktype.NewMsgSend(
granterAddr,
granteeAddr,
sendCoins,
)
msg := types.NewMsgExecAuthorized(grantee.Address, []sdk.ServiceMsg{execMsg})
msg := types.NewMsgExecAuthorized(grantee.Address, []sdk.Msg{execMsg})
sendGrant := targetGrant.Authorization.GetCachedValue().(*banktype.SendAuthorization)
_, _, err = sendGrant.Accept(ctx, execMsg)
if err != nil {

View File

@ -11,7 +11,7 @@ import (
// RegisterInterfaces registers the interfaces types with the interface registry
func RegisterInterfaces(registry types.InterfaceRegistry) {
registry.RegisterImplementations((*sdk.MsgRequest)(nil),
registry.RegisterImplementations((*sdk.Msg)(nil),
&MsgGrantAuthorizationRequest{},
&MsgRevokeAuthorizationRequest{},
&MsgExecAuthorizedRequest{},

View File

@ -2,8 +2,6 @@ package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/msgservice"
"github.com/cosmos/cosmos-sdk/x/authz/exported"
)
@ -24,14 +22,11 @@ func (authorization GenericAuthorization) MethodName() string {
}
// Accept implements Authorization.Accept.
func (authorization GenericAuthorization) Accept(ctx sdk.Context, msg sdk.ServiceMsg) (updated exported.Authorization, delete bool, err error) {
func (authorization GenericAuthorization) Accept(ctx sdk.Context, msg sdk.Msg) (updated exported.Authorization, delete bool, err error) {
return &authorization, false, nil
}
// ValidateBasic implements Authorization.ValidateBasic.
func (authorization GenericAuthorization) ValidateBasic() error {
if !msgservice.IsServiceMsg(authorization.MessageName) {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidType, " %s is not a valid service msg", authorization.MessageName)
}
return nil
}

View File

@ -10,12 +10,8 @@ import (
)
func TestGenericAuthorization(t *testing.T) {
t.Log("verify ValidateBasic returns error for non-service msg")
authorization := types.NewGenericAuthorization(banktypes.TypeMsgSend)
require.Error(t, authorization.ValidateBasic())
t.Log("verify ValidateBasic returns nil for service msg")
authorization = types.NewGenericAuthorization(banktypes.SendAuthorization{}.MethodName())
authorization := types.NewGenericAuthorization(banktypes.SendAuthorization{}.MethodName())
require.NoError(t, authorization.ValidateBasic())
require.Equal(t, banktypes.SendAuthorization{}.MethodName(), authorization.MessageName)
}

View File

@ -12,9 +12,9 @@ import (
)
var (
_ sdk.MsgRequest = &MsgGrantAuthorizationRequest{}
_ sdk.MsgRequest = &MsgRevokeAuthorizationRequest{}
_ sdk.MsgRequest = &MsgExecAuthorizedRequest{}
_ sdk.Msg = &MsgGrantAuthorizationRequest{}
_ sdk.Msg = &MsgRevokeAuthorizationRequest{}
_ sdk.Msg = &MsgExecAuthorizedRequest{}
_ types.UnpackInterfacesMessage = &MsgGrantAuthorizationRequest{}
_ types.UnpackInterfacesMessage = &MsgExecAuthorizedRequest{}
@ -96,7 +96,7 @@ func (msg *MsgGrantAuthorizationRequest) SetAuthorization(authorization exported
// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
func (msg MsgExecAuthorizedRequest) UnpackInterfaces(unpacker types.AnyUnpacker) error {
for _, x := range msg.Msgs {
var msgExecAuthorized sdk.MsgRequest
var msgExecAuthorized sdk.Msg
err := unpacker.UnpackAny(x, &msgExecAuthorized)
if err != nil {
return err
@ -155,20 +155,15 @@ func (msg MsgRevokeAuthorizationRequest) ValidateBasic() error {
// NewMsgExecAuthorized creates a new MsgExecAuthorized
//nolint:interfacer
func NewMsgExecAuthorized(grantee sdk.AccAddress, msgs []sdk.ServiceMsg) MsgExecAuthorizedRequest {
func NewMsgExecAuthorized(grantee sdk.AccAddress, msgs []sdk.Msg) MsgExecAuthorizedRequest {
msgsAny := make([]*types.Any, len(msgs))
for i, msg := range msgs {
bz, err := proto.Marshal(msg.Request)
any, err := types.NewAnyWithValue(msg)
if err != nil {
panic(err)
}
anyMsg := &types.Any{
TypeUrl: msg.MethodName,
Value: bz,
}
msgsAny[i] = anyMsg
msgsAny[i] = any
}
return MsgExecAuthorizedRequest{
@ -177,20 +172,15 @@ func NewMsgExecAuthorized(grantee sdk.AccAddress, msgs []sdk.ServiceMsg) MsgExec
}
}
// GetServiceMsgs returns the cache values from the MsgExecAuthorized.Msgs if present.
func (msg MsgExecAuthorizedRequest) GetServiceMsgs() ([]sdk.ServiceMsg, error) {
msgs := make([]sdk.ServiceMsg, len(msg.Msgs))
// GetMessages returns the cache values from the MsgExecAuthorized.Msgs if present.
func (msg MsgExecAuthorizedRequest) GetMessages() ([]sdk.Msg, error) {
msgs := make([]sdk.Msg, len(msg.Msgs))
for i, msgAny := range msg.Msgs {
msgReq, ok := msgAny.GetCachedValue().(sdk.MsgRequest)
msg, ok := msgAny.GetCachedValue().(sdk.Msg)
if !ok {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "messages contains %T which is not a sdk.MsgRequest", msgAny)
}
srvMsg := sdk.ServiceMsg{
MethodName: msgAny.TypeUrl,
Request: msgReq,
}
msgs[i] = srvMsg
msgs[i] = msg
}
return msgs, nil

View File

@ -23,19 +23,16 @@ func TestMsgExecAuthorized(t *testing.T) {
tests := []struct {
title string
grantee sdk.AccAddress
msgs []sdk.ServiceMsg
msgs []sdk.Msg
expectPass bool
}{
{"nil grantee address", nil, []sdk.ServiceMsg{}, false},
{"zero-messages test: should fail", grantee, []sdk.ServiceMsg{}, false},
{"valid test: msg type", grantee, []sdk.ServiceMsg{
{
MethodName: banktypes.SendAuthorization{}.MethodName(),
Request: &banktypes.MsgSend{
Amount: sdk.NewCoins(sdk.NewInt64Coin("steak", 2)),
FromAddress: granter.String(),
ToAddress: grantee.String(),
},
{"nil grantee address", nil, []sdk.Msg{}, false},
{"zero-messages test: should fail", grantee, []sdk.Msg{}, false},
{"valid test: msg type", grantee, []sdk.Msg{
&banktypes.MsgSend{
Amount: sdk.NewCoins(sdk.NewInt64Coin("steak", 2)),
FromAddress: granter.String(),
ToAddress: grantee.String(),
},
}, true},
}

View File

@ -1,22 +1,14 @@
package testutil
import (
"context"
"fmt"
"github.com/tendermint/tendermint/libs/cli"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/testutil"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
"github.com/cosmos/cosmos-sdk/x/bank/types"
)
func MsgSendExec(clientCtx client.Context, from, to, amount fmt.Stringer, extraArgs ...string) (testutil.BufferWriter, error) {
@ -32,56 +24,3 @@ func QueryBalancesExec(clientCtx client.Context, address fmt.Stringer, extraArgs
return clitestutil.ExecTestCLICmd(clientCtx, bankcli.GetBalancesCmd(), args)
}
// LegacyGRPCProtoMsgSend is a legacy method to broadcast a legacy proto MsgSend.
//
// Deprecated.
//nolint:interfacer
func LegacyGRPCProtoMsgSend(clientCtx client.Context, keyName string, from, to sdk.Address, fee, amount []sdk.Coin, extraArgs ...string) (*txtypes.BroadcastTxResponse, error) {
// prepare txBuilder with msg
txBuilder := clientCtx.TxConfig.NewTxBuilder()
feeAmount := fee
gasLimit := testdata.NewTestGasLimit()
// This sets a legacy Proto MsgSend.
err := txBuilder.SetMsgs(&types.MsgSend{
FromAddress: from.String(),
ToAddress: to.String(),
Amount: amount,
})
if err != nil {
return nil, err
}
txBuilder.SetFeeAmount(feeAmount)
txBuilder.SetGasLimit(gasLimit)
// setup txFactory
txFactory := tx.Factory{}.
WithChainID(clientCtx.ChainID).
WithKeybase(clientCtx.Keyring).
WithTxConfig(clientCtx.TxConfig).
WithSignMode(signing.SignMode_SIGN_MODE_DIRECT)
// Sign Tx.
err = authclient.SignTx(txFactory, clientCtx, keyName, txBuilder, false, true)
if err != nil {
return nil, err
}
txBytes, err := clientCtx.TxConfig.TxEncoder()(txBuilder.GetTx())
if err != nil {
return nil, err
}
// Broadcast the tx via gRPC.
queryClient := txtypes.NewServiceClient(clientCtx)
return queryClient.BroadcastTx(
context.Background(),
&txtypes.BroadcastTxRequest{
Mode: txtypes.BroadcastMode_BROADCAST_MODE_SYNC,
TxBytes: txBytes,
},
)
}

View File

@ -383,10 +383,7 @@ func (s *IntegrationTestSuite) TestNewSendTxCmdGenOnly() {
s.Require().NoError(err)
tx, err := s.cfg.TxConfig.TxJSONDecoder()(bz.Bytes())
s.Require().NoError(err)
s.Require().Equal([]sdk.Msg{sdk.ServiceMsg{
MethodName: "/cosmos.bank.v1beta1.Msg/Send",
Request: types.NewMsgSend(from, to, amount),
}}, tx.GetMsgs())
s.Require().Equal([]sdk.Msg{types.NewMsgSend(from, to, amount)}, tx.GetMsgs())
}
func (s *IntegrationTestSuite) TestNewSendTxCmd() {
@ -473,62 +470,6 @@ func (s *IntegrationTestSuite) TestNewSendTxCmd() {
}
}
// TestBankMsgService does a basic test of whether or not service Msg's as defined
// in ADR 031 work in the most basic end-to-end case.
func (s *IntegrationTestSuite) TestBankMsgService() {
val := s.network.Validators[0]
testCases := []struct {
name string
from, to sdk.AccAddress
amount sdk.Coins
args []string
expectErr bool
expectedCode uint32
respType proto.Message
rawLogContains string
}{
{
"valid transaction",
val.Address,
val.Address,
sdk.NewCoins(
sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(10)),
sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)),
),
[]string{
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),
},
false,
0,
&sdk.TxResponse{},
"/cosmos.bank.v1beta1.Msg/Send", // indicates we are using ServiceMsg and not a regular Msg
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
clientCtx := val.ClientCtx
bz, err := MsgSendExec(clientCtx, tc.from, tc.to, tc.amount, tc.args...)
if tc.expectErr {
s.Require().Error(err)
} else {
s.Require().NoError(err)
s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(bz.Bytes(), tc.respType), bz.String())
txResp := tc.respType.(*sdk.TxResponse)
s.Require().Equal(tc.expectedCode, txResp.Code)
s.Require().Contains(txResp.RawLog, tc.rawLogContains)
}
})
}
}
func NewCoin(denom string, amount sdk.Int) *sdk.Coin {
coin := sdk.NewCoin(denom, amount)
return &coin

View File

@ -1,8 +1,6 @@
package types
import (
"reflect"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authz "github.com/cosmos/cosmos-sdk/x/authz/exported"
@ -21,26 +19,25 @@ func NewSendAuthorization(spendLimit sdk.Coins) *SendAuthorization {
// MethodName implements Authorization.MethodName.
func (authorization SendAuthorization) MethodName() string {
return "/cosmos.bank.v1beta1.Msg/Send"
return sdk.MsgTypeURL(&MsgSend{})
}
// Accept implements Authorization.Accept.
func (authorization SendAuthorization) Accept(ctx sdk.Context, msg sdk.ServiceMsg) (updated authz.Authorization, delete bool, err error) {
if reflect.TypeOf(msg.Request) == reflect.TypeOf(&MsgSend{}) {
msg, ok := msg.Request.(*MsgSend)
if ok {
limitLeft, isNegative := authorization.SpendLimit.SafeSub(msg.Amount)
if isNegative {
return nil, false, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "requested amount is more than spend limit")
}
if limitLeft.IsZero() {
return nil, true, nil
}
return &SendAuthorization{SpendLimit: limitLeft}, false, nil
}
func (authorization SendAuthorization) Accept(_ sdk.Context, msg sdk.Msg) (updated authz.Authorization, delete bool, err error) {
msgSend, ok := msg.(*MsgSend)
if !ok {
return nil, false, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "type mismatch")
}
return nil, false, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "type mismatch")
limitLeft, isNegative := authorization.SpendLimit.SafeSub(msgSend.Amount)
if isNegative {
return nil, false, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "requested amount is more than spend limit")
}
if limitLeft.IsZero() {
return nil, true, nil
}
return &SendAuthorization{SpendLimit: limitLeft}, false, nil
}
// ValidateBasic implements Authorization.ValidateBasic.

View File

@ -24,31 +24,24 @@ func TestSendAuthorization(t *testing.T) {
authorization := types.NewSendAuthorization(coins1000)
t.Log("verify authorization returns valid method name")
require.Equal(t, authorization.MethodName(), "/cosmos.bank.v1beta1.Msg/Send")
require.Equal(t, authorization.MethodName(), "/cosmos.bank.v1beta1.MsgSend")
require.NoError(t, authorization.ValidateBasic())
send := types.NewMsgSend(fromAddr, toAddr, coins1000)
srvMsg := sdk.ServiceMsg{
MethodName: "/cosmos.bank.v1beta1.Msg/Send",
Request: send,
}
require.NoError(t, authorization.ValidateBasic())
t.Log("verify updated authorization returns nil")
updated, del, err := authorization.Accept(ctx, srvMsg)
updated, del, err := authorization.Accept(ctx, send)
require.NoError(t, err)
require.True(t, del)
require.Nil(t, updated)
authorization = types.NewSendAuthorization(coins1000)
require.Equal(t, authorization.MethodName(), "/cosmos.bank.v1beta1.Msg/Send")
require.Equal(t, authorization.MethodName(), "/cosmos.bank.v1beta1.MsgSend")
require.NoError(t, authorization.ValidateBasic())
send = types.NewMsgSend(fromAddr, toAddr, coins500)
srvMsg = sdk.ServiceMsg{
MethodName: "/cosmos.bank.v1beta1.Msg/Send",
Request: send,
}
require.NoError(t, authorization.ValidateBasic())
updated, del, err = authorization.Accept(ctx, srvMsg)
updated, del, err = authorization.Accept(ctx, send)
t.Log("verify updated authorization returns remaining spent limit")
require.NoError(t, err)
@ -58,7 +51,7 @@ func TestSendAuthorization(t *testing.T) {
require.Equal(t, sendAuth.String(), updated.String())
t.Log("expect updated authorization nil after spending remaining amount")
updated, del, err = updated.Accept(ctx, srvMsg)
updated, del, err = updated.Accept(ctx, send)
require.NoError(t, err)
require.True(t, del)
require.Nil(t, updated)

View File

@ -8,6 +8,7 @@ import (
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
"github.com/cosmos/cosmos-sdk/x/evidence/exported"
"github.com/cosmos/cosmos-sdk/x/evidence/types"
)
@ -50,8 +51,8 @@ func TestMsgSubmitEvidence(t *testing.T) {
}
for i, tc := range testCases {
require.Equal(t, tc.msg.Route(), types.RouterKey, "unexpected result for tc #%d", i)
require.Equal(t, tc.msg.Type(), types.TypeMsgSubmitEvidence, "unexpected result for tc #%d", i)
require.Equal(t, tc.msg.(legacytx.LegacyMsg).Route(), types.RouterKey, "unexpected result for tc #%d", i)
require.Equal(t, tc.msg.(legacytx.LegacyMsg).Type(), types.TypeMsgSubmitEvidence, "unexpected result for tc #%d", i)
require.Equal(t, tc.expectErr, tc.msg.ValidateBasic() != nil, "unexpected result for tc #%d", i)
if !tc.expectErr {

View File

@ -58,7 +58,7 @@ Examples:
%s tx %s grant cosmos1skjw... cosmos1skjw... --spend-limit 100stake --expiration 2022-01-30T15:04:05Z or
%s tx %s grant cosmos1skjw... cosmos1skjw... --spend-limit 100stake --period 3600 --period-limit 10stake --expiration 36000 or
%s tx %s grant cosmos1skjw... cosmos1skjw... --spend-limit 100stake --expiration 2022-01-30T15:04:05Z
--allowed-messages "/cosmos.gov.v1beta1.Msg/SubmitProposal,/cosmos.gov.v1beta1.Msg/Vote"
--allowed-messages "/cosmos.gov.v1beta1.MsgSubmitProposal,/cosmos.gov.v1beta1.MsgVote"
`, version.AppName, types.ModuleName, version.AppName, types.ModuleName, version.AppName, types.ModuleName,
),
),

View File

@ -2,6 +2,7 @@ package testutil
import (
"fmt"
"strings"
"testing"
"time"
@ -649,7 +650,7 @@ func (s *IntegrationTestSuite) TestFilteredFeeAllowance() {
}
spendLimit := sdk.NewCoin("stake", sdk.NewInt(1000))
allowMsgs := "/cosmos.gov.v1beta1.Msg/SubmitProposal,weighted_vote"
allowMsgs := strings.Join([]string{sdk.MsgTypeURL(&govtypes.MsgSubmitProposal{}), sdk.MsgTypeURL(&govtypes.MsgVoteWeighted{})}, ",")
testCases := []struct {
name string

View File

@ -52,7 +52,7 @@ func generateRandomAllowances(granter, grantee sdk.AccAddress, r *rand.Rand) typ
filteredAllowance, err := types.NewFeeAllowanceGrant(granter, grantee, &types.AllowedMsgFeeAllowance{
Allowance: basicAllowance.GetAllowance(),
AllowedMessages: []string{"/cosmos.gov.v1beta1.Msg/SubmitProposal"},
AllowedMessages: []string{"/cosmos.gov.v1beta1.MsgSubmitProposal"},
})
if err != nil {
panic(err)

View File

@ -21,8 +21,11 @@ import (
const (
OpWeightMsgGrantFeeAllowance = "op_weight_msg_grant_fee_allowance"
OpWeightMsgRevokeFeeAllowance = "op_weight_msg_grant_revoke_allowance"
TypeMsgGrantFeeAllowance = "/cosmos.feegrant.v1beta1.Msg/GrantFeeAllowance"
TypeMsgRevokeFeeAllowance = "/cosmos.feegrant.v1beta1.Msg/RevokeFeeAllowance"
)
var (
TypeMsgGrantFeeAllowance = sdk.MsgTypeURL(&types.MsgGrantFeeAllowance{})
TypeMsgRevokeFeeAllowance = sdk.MsgTypeURL(&types.MsgRevokeFeeAllowance{})
)
func WeightedOperations(
@ -121,7 +124,7 @@ func SimulateMsgGrantFeeAllowance(ak types.AccountKeeper, bk types.BankKeeper, k
_, _, err = app.Deliver(txGen.TxEncoder(), tx)
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, svcMsgClientConn.GetMsgs()[0].Type(), "unable to deliver tx"), nil, err
return simtypes.NoOpMsg(types.ModuleName, sdk.MsgTypeURL(svcMsgClientConn.GetMsgs()[0]), "unable to deliver tx"), nil, err
}
return simtypes.NewOperationMsg(svcMsgClientConn.GetMsgs()[0], true, "", protoCdc), nil, err
}

View File

@ -8,7 +8,7 @@ import (
// RegisterInterfaces registers the interfaces types with the interface registry
func RegisterInterfaces(registry types.InterfaceRegistry) {
registry.RegisterImplementations((*sdk.MsgRequest)(nil),
registry.RegisterImplementations((*sdk.Msg)(nil),
&MsgGrantFeeAllowance{},
&MsgRevokeFeeAllowance{},
)

View File

@ -80,7 +80,7 @@ func (a *AllowedMsgFeeAllowance) allMsgTypesAllowed(ctx sdk.Context, msgs []sdk.
for _, msg := range msgs {
ctx.GasMeter().ConsumeGas(gasCostPerIteration, "check msg")
if !msgsMap[msg.Type()] {
if !msgsMap[sdk.MsgTypeURL(msg)] {
return false
}
}

View File

@ -9,7 +9,7 @@ import (
)
var (
_, _ sdk.MsgRequest = &MsgGrantFeeAllowance{}, &MsgRevokeFeeAllowance{}
_, _ sdk.Msg = &MsgGrantFeeAllowance{}, &MsgRevokeFeeAllowance{}
_ types.UnpackInterfacesMessage = &MsgGrantFeeAllowance{}
)

View File

@ -15,6 +15,7 @@ import (
"github.com/cosmos/cosmos-sdk/testutil"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
"github.com/cosmos/cosmos-sdk/x/staking/types"
@ -84,7 +85,7 @@ func (s *IntegrationTestSuite) TestGenTxCmd() {
msgs := tx.GetMsgs()
s.Require().Len(msgs, 1)
s.Require().Equal(types.TypeMsgCreateValidator, msgs[0].Type())
s.Require().Equal(types.TypeMsgCreateValidator, msgs[0].(legacytx.LegacyMsg).Type())
s.Require().Equal([]sdk.AccAddress{val.Address}, msgs[0].GetSigners())
s.Require().Equal(amount, msgs[0].(*types.MsgCreateValidator).Value)
err = tx.ValidateBasic()

View File

@ -39,14 +39,14 @@ func (p Proposer) String() string {
func QueryDepositsByTxQuery(clientCtx client.Context, params types.QueryProposalParams) ([]byte, error) {
searchResult, err := combineEvents(
clientCtx, defaultPage,
// Query old Msgs
// Query legacy Msgs event action
[]string{
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgDeposit),
fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalDeposit, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))),
},
// Query service Msgs
// Query proto Msgs event action
[]string{
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeSvcMsgDeposit),
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgDeposit{})),
fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalDeposit, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))),
},
)
@ -58,14 +58,7 @@ func QueryDepositsByTxQuery(clientCtx client.Context, params types.QueryProposal
for _, info := range searchResult.Txs {
for _, msg := range info.GetTx().GetMsgs() {
var depMsg *types.MsgDeposit
if msg.Type() == types.TypeSvcMsgDeposit {
depMsg = msg.(sdk.ServiceMsg).Request.(*types.MsgDeposit)
} else if protoDepMsg, ok := msg.(*types.MsgDeposit); ok {
depMsg = protoDepMsg
}
if depMsg != nil {
if depMsg, ok := msg.(*types.MsgDeposit); ok {
deposits = append(deposits, types.Deposit{
Depositor: depMsg.Depositor,
ProposalId: params.ProposalID,
@ -95,27 +88,27 @@ func QueryVotesByTxQuery(clientCtx client.Context, params types.QueryProposalVot
// query interrupted either if we collected enough votes or tx indexer run out of relevant txs
for len(votes) < totalLimit {
// Search for both (old) votes and weighted votes.
// Search for both (legacy) votes and weighted votes.
searchResult, err := combineEvents(
clientCtx, nextTxPage,
// Query old Vote Msgs
// Query legacy Vote Msgs
[]string{
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgVote),
fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalVote, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))),
},
// Query Vote service Msgs
// Query Vote proto Msgs
[]string{
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeSvcMsgVote),
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgVote{})),
fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalVote, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))),
},
// Query old VoteWeighted Msgs
// Query legacy VoteWeighted Msgs
[]string{
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgVoteWeighted),
fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalVote, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))),
},
// Query VoteWeighted service Msgs
// Query VoteWeighted proto Msgs
[]string{
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeSvcMsgVoteWeighted),
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgVoteWeighted{})),
fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalVote, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))),
},
)
@ -125,14 +118,7 @@ func QueryVotesByTxQuery(clientCtx client.Context, params types.QueryProposalVot
for _, info := range searchResult.Txs {
for _, msg := range info.GetTx().GetMsgs() {
var voteMsg *types.MsgVote
if msg.Type() == types.TypeSvcMsgVote {
voteMsg = msg.(sdk.ServiceMsg).Request.(*types.MsgVote)
} else if protoVoteMsg, ok := msg.(*types.MsgVote); ok {
voteMsg = protoVoteMsg
}
if voteMsg != nil {
if voteMsg, ok := msg.(*types.MsgVote); ok {
votes = append(votes, types.Vote{
Voter: voteMsg.Voter,
ProposalId: params.ProposalID,
@ -140,14 +126,7 @@ func QueryVotesByTxQuery(clientCtx client.Context, params types.QueryProposalVot
})
}
var voteWeightedMsg *types.MsgVoteWeighted
if msg.Type() == types.TypeSvcMsgVoteWeighted {
voteWeightedMsg = msg.(sdk.ServiceMsg).Request.(*types.MsgVoteWeighted)
} else if protoVoteWeightedMsg, ok := msg.(*types.MsgVoteWeighted); ok {
voteWeightedMsg = protoVoteWeightedMsg
}
if voteWeightedMsg != nil {
if voteWeightedMsg, ok := msg.(*types.MsgVoteWeighted); ok {
votes = append(votes, types.Vote{
Voter: voteWeightedMsg.Voter,
ProposalId: params.ProposalID,
@ -181,27 +160,27 @@ func QueryVotesByTxQuery(clientCtx client.Context, params types.QueryProposalVot
func QueryVoteByTxQuery(clientCtx client.Context, params types.QueryVoteParams) ([]byte, error) {
searchResult, err := combineEvents(
clientCtx, defaultPage,
// Query old Vote Msgs
// Query legacy Vote Msgs
[]string{
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgVote),
fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalVote, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))),
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, []byte(params.Voter.String())),
},
// Query Vote service Msgs
// Query Vote proto Msgs
[]string{
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeSvcMsgVote),
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgVote{})),
fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalVote, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))),
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, []byte(params.Voter.String())),
},
// Query old VoteWeighted Msgs
// Query legacy VoteWeighted Msgs
[]string{
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgVoteWeighted),
fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalVote, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))),
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, []byte(params.Voter.String())),
},
// Query VoteWeighted service Msgs
// Query VoteWeighted proto Msgs
[]string{
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeSvcMsgVoteWeighted),
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgVoteWeighted{})),
fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalVote, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))),
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, []byte(params.Voter.String())),
},
@ -212,37 +191,26 @@ func QueryVoteByTxQuery(clientCtx client.Context, params types.QueryVoteParams)
for _, info := range searchResult.Txs {
for _, msg := range info.GetTx().GetMsgs() {
var voteMsg *types.MsgVote
// there should only be a single vote under the given conditions
if msg.Type() == types.TypeSvcMsgVote {
voteMsg = msg.(sdk.ServiceMsg).Request.(*types.MsgVote)
} else if protoVoteMsg, ok := msg.(*types.MsgVote); ok {
voteMsg = protoVoteMsg
}
if voteMsg != nil {
vote := types.Vote{
var vote *types.Vote
if voteMsg, ok := msg.(*types.MsgVote); ok {
vote = &types.Vote{
Voter: voteMsg.Voter,
ProposalId: params.ProposalID,
Options: types.NewNonSplitVoteOption(voteMsg.Option),
}
}
bz, err := clientCtx.JSONMarshaler.MarshalJSON(&vote)
if err != nil {
return nil, err
}
return bz, nil
} else if msg.Type() == types.TypeMsgVoteWeighted {
voteMsg := msg.(*types.MsgVoteWeighted)
vote := types.Vote{
Voter: voteMsg.Voter,
if voteWeightedMsg, ok := msg.(*types.MsgVoteWeighted); ok {
vote = &types.Vote{
Voter: voteWeightedMsg.Voter,
ProposalId: params.ProposalID,
Options: voteMsg.Options,
Options: voteWeightedMsg.Options,
}
}
bz, err := clientCtx.JSONMarshaler.MarshalJSON(&vote)
if vote != nil {
bz, err := clientCtx.JSONMarshaler.MarshalJSON(vote)
if err != nil {
return nil, err
}
@ -260,15 +228,15 @@ func QueryVoteByTxQuery(clientCtx client.Context, params types.QueryVoteParams)
func QueryDepositByTxQuery(clientCtx client.Context, params types.QueryDepositParams) ([]byte, error) {
searchResult, err := combineEvents(
clientCtx, defaultPage,
// Query old Msgs
// Query legacy Msgs event action
[]string{
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgDeposit),
fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalDeposit, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))),
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, []byte(params.Depositor.String())),
},
// Query service Msgs
// Query proto Msgs event action
[]string{
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeSvcMsgDeposit),
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgDeposit{})),
fmt.Sprintf("%s.%s='%s'", types.EventTypeProposalDeposit, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", params.ProposalID))),
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeySender, []byte(params.Depositor.String())),
},
@ -279,15 +247,8 @@ func QueryDepositByTxQuery(clientCtx client.Context, params types.QueryDepositPa
for _, info := range searchResult.Txs {
for _, msg := range info.GetTx().GetMsgs() {
var depMsg *types.MsgDeposit
// there should only be a single deposit under the given conditions
if msg.Type() == types.TypeSvcMsgDeposit {
depMsg = msg.(sdk.ServiceMsg).Request.(*types.MsgDeposit)
} else if protoDepMsg, ok := msg.(*types.MsgDeposit); ok {
depMsg = protoDepMsg
}
if depMsg != nil {
if depMsg, ok := msg.(*types.MsgDeposit); ok {
deposit := types.Deposit{
Depositor: depMsg.Depositor,
ProposalId: params.ProposalID,
@ -313,14 +274,14 @@ func QueryProposerByTxQuery(clientCtx client.Context, proposalID uint64) (Propos
searchResult, err := combineEvents(
clientCtx,
defaultPage,
// Query old Msgs
// Query legacy Msgs event action
[]string{
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeMsgSubmitProposal),
fmt.Sprintf("%s.%s='%s'", types.EventTypeSubmitProposal, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", proposalID))),
},
// Query service Msgs
// Query proto Msgs event action
[]string{
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, types.TypeSvcMsgSubmitProposal),
fmt.Sprintf("%s.%s='%s'", sdk.EventTypeMessage, sdk.AttributeKeyAction, sdk.MsgTypeURL(&types.MsgSubmitProposal{})),
fmt.Sprintf("%s.%s='%s'", types.EventTypeSubmitProposal, types.AttributeKeyProposalID, []byte(fmt.Sprintf("%d", proposalID))),
},
)
@ -331,13 +292,7 @@ func QueryProposerByTxQuery(clientCtx client.Context, proposalID uint64) (Propos
for _, info := range searchResult.Txs {
for _, msg := range info.GetTx().GetMsgs() {
// there should only be a single proposal under the given conditions
if msg.Type() == types.TypeSvcMsgSubmitProposal {
subMsg := msg.(sdk.ServiceMsg).Request.(*types.MsgSubmitProposal)
return NewProposer(proposalID, subMsg.Proposer), nil
} else if protoSubMsg, ok := msg.(*types.MsgSubmitProposal); ok {
subMsg := protoSubMsg
if subMsg, ok := msg.(*types.MsgSubmitProposal); ok {
return NewProposer(proposalID, subMsg.Proposer), nil
}
}
@ -367,7 +322,7 @@ func QueryProposalByID(proposalID uint64, clientCtx client.Context, queryRoute s
//
// Tx are indexed in tendermint via their Msgs `Type()`, which can be:
// - via legacy Msgs (amino or proto), their `Type()` is a custom string,
// - via ADR-031 service msgs, their `Type()` is the protobuf FQ method name.
// - via ADR-031 proto msgs, their `Type()` is the protobuf FQ method name.
// In searching for events, we search for both `Type()`s, and we use the
// `combineEvents` function here to merge events.
func combineEvents(clientCtx client.Context, page int, eventGroups ...[]string) (*sdk.SearchTxsResult, error) {

View File

@ -13,6 +13,7 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
"github.com/cosmos/cosmos-sdk/x/gov/client/utils"
"github.com/cosmos/cosmos-sdk/x/gov/types"
)
@ -44,7 +45,7 @@ func (mock TxSearchMock) TxSearch(ctx context.Context, query string, prove bool,
return nil, err
}
for _, msg := range sdkTx.GetMsgs() {
if msg.Type() == msgType {
if msg.(legacytx.LegacyMsg).Type() == msgType {
matchingTxs = append(matchingTxs, tx)
break
}

View File

@ -18,12 +18,6 @@ const (
TypeMsgVote = "vote"
TypeMsgVoteWeighted = "weighted_vote"
TypeMsgSubmitProposal = "submit_proposal"
// These are used for querying events by action.
TypeSvcMsgDeposit = "/cosmos.gov.v1beta1.Msg/Deposit"
TypeSvcMsgVote = "/cosmos.gov.v1beta1.Msg/Vote"
TypeSvcMsgVoteWeighted = "/cosmos.gov.v1beta1.Msg/VoteWeighted"
TypeSvcMsgSubmitProposal = "/cosmos.gov.v1beta1.Msg/SubmitProposal"
)
var (

View File

@ -153,28 +153,22 @@ func delegatorTxsHandlerFn(clientCtx client.Context) http.HandlerFunc {
// For each case, we search txs for both:
// - legacy messages: their Type() is a custom string, e.g. "delegate"
// - service Msgs: their Type() is their FQ method name, e.g. "/cosmos.staking.v1beta1.Msg/Delegate"
// - service Msgs: their Type() is their FQ method name, e.g. "/cosmos.staking.v1beta1.MsgDelegate"
// and we combine the results.
switch {
case isBondTx:
actions = append(actions, types.TypeMsgDelegate)
actions = append(actions, types.TypeSvcMsgDelegate)
case isUnbondTx:
actions = append(actions, types.TypeMsgUndelegate)
actions = append(actions, types.TypeSvcMsgUndelegate)
case isRedTx:
actions = append(actions, types.TypeMsgBeginRedelegate)
actions = append(actions, types.TypeSvcMsgBeginRedelegate)
case noQuery:
actions = append(actions, types.TypeMsgDelegate)
actions = append(actions, types.TypeSvcMsgDelegate)
actions = append(actions, types.TypeMsgUndelegate)
actions = append(actions, types.TypeSvcMsgUndelegate)
actions = append(actions, types.TypeMsgBeginRedelegate)
actions = append(actions, types.TypeSvcMsgBeginRedelegate)
default:
w.WriteHeader(http.StatusNoContent)

View File

@ -12,10 +12,6 @@ const gasCostPerIteration = uint64(10)
var (
_ authz.Authorization = &StakeAuthorization{}
TypeDelegate = "/cosmos.staking.v1beta1.Msg/Delegate"
TypeUndelegate = "/cosmos.staking.v1beta1.Msg/Undelegate"
TypeBeginRedelegate = "/cosmos.staking.v1beta1.Msg/BeginRedelegate"
)
// NewStakeAuthorization creates a new StakeAuthorization object.
@ -61,11 +57,11 @@ func (authorization StakeAuthorization) ValidateBasic() error {
}
// Accept implements Authorization.Accept.
func (authorization StakeAuthorization) Accept(ctx sdk.Context, msg sdk.ServiceMsg) (updated authz.Authorization, delete bool, err error) {
func (authorization StakeAuthorization) Accept(ctx sdk.Context, msg sdk.Msg) (updated authz.Authorization, delete bool, err error) {
var validatorAddress string
var amount sdk.Coin
switch msg := msg.Request.(type) {
switch msg := msg.(type) {
case *MsgDelegate:
validatorAddress = msg.ValidatorAddress
amount = msg.Amount
@ -142,11 +138,11 @@ func validateAndBech32fy(allowed []sdk.ValAddress, denied []sdk.ValAddress) ([]s
func normalizeAuthzType(authzType AuthorizationType) (string, error) {
switch authzType {
case AuthorizationType_AUTHORIZATION_TYPE_DELEGATE:
return TypeDelegate, nil
return sdk.MsgTypeURL(&MsgDelegate{}), nil
case AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE:
return TypeUndelegate, nil
return sdk.MsgTypeURL(&MsgUndelegate{}), nil
case AuthorizationType_AUTHORIZATION_TYPE_REDELEGATE:
return TypeBeginRedelegate, nil
return sdk.MsgTypeURL(&MsgBeginRedelegate{}), nil
default:
return "", sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "unknown authorization type %T", authzType)
}

View File

@ -3,9 +3,8 @@ package types_test
import (
"testing"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/stretchr/testify/require"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -33,7 +32,7 @@ func TestAuthzAuthorizations(t *testing.T) {
// verify MethodName
delAuth, err = stakingtypes.NewStakeAuthorization([]sdk.ValAddress{val1, val2}, []sdk.ValAddress{}, stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, &coin100)
require.NoError(t, err)
require.Equal(t, delAuth.MethodName(), stakingtypes.TypeDelegate)
require.Equal(t, delAuth.MethodName(), sdk.MsgTypeURL(&stakingtypes.MsgDelegate{}))
// error both allow & deny list
_, err = stakingtypes.NewStakeAuthorization([]sdk.ValAddress{val1, val2}, []sdk.ValAddress{val1}, stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE, &coin100)
@ -41,11 +40,11 @@ func TestAuthzAuthorizations(t *testing.T) {
// verify MethodName
undelAuth, _ := stakingtypes.NewStakeAuthorization([]sdk.ValAddress{val1, val2}, []sdk.ValAddress{}, stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE, &coin100)
require.Equal(t, undelAuth.MethodName(), stakingtypes.TypeUndelegate)
require.Equal(t, undelAuth.MethodName(), sdk.MsgTypeURL(&stakingtypes.MsgUndelegate{}))
// verify MethodName
beginRedelAuth, _ := stakingtypes.NewStakeAuthorization([]sdk.ValAddress{val1, val2}, []sdk.ValAddress{}, stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_REDELEGATE, &coin100)
require.Equal(t, beginRedelAuth.MethodName(), stakingtypes.TypeBeginRedelegate)
require.Equal(t, beginRedelAuth.MethodName(), sdk.MsgTypeURL(&stakingtypes.MsgBeginRedelegate{}))
validators1_2 := []string{val1.String(), val2.String()}
@ -55,7 +54,7 @@ func TestAuthzAuthorizations(t *testing.T) {
denied []sdk.ValAddress
msgType stakingtypes.AuthorizationType
limit *sdk.Coin
srvMsg sdk.ServiceMsg
srvMsg sdk.Msg
expectErr bool
isDelete bool
updatedAuthorization *stakingtypes.StakeAuthorization
@ -66,7 +65,7 @@ func TestAuthzAuthorizations(t *testing.T) {
[]sdk.ValAddress{},
stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE,
&coin100,
createSrvMsgDelegate(delAuth.MethodName(), delAddr, val1, coin100),
stakingtypes.NewMsgDelegate(delAddr, val1, coin100),
false,
true,
nil,
@ -77,7 +76,7 @@ func TestAuthzAuthorizations(t *testing.T) {
[]sdk.ValAddress{},
stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE,
&coin100,
createSrvMsgDelegate(delAuth.MethodName(), delAddr, val1, coin50),
stakingtypes.NewMsgDelegate(delAddr, val1, coin50),
false,
false,
&stakingtypes.StakeAuthorization{
@ -91,7 +90,7 @@ func TestAuthzAuthorizations(t *testing.T) {
[]sdk.ValAddress{},
stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE,
&coin100,
createSrvMsgDelegate(delAuth.MethodName(), delAddr, val3, coin100),
stakingtypes.NewMsgDelegate(delAddr, val3, coin100),
true,
false,
nil,
@ -102,7 +101,7 @@ func TestAuthzAuthorizations(t *testing.T) {
[]sdk.ValAddress{},
stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE,
nil,
createSrvMsgDelegate(delAuth.MethodName(), delAddr, val2, coin100),
stakingtypes.NewMsgDelegate(delAddr, val2, coin100),
false,
false,
&stakingtypes.StakeAuthorization{
@ -116,7 +115,7 @@ func TestAuthzAuthorizations(t *testing.T) {
[]sdk.ValAddress{val1},
stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_DELEGATE,
nil,
createSrvMsgDelegate(delAuth.MethodName(), delAddr, val1, coin100),
stakingtypes.NewMsgDelegate(delAddr, val1, coin100),
true,
false,
nil,
@ -128,7 +127,7 @@ func TestAuthzAuthorizations(t *testing.T) {
[]sdk.ValAddress{},
stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE,
&coin100,
createSrvMsgUndelegate(undelAuth.MethodName(), delAddr, val1, coin100),
stakingtypes.NewMsgUndelegate(delAddr, val1, coin100),
false,
true,
nil,
@ -139,7 +138,7 @@ func TestAuthzAuthorizations(t *testing.T) {
[]sdk.ValAddress{},
stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE,
&coin100,
createSrvMsgUndelegate(undelAuth.MethodName(), delAddr, val1, coin50),
stakingtypes.NewMsgUndelegate(delAddr, val1, coin50),
false,
false,
&stakingtypes.StakeAuthorization{
@ -153,7 +152,7 @@ func TestAuthzAuthorizations(t *testing.T) {
[]sdk.ValAddress{},
stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE,
&coin100,
createSrvMsgUndelegate(undelAuth.MethodName(), delAddr, val3, coin100),
stakingtypes.NewMsgUndelegate(delAddr, val3, coin100),
true,
false,
nil,
@ -164,7 +163,7 @@ func TestAuthzAuthorizations(t *testing.T) {
[]sdk.ValAddress{},
stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE,
nil,
createSrvMsgUndelegate(undelAuth.MethodName(), delAddr, val2, coin100),
stakingtypes.NewMsgUndelegate(delAddr, val2, coin100),
false,
false,
&stakingtypes.StakeAuthorization{
@ -178,7 +177,7 @@ func TestAuthzAuthorizations(t *testing.T) {
[]sdk.ValAddress{val1},
stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_UNDELEGATE,
&coin100,
createSrvMsgUndelegate(undelAuth.MethodName(), delAddr, val1, coin100),
stakingtypes.NewMsgUndelegate(delAddr, val1, coin100),
true,
false,
nil,
@ -190,7 +189,7 @@ func TestAuthzAuthorizations(t *testing.T) {
[]sdk.ValAddress{},
stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_REDELEGATE,
&coin100,
createSrvMsgUndelegate(undelAuth.MethodName(), delAddr, val1, coin100),
stakingtypes.NewMsgUndelegate(delAddr, val1, coin100),
false,
true,
nil,
@ -201,7 +200,7 @@ func TestAuthzAuthorizations(t *testing.T) {
[]sdk.ValAddress{},
stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_REDELEGATE,
&coin100,
createSrvMsgReDelegate(undelAuth.MethodName(), delAddr, val1, coin50),
stakingtypes.NewMsgBeginRedelegate(delAddr, val1, val1, coin50),
false,
false,
&stakingtypes.StakeAuthorization{
@ -215,7 +214,7 @@ func TestAuthzAuthorizations(t *testing.T) {
[]sdk.ValAddress{},
stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_REDELEGATE,
&coin100,
createSrvMsgReDelegate(undelAuth.MethodName(), delAddr, val3, coin100),
stakingtypes.NewMsgBeginRedelegate(delAddr, val3, val3, coin100),
true,
false,
nil,
@ -226,7 +225,7 @@ func TestAuthzAuthorizations(t *testing.T) {
[]sdk.ValAddress{},
stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_REDELEGATE,
nil,
createSrvMsgReDelegate(undelAuth.MethodName(), delAddr, val2, coin100),
stakingtypes.NewMsgBeginRedelegate(delAddr, val2, val2, coin100),
false,
false,
&stakingtypes.StakeAuthorization{
@ -240,7 +239,7 @@ func TestAuthzAuthorizations(t *testing.T) {
[]sdk.ValAddress{val1},
stakingtypes.AuthorizationType_AUTHORIZATION_TYPE_REDELEGATE,
&coin100,
createSrvMsgReDelegate(undelAuth.MethodName(), delAddr, val1, coin100),
stakingtypes.NewMsgBeginRedelegate(delAddr, val1, val1, coin100),
true,
false,
nil,
@ -266,27 +265,3 @@ func TestAuthzAuthorizations(t *testing.T) {
})
}
}
func createSrvMsgUndelegate(methodName string, delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount sdk.Coin) sdk.ServiceMsg {
msg := stakingtypes.NewMsgUndelegate(delAddr, valAddr, amount)
return sdk.ServiceMsg{
MethodName: methodName,
Request: msg,
}
}
func createSrvMsgReDelegate(methodName string, delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount sdk.Coin) sdk.ServiceMsg {
msg := stakingtypes.NewMsgBeginRedelegate(delAddr, valAddr, valAddr, amount)
return sdk.ServiceMsg{
MethodName: methodName,
Request: msg,
}
}
func createSrvMsgDelegate(methodName string, delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount sdk.Coin) sdk.ServiceMsg {
msg := stakingtypes.NewMsgDelegate(delAddr, valAddr, amount)
return sdk.ServiceMsg{
MethodName: methodName,
Request: msg,
}
}

View File

@ -16,13 +16,6 @@ const (
TypeMsgCreateValidator = "create_validator"
TypeMsgDelegate = "delegate"
TypeMsgBeginRedelegate = "begin_redelegate"
// These are used for querying events by action.
TypeSvcMsgUndelegate = "/cosmos.staking.v1beta1.Msg/Undelegate"
TypeSvcMsgEditValidator = "/cosmos.staking.v1beta1.Msg/EditValidator"
TypeSvcMsgCreateValidator = "/cosmos.staking.v1beta1.Msg/CreateValidator"
TypeSvcMsgDelegate = "/cosmos.staking.v1beta1.Msg/Delegate"
TypeSvcMsgBeginRedelegate = "/cosmos.staking.v1beta1.Msg/BeginRedelegate"
)
var (