* add test of alternative impl * simplify query route too * change name querier * simplify register routes * revert change * add route * add router * first step refactor * refactor * update documentation * update * add format * simplify appmodule * update changelog * rename vars * remove interface * Update CHANGELOG.md Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
4.7 KiB
Handlers
A Handler designates a function that processes messages. Handlers are specific to the module in which they are defined, and only process messages defined within the said module. They are called from baseapp during DeliverTx. {synopsis}
Pre-requisite Readings
- Module Manager {prereq}
- Messages and Queries {prereq}
handler type
The handler type defined in the Cosmos SDK specifies the typical structure of a handler function.
+++ 7d7821b9af/types/handler.go (L4)
Let us break it down:
- The
Msgis the actual object being processed. - The
Contextcontains all the necessary information needed to process themsg, as well as a cache-wrapped copy of the latest state. If themsgis succesfully processed, the modified version of the temporary state contained in thectxwill be written to the main state. - The [
Result] returned tobaseapp, which contains (among other things) information on the execution of thehandler,gasconsumption andevents. +++7d7821b9af/types/result.go (L15-L40)
Implementation of a module handlers
Module handlers are typically implemented in a ./handler.go file inside the module's folder. The
module manager is used to add the module's handlers to the
application's router via the Route() method. Typically,
the manager's Route() method simply constructs a Route that calls a NewHandler() method defined in handler.go,
which looks like the following:
func NewHandler(keeper Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager())
switch msg := msg.(type) {
case MsgType1:
return handleMsgType1(ctx, keeper, msg)
case MsgType2:
return handleMsgType2(ctx, keeper, msg)
default:
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg)
}
}
}
First, the handler function sets a new EventManager to the context to isolate events per msg.
Then, this simple switch returns a handler function specific to the type of the received message. These handler functions are the ones that actually process messages, and usually follow the following 2 steps:
- First, they perform stateful checks to make sure the
messageis valid. At this stage, themessage'sValidateBasic()method has already been called, meaning stateless checks on the message (like making sure parameters are correctly formatted) have already been performed. Checks performed in thehandlercan be more expensive and require access to the state. For example, ahandlerfor atransfermessage might check that the sending account has enough funds to actually perform the transfer. To access the state, thehandlerneeds to call thekeeper's getter functions. - Then, if the checks are successfull, the
handlercalls thekeeper's setter functions to actually perform the state transition.
Before returning, handler functions generally emit one or multiple events via the EventManager held in the ctx:
ctx.EventManager().EmitEvent(
sdk.NewEvent(
eventType, // e.g. sdk.EventTypeMessage for a message, types.CustomEventType for a custom event defined in the module
sdk.NewAttribute(attributeKey, attributeValue),
),
)
These events are relayed back to the underlying consensus engine and can be used by service providers to implement services around the application. Click here to learn more about events.
Finally, the handler function returns a sdk.Result which contains the aforementioned events and an optional Data field.
+++ 7d7821b9af/types/result.go (L15-L40)
Next is an example of how to return a Result from the gov module:
+++ 7d7821b9af/x/gov/handler.go (L59-L62)
For a deeper look at handlers, see this example implementation of a handler function from the nameservice tutorial.
Next {hide}
Learn about queriers {hide}