Skip to content
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

chore(core): bring changes from serverv2 #19617

Merged
merged 8 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
tac0turtle marked this conversation as resolved.
Show resolved Hide resolved

### 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
}
16 changes: 16 additions & 0 deletions core/appmodule/v2/genesis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package appmodule

import (
"context"
)

// 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 Message) error
tac0turtle marked this conversation as resolved.
Show resolved Hide resolved
InitGenesis(ctx context.Context, data Message) error
ExportGenesis(ctx context.Context) (Message, 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
Loading