Skip to main content
Version: v0.52

Msg Services

Synopsis

A Protobuf Msg service processes messages. Protobuf Msg services 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 FinalizeBlock.

Implementation of a module Msg service

Each module should define a Protobuf Msg service, which will be responsible for processing requests (implementing transaction.Msg) and returning responses.

As further described in ADR 031, this approach has the advantage of clearly specifying return types and generating server and client code.

Protobuf generates a MsgServer interface based on the definition of Msg service. It is the role of the module developer to implement this interface, by implementing the state transition logic that should happen upon receival of each transaction.Msg. As an example, here is the generated MsgServer interface for x/bank, which exposes two transaction.Msgs:

x/bank/types/tx.pb.go
loading...

When possible, the existing module's Keeper should implement MsgServer, otherwise a msgServer struct that embeds the Keeper can be created, typically in ./keeper/msg_server.go:

x/bank/keeper/msg_server.go
loading...

msgServer methods can retrieve the auxiliary information or services using the environment variable, it is should always be located in the keeper.

A transaction.Msg processing usually follows these 3 steps:

Validation

The message server must perform all validation required (both stateful and stateless) to make sure the message is valid. The signer is charged for the gas cost of this validation.

For example, a msgServer method for a transfer message should check that the sending account has enough funds to actually perform the transfer.

It is recommended to implement all validation checks in a separate function that passes state values as arguments. This implementation simplifies testing. As expected, expensive validation functions charge additional gas. Example:

ValidateMsgA(msg MsgA, now Time, gm GasMeter) error {
if now.Before(msg.Expire) {
return sdkerrors.ErrInvalidRequest.Wrap("msg expired")
}
gm.ConsumeGas(1000, "signature verification")
return signatureVerificaton(msg.Prover, msg.Data)
}
danger

Previously, the ValidateBasic method was used to perform simple and stateless validation checks. This way of validating is deprecated, this means the msgServer must perform all validation checks.

State Transition

After the validation is successful, the msgServer method uses the keeper functions to access the state and perform a state transition.

Events

Before returning, msgServer methods generally emit one or more events by using the EventService held in environment.

There are two ways to emit events, typed events using protobuf or arbitrary key & values.

For typed events:

environment.EventService.EventManager(ctx).Emit(&group.EventABC{Key1: Value1,  Key2, Value2})

Or using simple KV events:

environment.EventService.EventManager(ctx).EmitKV(
eventType, // e.g. sdk.EventTypeMessage for a message, types.CustomEventType for a custom event defined in the module
event.Attribute{Key: key1, Value: value1},
event.Attribute{Key: key2, Value: value2},
)

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.

Telemetry

:::Warning Telemetry adds a performance overhead to the chain. It is recommended to only use this in critical paths :::

New telemetry metrics can be created from msgServer methods when handling messages.

This is an example from the x/auth/vesting module:

x/auth/vesting/msg_server.go
loading...

How it works

danger

This flow concerns only a Cosmos SDK baseapp, and not Cosmos SDK v2.

The invoked msgServer method returns a proto.Message response and an error. These return values are then wrapped into an *sdk.Result or an error:

baseapp/msg_service_router.go
loading...

This method takes care of marshaling the res parameter to protobuf and attaching any events on the EventManager() to the sdk.Result.

proto/cosmos/base/abci/v1beta1/abci.proto
loading...

This diagram shows a typical structure of a Protobuf Msg service, and how the message propagates through the module.