Skip to content

Commit

Permalink
feat(core/handlers): improve handlers registration DevX (#22007)
Browse files Browse the repository at this point in the history
  • Loading branch information
testinginprod authored Oct 1, 2024
1 parent a0f9693 commit a3729c1
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 18 deletions.
50 changes: 34 additions & 16 deletions core/appmodule/v2/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ import (
type (
// PreMsgHandler is a handler that is executed before Handler. If it errors the execution reverts.
PreMsgHandler = func(ctx context.Context, msg transaction.Msg) error
// Handler handles the state transition of the provided message.
Handler = func(ctx context.Context, msg transaction.Msg) (msgResp transaction.Msg, err error)
// HandlerFunc handles the state transition of the provided message.
HandlerFunc = func(ctx context.Context, msg transaction.Msg) (msgResp transaction.Msg, err error)
// PostMsgHandler runs after Handler, only if Handler does not error. If PostMsgHandler errors
// then the execution is reverted.
PostMsgHandler = func(ctx context.Context, msg, msgResp transaction.Msg) error
)

// PreMsgRouter is a router that allows you to register PreMsgHandlers for specific message types.
type PreMsgRouter interface {
// RegisterPreHandler will register a specific message handler hooking into the message with
// RegisterPreMsgHandler will register a specific message handler hooking into the message with
// the provided name.
RegisterPreMsgHandler(msgName string, handler PreMsgHandler)
// RegisterGlobalPreHandler will register a global message handler hooking into any message
// RegisterGlobalPreMsgHandler will register a global message handler hooking into any message
// being executed.
RegisterGlobalPreMsgHandler(handler PreMsgHandler)
}
Expand Down Expand Up @@ -64,10 +64,10 @@ func RegisterMsgPreHandler[Req transaction.Msg](

// PostMsgRouter is a router that allows you to register PostMsgHandlers for specific message types.
type PostMsgRouter interface {
// RegisterPostHandler will register a specific message handler hooking after the execution of message with
// RegisterPostMsgHandler will register a specific message handler hooking after the execution of message with
// the provided name.
RegisterPostMsgHandler(msgName string, handler PostMsgHandler)
// RegisterGlobalPostHandler will register a global message handler hooking after the execution of any message.
// RegisterGlobalPostMsgHandler will register a global message handler hooking after the execution of any message.
RegisterGlobalPostMsgHandler(handler PostMsgHandler)
}

Expand All @@ -76,7 +76,7 @@ type HasPostMsgHandlers interface {
RegisterPostMsgHandlers(router PostMsgRouter)
}

// RegisterPostHandler is a helper function that modules can use to not lose type safety when registering handlers to the
// RegisterPostMsgHandler is a helper function that modules can use to not lose type safety when registering handlers to the
// PostMsgRouter. Example usage:
// ```go
//
Expand Down Expand Up @@ -110,9 +110,20 @@ func RegisterPostMsgHandler[Req, Resp transaction.Msg](
router.RegisterPostMsgHandler(msgName, untypedHandler)
}

// Handler defines a handler descriptor.
type Handler struct {
// Func defines the actual handler, the function that runs a request and returns a response.
// Can be query handler or msg handler.
Func HandlerFunc
// MakeMsg instantiates the type of the request, can be used in decoding contexts.
MakeMsg func() transaction.Msg
// MakeMsgResp instantiates a new response, can be used in decoding contexts.
MakeMsgResp func() transaction.Msg
}

// MsgRouter is a router that allows you to register Handlers for specific message types.
type MsgRouter = interface {
RegisterHandler(msgName string, handler Handler) error
RegisterHandler(handler Handler)
}

// HasMsgHandlers is an interface that modules must implement if they want to register Handlers.
Expand Down Expand Up @@ -142,27 +153,34 @@ type HasQueryHandlers interface {
//
// func (m Module) RegisterMsgHandlers(router appmodule.MsgRouter) {
// handlers := keeper.NewHandlers(m.keeper)
// err := appmodule.RegisterHandler(router, gogoproto.MessageName(types.MsgMint{}), handlers.MsgMint)
// err := appmodule.RegisterHandler(router, handlers.MsgMint)
// }
//
// func (m Module) RegisterQueryHandlers(router appmodule.QueryRouter) {
// handlers := keeper.NewHandlers(m.keeper)
// err := appmodule.RegisterHandler(router, gogoproto.MessageName(types.QueryBalanceRequest{}), handlers.QueryBalance)
// err := appmodule.RegisterHandler(router, handlers.QueryBalance)
// }
//
// ```
func RegisterHandler[Req, Resp transaction.Msg](
func RegisterMsgHandler[Req, Resp any, PReq transaction.GenericMsg[Req], PResp transaction.GenericMsg[Resp]](
router MsgRouter,
msgName string,
handler func(ctx context.Context, msg Req) (msgResp Resp, err error),
) error {
handler func(ctx context.Context, msg PReq) (msgResp PResp, err error),
) {
untypedHandler := func(ctx context.Context, m transaction.Msg) (transaction.Msg, error) {
typed, ok := m.(Req)
typed, ok := m.(PReq)
if !ok {
return nil, fmt.Errorf("unexpected type %T, wanted: %T", m, *new(Req))
}
return handler(ctx, typed)
}

return router.RegisterHandler(msgName, untypedHandler)
router.RegisterHandler(Handler{
Func: untypedHandler,
MakeMsg: func() transaction.Msg {
return PReq(new(Req))
},
MakeMsgResp: func() transaction.Msg {
return PResp(new(Resp))
},
})
}
8 changes: 8 additions & 0 deletions core/transaction/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ type (
Identity = []byte
)

// GenericMsg defines a generic version of a Msg.
// The GenericMsg refers to the non pointer version of Msg,
// and is required to allow its instantiations in generic contexts.
type GenericMsg[T any] interface {
*T
Msg
}

// Codec defines the TX codec, which converts a TX from bytes to its concrete representation.
type Codec[T Tx] interface {
// Decode decodes the tx bytes into a DecodedTx, containing
Expand Down
3 changes: 1 addition & 2 deletions simapp/v2/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.23.1
require (
cosmossdk.io/api v0.7.6
cosmossdk.io/client/v2 v2.0.0-00010101000000-000000000000
cosmossdk.io/core v1.0.0-alpha.3
cosmossdk.io/core v1.0.0-alpha.3.0.20241001182821-3f9c9a087760
cosmossdk.io/depinject v1.0.0
cosmossdk.io/log v1.4.1
cosmossdk.io/math v1.3.0
Expand Down Expand Up @@ -291,7 +291,6 @@ replace (
// server v2 integration
replace (
cosmossdk.io/api => ../../api
cosmossdk.io/core => ../../core
cosmossdk.io/runtime/v2 => ../../runtime/v2
cosmossdk.io/server/v2 => ../../server/v2
cosmossdk.io/server/v2/appmanager => ../../server/v2/appmanager
Expand Down
2 changes: 2 additions & 0 deletions simapp/v2/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xX
cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg=
cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0=
cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M=
cosmossdk.io/core v1.0.0-alpha.3.0.20241001182821-3f9c9a087760 h1:jyldjo99XdhT94cIyoSVBT2hxNoI4X/1pEUh4+659e0=
cosmossdk.io/core v1.0.0-alpha.3.0.20241001182821-3f9c9a087760/go.mod h1:3u9cWq1FAVtiiCrDPpo4LhR+9V6k/ycSG4/Y/tREWCY=
cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29 h1:NxxUo0GMJUbIuVg0R70e3cbn9eFTEuMr7ev1AFvypdY=
cosmossdk.io/core/testing v0.0.0-20240923163230-04da382a9f29/go.mod h1:8s2tPeJtSiQuoyPmr2Ag7meikonISO4Fv4MoO8+ORrs=
cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050=
Expand Down

0 comments on commit a3729c1

Please sign in to comment.