Skip to content

Commit

Permalink
refactor(runtime/v2): simplify app manager (#22300)
Browse files Browse the repository at this point in the history
  • Loading branch information
julienrbrt authored Oct 21, 2024
1 parent 97d37ae commit 681366e
Show file tree
Hide file tree
Showing 22 changed files with 194 additions and 192 deletions.
43 changes: 19 additions & 24 deletions runtime/v2/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,24 @@ import (
// done declaratively with an app config and the rest of it is done the old way.
// See simapp/app_v2.go for an example of this setup.
type App[T transaction.Tx] struct {
*appmanager.AppManager[T]
appmanager.AppManager[T]

// app manager dependencies
// app configuration
logger log.Logger
config *runtimev2.Module

// state
stf *stf.STF[T]
msgRouterBuilder *stf.MsgRouterBuilder
queryRouterBuilder *stf.MsgRouterBuilder
db Store
storeLoader StoreLoader

// app configuration
logger log.Logger
config *runtimev2.Module

// modules
interfaceRegistrar registry.InterfaceRegistrar
amino registry.AminoRegistrar
moduleManager *MM[T]

// QueryHandlers defines the query handlers
QueryHandlers map[string]appmodulev2.Handler

storeLoader StoreLoader
queryHandlers map[string]appmodulev2.Handler // queryHandlers defines the query handlers
}

// Name returns the app name.
Expand Down Expand Up @@ -85,24 +83,21 @@ func (a *App[T]) LoadLatestHeight() (uint64, error) {
return a.db.GetLatestVersion()
}

// Close is called in start cmd to gracefully cleanup resources.
func (a *App[T]) Close() error {
return nil
}

func (a *App[T]) GetAppManager() *appmanager.AppManager[T] {
return a.AppManager
}

func (a *App[T]) GetQueryHandlers() map[string]appmodulev2.Handler {
return a.QueryHandlers
// GetQueryHandlers returns the query handlers.
func (a *App[T]) QueryHandlers() map[string]appmodulev2.Handler {
return a.queryHandlers
}

// GetSchemaDecoderResolver returns the module schema resolver.
func (a *App[T]) GetSchemaDecoderResolver() decoding.DecoderResolver {
// SchemaDecoderResolver returns the module schema resolver.
func (a *App[T]) SchemaDecoderResolver() decoding.DecoderResolver {
moduleSet := map[string]any{}
for moduleName, module := range a.moduleManager.Modules() {
moduleSet[moduleName] = module
}
return decoding.ModuleSetDecoderResolver(moduleSet)
}

// Close is called in start cmd to gracefully cleanup resources.
func (a *App[T]) Close() error {
return nil
}
127 changes: 60 additions & 67 deletions runtime/v2/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,6 @@ type AppBuilder[T transaction.Tx] struct {
postTxExec func(ctx context.Context, tx T, success bool) error
}

// DefaultGenesis returns a default genesis from the registered AppModule's.
func (a *AppBuilder[T]) DefaultGenesis() map[string]json.RawMessage {
return a.app.moduleManager.DefaultGenesis()
}

// RegisterModules registers the provided modules with the module manager.
// This is the primary hook for integrating with modules which are not registered using the app config.
func (a *AppBuilder[T]) RegisterModules(modules map[string]appmodulev2.AppModule) error {
Expand Down Expand Up @@ -98,7 +93,7 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) {

endBlocker, valUpdate := a.app.moduleManager.EndBlock()

stf, err := stf.NewSTF[T](
stf, err := stf.New[T](
a.app.logger.With("module", "stf"),
a.app.msgRouterBuilder,
a.app.queryRouterBuilder,
Expand All @@ -115,77 +110,75 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) {
}
a.app.stf = stf

appManagerBuilder := appmanager.Builder[T]{
STF: a.app.stf,
DB: a.app.db,
ValidateTxGasLimit: a.app.config.GasConfig.ValidateTxGasLimit,
QueryGasLimit: a.app.config.GasConfig.QueryGasLimit,
SimulationGasLimit: a.app.config.GasConfig.SimulationGasLimit,
InitGenesis: func(
ctx context.Context,
src io.Reader,
txHandler func(json.RawMessage) error,
) (store.WriterMap, error) {
// this implementation assumes that the state is a JSON object
bz, err := io.ReadAll(src)
if err != nil {
return nil, fmt.Errorf("failed to read import state: %w", err)
}
var genesisJSON map[string]json.RawMessage
if err = json.Unmarshal(bz, &genesisJSON); err != nil {
return nil, err
}

v, zeroState, err := a.app.db.StateLatest()
if err != nil {
return nil, fmt.Errorf("unable to get latest state: %w", err)
}
if v != 0 { // TODO: genesis state may be > 0, we need to set version on store
return nil, errors.New("cannot init genesis on non-zero state")
}
genesisCtx := services.NewGenesisContext(a.branch(zeroState))
genesisState, err := genesisCtx.Mutate(ctx, func(ctx context.Context) error {
err = a.app.moduleManager.InitGenesisJSON(ctx, genesisJSON, txHandler)
if err != nil {
return fmt.Errorf("failed to init genesis: %w", err)
}
return nil
})

return genesisState, err
a.app.AppManager = appmanager.New[T](
appmanager.Config{
ValidateTxGasLimit: a.app.config.GasConfig.ValidateTxGasLimit,
QueryGasLimit: a.app.config.GasConfig.QueryGasLimit,
SimulationGasLimit: a.app.config.GasConfig.SimulationGasLimit,
},
ExportGenesis: func(ctx context.Context, version uint64) ([]byte, error) {
state, err := a.app.db.StateAt(version)
if err != nil {
return nil, fmt.Errorf("unable to get state at given version: %w", err)
}
a.app.db,
a.app.stf,
a.initGenesis,
a.exportGenesis,
)

genesisJson, err := a.app.moduleManager.ExportGenesisForModules(
ctx,
func() store.WriterMap {
return a.branch(state)
},
)
if err != nil {
return nil, fmt.Errorf("failed to export genesis: %w", err)
}
return a.app, nil
}

bz, err := json.Marshal(genesisJson)
if err != nil {
return nil, fmt.Errorf("failed to marshal genesis: %w", err)
}
// initGenesis returns the app initialization genesis for modules
func (a *AppBuilder[T]) initGenesis(ctx context.Context, src io.Reader, txHandler func(json.RawMessage) error) (store.WriterMap, error) {
// this implementation assumes that the state is a JSON object
bz, err := io.ReadAll(src)
if err != nil {
return nil, fmt.Errorf("failed to read import state: %w", err)
}
var genesisJSON map[string]json.RawMessage
if err = json.Unmarshal(bz, &genesisJSON); err != nil {
return nil, err
}

v, zeroState, err := a.app.db.StateLatest()
if err != nil {
return nil, fmt.Errorf("unable to get latest state: %w", err)
}
if v != 0 { // TODO: genesis state may be > 0, we need to set version on store
return nil, errors.New("cannot init genesis on non-zero state")
}
genesisCtx := services.NewGenesisContext(a.branch(zeroState))
genesisState, err := genesisCtx.Mutate(ctx, func(ctx context.Context) error {
err = a.app.moduleManager.InitGenesisJSON(ctx, genesisJSON, txHandler)
if err != nil {
return fmt.Errorf("failed to init genesis: %w", err)
}
return nil
})

return bz, nil
return genesisState, err
}

// exportGenesis returns the app export genesis logic for modules
func (a *AppBuilder[T]) exportGenesis(ctx context.Context, version uint64) ([]byte, error) {
state, err := a.app.db.StateAt(version)
if err != nil {
return nil, fmt.Errorf("unable to get state at given version: %w", err)
}

genesisJson, err := a.app.moduleManager.ExportGenesisForModules(
ctx,
func() store.WriterMap {
return a.branch(state)
},
)
if err != nil {
return nil, fmt.Errorf("failed to export genesis: %w", err)
}

appManager, err := appManagerBuilder.Build()
bz, err := json.Marshal(genesisJson)
if err != nil {
return nil, fmt.Errorf("failed to build app manager: %w", err)
return nil, fmt.Errorf("failed to marshal genesis: %w", err)
}
a.app.AppManager = appManager

return a.app, nil
return bz, nil
}

// AppBuilderOption is a function that can be passed to AppBuilder.Build to customize the resulting app.
Expand Down
4 changes: 2 additions & 2 deletions runtime/v2/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ func registerServices[T transaction.Tx](s appmodulev2.AppModule, app *App[T], re

// merge maps
for path, decoder := range c.queryHandlers {
app.QueryHandlers[path] = decoder
app.queryHandlers[path] = decoder
}
}

Expand All @@ -655,7 +655,7 @@ func registerServices[T transaction.Tx](s appmodulev2.AppModule, app *App[T], re
module.RegisterQueryHandlers(&wrapper)

for path, handler := range wrapper.handlers {
app.QueryHandlers[path] = handler
app.queryHandlers[path] = handler
}
}

Expand Down
2 changes: 1 addition & 1 deletion runtime/v2/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func ProvideAppBuilder[T transaction.Tx](
amino: amino,
msgRouterBuilder: msgRouterBuilder,
queryRouterBuilder: stf.NewMsgRouterBuilder(), // TODO dedicated query router
QueryHandlers: map[string]appmodulev2.Handler{},
queryHandlers: map[string]appmodulev2.Handler{},
storeLoader: DefaultStoreLoader,
}
appBuilder := &AppBuilder[T]{app: app, storeBuilder: storeBuilder}
Expand Down
6 changes: 3 additions & 3 deletions server/v2/api/grpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,14 @@ func (s *Server[T]) Init(appI serverv2.AppI[T], cfg map[string]any, logger log.L
return fmt.Errorf("failed to unmarshal config: %w", err)
}
}
methodsMap := appI.GetQueryHandlers()
methodsMap := appI.QueryHandlers()

grpcSrv := grpc.NewServer(
grpc.ForceServerCodec(newProtoCodec(appI.InterfaceRegistry()).GRPCCodec()),
grpc.MaxSendMsgSize(serverCfg.MaxSendMsgSize),
grpc.MaxRecvMsgSize(serverCfg.MaxRecvMsgSize),
grpc.UnknownServiceHandler(
makeUnknownServiceHandler(methodsMap, appI.GetAppManager()),
makeUnknownServiceHandler(methodsMap, appI),
),
)

Expand All @@ -85,7 +85,7 @@ func (s *Server[T]) StartCmdFlags() *pflag.FlagSet {
}

func makeUnknownServiceHandler(handlers map[string]appmodulev2.Handler, querier interface {
Query(ctx context.Context, version uint64, msg gogoproto.Message) (gogoproto.Message, error)
Query(ctx context.Context, version uint64, msg transaction.Msg) (transaction.Msg, error)
},
) grpc.StreamHandler {
getRegistry := sync.OnceValues(gogoproto.MergedRegistry)
Expand Down
4 changes: 2 additions & 2 deletions server/v2/api/rest/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ const (
MaxBodySize = 1 << 20 // 1 MB
)

func NewDefaultHandler[T transaction.Tx](appManager *appmanager.AppManager[T]) http.Handler {
func NewDefaultHandler[T transaction.Tx](appManager appmanager.AppManager[T]) http.Handler {
return &DefaultHandler[T]{appManager: appManager}
}

type DefaultHandler[T transaction.Tx] struct {
appManager *appmanager.AppManager[T]
appManager appmanager.AppManager[T]
}

func (h *DefaultHandler[T]) ServeHTTP(w http.ResponseWriter, r *http.Request) {
Expand Down
2 changes: 1 addition & 1 deletion server/v2/api/rest/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (s *Server[T]) Init(appI serverv2.AppI[T], cfg map[string]any, logger log.L
}

s.router = http.NewServeMux()
s.router.Handle("/", NewDefaultHandler(appI.GetAppManager()))
s.router.Handle("/", NewDefaultHandler(appI))
s.config = serverCfg

return nil
Expand Down
Loading

0 comments on commit 681366e

Please sign in to comment.