-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove ServiceMsgs from ADR-031 #9139
Changes from all commits
f1398cb
b54d71f
03a358d
2a6223e
559fc54
f2d8355
d5c6ce9
569f777
19720e7
c52587c
aa30868
2919375
488dc62
72c0cbc
04ba707
5f543a4
6d1b1cc
16b72f1
d4130c2
5f4a19c
d5a2982
9743b9e
a323bff
14acc84
0e57b6f
0840c18
5cb4301
fc37733
5d1836b
fcaedf9
7904aef
b2bf609
77e20c2
3cac0e6
113ef64
1c3886d
09e81a2
7e05b80
68b7e5f
bb33c2b
c2a024d
f25b2c6
31e5c2a
d6ab3eb
3e7d3ae
2000ebf
a688c73
666fe92
aa2b26c
249f857
d2a8ae5
cd4bc02
774a4ab
d3c3381
98ad2b7
e95ae32
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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() | ||
Comment on lines
717
to
+723
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also a sanity check, ledger signed transactions would not end up here if there is a registered proto message? This would be because the difference between the transaction/message layer? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the modules in the SDK is this ever reached? Docs indicate that the handler type will be deprecated, but it seems like now all the SDK modules could remove their legacy There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For SDK modules, this is never reached. I just confirmed by adding a
That's also correct, but we're thinking a better |
||
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)) | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is there context available in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately not, sd is just a descriptor. |
||
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)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why we don't return an error? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we return an error, then the app will continue running, with potential encoding errors that are hard to debug down the road. |
||
} | ||
|
||
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] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. whenever I see it I always read FAQ method 🤣 |
||
_, 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 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
message.action
is very important for relayers as it is used to distinguish when the next message event starts/ends and what type of event is occurring. Relayers may be connected to chains on the old version and the new version and thus need to be aware of this change to ensure IBC continues to work between chains with different versionsDoes the
svcMsg.MethodName
!=sdk.MsgTypeURL(msg)
? Or is there no breaking change here for Msgs migrated to proto messages registered on a Msg service (which from my understanding is the case for the current IBC Msgs). I'm a little fuzzy on the exact differences between the legacy messages, the proto message req/resp types and the msg service router, so please excuse me if I used the terminology wrongThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's just confusing, to me too. I tried to simplify it like this:
In v0.42, these message.actions were emitted:
message.action='/cosmos.bank.v1beta1.Msg/Send'
if the user explicity sent aServiceMsg
tx (note the 2/
)message.action='send'
for all other messages (99% of the messages)After this PR:
message.action='/cosmos.bank.v1beta1.MsgSend'
(note only 1/
), so legacymessage.action='send'
are not emitted anymore (unless the app developer didn't wire up proto registration correctly). This is not retroactive though.Let me know if that works for IBC.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, thanks for the response! This makes sense. This should be fine for relayers, but it will likely require a small change. Relayer should now check for
message.action='send' || message.action='/cosmos.bank.v1beta1.MsgSend'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's the approach I'm taking too, e.g. if querying deposits here.