Skip to content

Commit

Permalink
chore(core): bring changes from serverv2 (#19617)
Browse files Browse the repository at this point in the history
  • Loading branch information
tac0turtle authored Mar 1, 2024
1 parent 69f03cd commit 7628592
Show file tree
Hide file tree
Showing 16 changed files with 470 additions and 52 deletions.
11 changes: 11 additions & 0 deletions core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ Ref: https://keepachangelog.com/en/1.0.0/
* [#18457](https://github.com/cosmos/cosmos-sdk/pull/18457) Add branch.ExecuteWithGasLimit.
* [#19041](https://github.com/cosmos/cosmos-sdk/pull/19041) Add `appmodule.Environment` interface to fetch different services
* [#19370](https://github.com/cosmos/cosmos-sdk/pull/19370) Add `appmodule.Migrations` interface to handle migrations
* [#19617](https://github.com/cosmos/cosmos-sdk/pull/19617) Add DataBaseService to store non-consensus data in a database
* Create V2 appmodule with v2 api for runtime/v2
* Introduce `Transaction.Tx` for use in runtime/v2
* Introduce `HasUpdateValidators` interface and `ValidatorUpdate` struct for validator updates
* Introduce `HasTxValidation` interface for modules to register tx validation handlers
* `HasGenesis` interface for modules to register import, export, validation and default genesis handlers. The new api works with `proto.Message`
* Add `PreMsghandler`and `PostMsgHandler` for pre and post message hooks
* Add `MsgHandler` as an alternative to grpc handlers
* Provide separate `MigrationRegistrar` instead of grouping with `RegisterServices`

### Improvements

### API Breaking Changes

Expand Down
17 changes: 2 additions & 15 deletions core/appmodule/environment.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,8 @@
package appmodule

import (
"cosmossdk.io/core/branch"
"cosmossdk.io/core/event"
"cosmossdk.io/core/gas"
"cosmossdk.io/core/header"
"cosmossdk.io/core/store"
"cosmossdk.io/log"
appmodule "cosmossdk.io/core/appmodule/v2"
)

// Environment is used to get all services to their respective module
type Environment struct {
BranchService branch.Service
EventService event.Service
GasService gas.Service
HeaderService header.Service
KVStoreService store.KVStoreService
MemStoreService store.MemoryStoreService
Logger log.Logger
}
type Environment = appmodule.Environment
41 changes: 14 additions & 27 deletions core/appmodule/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,27 @@ import (

"google.golang.org/grpc"
"google.golang.org/protobuf/runtime/protoiface"

appmodule "cosmossdk.io/core/appmodule/v2"
)

// AppModule is a tag interface for app module implementations to use as a basis
// for extension interfaces. It provides no functionality itself, but is the
// type that all valid app modules should provide so that they can be identified
// by other modules (usually via depinject) as app modules.
type AppModule interface {
// IsAppModule is a dummy method to tag a struct as implementing an AppModule.
IsAppModule()
type AppModule = appmodule.AppModule

// HasMigrations is the extension interface that modules should implement to register migrations.
type HasMigrations interface {
AppModule

// IsOnePerModuleType is a dummy method to help depinject resolve modules.
IsOnePerModuleType()
// RegisterMigrations registers the module's migrations with the app's migrator.
RegisterMigrations(MigrationRegistrar) error
}

// HasConsensusVersion is the interface for declaring a module consensus version.
type HasConsensusVersion = appmodule.HasConsensusVersion

// HasServices is the extension interface that modules should implement to register
// implementations of services defined in .proto files.
type HasServices interface {
Expand All @@ -39,14 +46,6 @@ type HasServices interface {
RegisterServices(grpc.ServiceRegistrar) error
}

// HasMigrations is the extension interface that modules should implement to register migrations.
type HasMigrations interface {
AppModule

// RegisterMigrations registers the module's migrations with the app's migrator.
RegisterMigrations(MigrationRegistrar) error
}

// ResponsePreBlock represents the response from the PreBlock method.
// It can modify consensus parameters in storage and signal the caller through the return value.
// When it returns ConsensusParamsChanged=true, the caller must refresh the consensus parameter in the finalize context.
Expand All @@ -65,23 +64,11 @@ type HasPreBlocker interface {

// HasBeginBlocker is the extension interface that modules should implement to run
// custom logic before transaction processing in a block.
type HasBeginBlocker interface {
AppModule

// BeginBlock is a method that will be run before transactions are processed in
// a block.
BeginBlock(context.Context) error
}
type HasBeginBlocker = appmodule.HasBeginBlocker

// HasEndBlocker is the extension interface that modules should implement to run
// custom logic after transaction processing in a block.
type HasEndBlocker interface {
AppModule

// EndBlock is a method that will be run after transactions are processed in
// a block.
EndBlock(context.Context) error
}
type HasEndBlocker = appmodule.HasEndBlocker

// MsgHandlerRouter is implemented by the runtime provider.
type MsgHandlerRouter interface {
Expand Down
92 changes: 92 additions & 0 deletions core/appmodule/v2/appmodule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package appmodule

import (
"context"

"cosmossdk.io/core/transaction"
)

// AppModule is a tag interface for app module implementations to use as a basis
// for extension interfaces. It provides no functionality itself, but is the
// type that all valid app modules should provide so that they can be identified
// by other modules (usually via depinject) as app modules.
type AppModule interface {
// IsAppModule is a dummy method to tag a struct as implementing an AppModule.
IsAppModule()

// IsOnePerModuleType is a dummy method to help depinject resolve modules.
IsOnePerModuleType()
}

// HasBeginBlocker is the extension interface that modules should implement to run
// custom logic before transaction processing in a block.
type HasBeginBlocker interface {
AppModule

// BeginBlock is a method that will be run before transactions are processed in
// a block.
BeginBlock(context.Context) error
}

// HasEndBlocker is the extension interface that modules should implement to run
// custom logic after transaction processing in a block.
type HasEndBlocker interface {
AppModule

// EndBlock is a method that will be run after transactions are processed in
// a block.
EndBlock(context.Context) error
}

// HasTxValidation is the extension interface that modules should implement to run
// custom logic for validating transactions.
// It was previously known as AnteHandler/Decorator.
type HasTxValidation[T transaction.Tx] interface {
AppModule

// TxValidator is a method that will be run on each transaction.
// If an error is returned:
// ,---.
// / |
// / |
// You shall not pass! / |
// / |
// \ ___,' |
// < -' :
// `-.__..--'``-,_\_
// |o/ <o>` :,.)_`>
// :/ ` ||/)
// (_.).__,-` |\
// /( `.`` `| :
// \'`-.) ` ; ;
// | ` /-<
// | ` / `.
// ,-_-..____ /| ` :__..-'\
// /,'-.__\\ ``-./ :` ; \
// `\ `\ `\\ \ : ( ` / , `. \
// \` \ \\ | | ` : : .\ \
// \ `\_ )) : ; | | ): :
// (`-.-'\ || |\ \ ` ; ; | |
// \-_ `;;._ ( ` / /_ | |
// `-.-.// ,'`-._\__/_,' ; |
// \:: : / ` , / |
// || | ( ,' / / |
// || ,' / |
TxValidator(ctx context.Context, tx T) error
}

// HasUpdateValidators is an extension interface that contains information about the AppModule and UpdateValidators.
// It can be seen as the alternative of the Cosmos SDK' HasABCIEndBlocker.
// Both are still supported.
type HasUpdateValidators interface {
AppModule

UpdateValidators(ctx context.Context) ([]ValidatorUpdate, error)
}

// ValidatorUpdate defines a validator update.
type ValidatorUpdate struct {
PubKey []byte
PubKeyType string
Power int64 // updated power of the validtor
}
22 changes: 22 additions & 0 deletions core/appmodule/v2/environment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package appmodule

import (
"cosmossdk.io/core/branch"
"cosmossdk.io/core/event"
"cosmossdk.io/core/gas"
"cosmossdk.io/core/header"
"cosmossdk.io/core/store"
"cosmossdk.io/log"
)

// Environment is used to get all services to their respective module
type Environment struct {
BranchService branch.Service
EventService event.Service
GasService gas.Service
HeaderService header.Service
KVStoreService store.KVStoreService
MemStoreService store.MemoryStoreService
DataBaseService store.DatabaseService
Logger log.Logger
}
17 changes: 17 additions & 0 deletions core/appmodule/v2/genesis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package appmodule

import (
"context"
"encoding/json"
)

// HasGenesis defines a custom genesis handling API implementation.
// WARNING: this API is meant as a short-term solution to allow for the
// migration of existing modules to the new app module API. It is intended to be replaced by collections
type HasGenesis interface {
AppModule
DefaultGenesis() Message
ValidateGenesis(data json.RawMessage) error
InitGenesis(ctx context.Context, data json.RawMessage) error
ExportGenesis(ctx context.Context) (json.RawMessage, error)
}
142 changes: 142 additions & 0 deletions core/appmodule/v2/handlers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package appmodule

import (
"context"
"fmt"
)

type (
// PreMsgHandler is a handler that is executed before Handler. If it errors the execution reverts.
PreMsgHandler = func(ctx context.Context, msg Message) error
// Handler handles the state transition of the provided message.
Handler = func(ctx context.Context, msg Message) (msgResp Message, 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 Message) error
)

// RegisterHandler is a helper function that modules can use to not lose type safety when registering handlers to the
// QueryRouter or MsgRouter. Example usage:
// ```go
//
// func (k Keeper) QueryBalance(ctx context.Context, req *types.QueryBalanceRequest) (*types.QueryBalanceResponse, error) {
// ... query logic ...
// }
//
// func (m Module) RegisterQueryHandlers(router appmodule.QueryRouter) {
// appmodule.RegisterHandler(router, keeper.QueryBalance)
// }
//
// ```
func RegisterHandler[R interface{ Register(string, Handler) }, Req, Resp Message](
router R,
handler func(ctx context.Context, msg Req) (msgResp Resp, err error),
) {
untypedHandler := func(ctx context.Context, m Message) (Message, error) {
typed, ok := m.(Req)
if !ok {
return nil, fmt.Errorf("unexpected type %T, wanted: %T", m, *new(Req))
}
return handler(ctx, typed)
}
router.Register(messageName[Req](), untypedHandler)
}

// RegisterPreHandler is a helper function that modules can use to not lose type safety when registering PreMsgHandler to the
// PreMsgRouter. Example usage:
// ```go
//
// func (k Keeper) BeforeSend(ctx context.Context, req *types.MsgSend) (*types.QueryBalanceResponse, error) {
// ... before send logic ...
// }
//
// func (m Module) RegisterPreMsgHandlers(router appmodule.PreMsgRouter) {
// appmodule.RegisterPreHandler(router, keeper.BeforeSend)
// }
//
// ```
func RegisterPreHandler[Req Message](
router PreMsgRouter,
handler func(ctx context.Context, msg Req) error,
) {
untypedHandler := func(ctx context.Context, m Message) error {
typed, ok := m.(Req)
if !ok {
return fmt.Errorf("unexpected type %T, wanted: %T", m, *new(Req))
}
return handler(ctx, typed)
}
router.Register(messageName[Req](), untypedHandler)
}

// RegisterPostHandler is a helper function that modules can use to not lose type safety when registering handlers to the
// PostMsgRouter. Example usage:
// ```go
//
// func (k Keeper) AfterSend(ctx context.Context, req *types.MsgSend, resp *types.MsgSendResponse) error {
// ... query logic ...
// }
//
// func (m Module) RegisterPostMsgHandlers(router appmodule.PostMsgRouter) {
// appmodule.RegisterPostHandler(router, keeper.AfterSend)
// }
//
// ```
func RegisterPostHandler[Req, Resp Message](
router PostMsgRouter,
handler func(ctx context.Context, msg Req, msgResp Resp) error,
) {
untypedHandler := func(ctx context.Context, m, mResp Message) error {
typed, ok := m.(Req)
if !ok {
return fmt.Errorf("unexpected type %T, wanted: %T", m, *new(Req))
}
typedResp, ok := mResp.(Resp)
if !ok {
return fmt.Errorf("unexpected type %T, wanted: %T", m, *new(Resp))
}
return handler(ctx, typed, typedResp)
}
router.Register(messageName[Req](), untypedHandler)
}

// msg handler

type PreMsgRouter interface {
// Register will register a specific message handler hooking into the message with
// the provided name.
Register(msgName string, handler PreMsgHandler)
// RegisterGlobal will register a global message handler hooking into any message
// being executed.
RegisterGlobal(handler PreMsgHandler)
}

type HasPreMsgHandlers interface {
RegisterPreMsgHandlers(router PreMsgRouter)
}

type MsgRouter interface {
Register(msgName string, handler Handler)
}

type HasMsgHandlers interface {
RegisterMsgHandlers(router MsgRouter)
}

type PostMsgRouter interface {
// Register will register a specific message handler hooking after the execution of message with
// the provided name.
Register(msgName string, handler PostMsgHandler)
// RegisterGlobal will register a global message handler hooking after the execution of any message.
RegisterGlobal(handler PreMsgHandler)
}

// query handler

type QueryRouter interface {
Register(queryName string, handler Handler)
}

type HasQueryHandlers interface {
RegisterQueryHandlers(router QueryRouter)
}
Loading

0 comments on commit 7628592

Please sign in to comment.