refactor(runtime/v2): simplify app manager (#22300)
This commit is contained in:
+20
-25
@@ -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]
|
||||
|
||||
// app manager dependencies
|
||||
stf *stf.STF[T]
|
||||
msgRouterBuilder *stf.MsgRouterBuilder
|
||||
queryRouterBuilder *stf.MsgRouterBuilder
|
||||
db Store
|
||||
appmanager.AppManager[T]
|
||||
|
||||
// app configuration
|
||||
logger log.Logger
|
||||
config *runtimev2.Module
|
||||
|
||||
// state
|
||||
stf *stf.STF[T]
|
||||
msgRouterBuilder *stf.MsgRouterBuilder
|
||||
queryRouterBuilder *stf.MsgRouterBuilder
|
||||
db Store
|
||||
storeLoader StoreLoader
|
||||
|
||||
// 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.
|
||||
@@ -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
|
||||
// GetQueryHandlers returns the query handlers.
|
||||
func (a *App[T]) QueryHandlers() map[string]appmodulev2.Handler {
|
||||
return a.queryHandlers
|
||||
}
|
||||
|
||||
func (a *App[T]) GetAppManager() *appmanager.AppManager[T] {
|
||||
return a.AppManager
|
||||
}
|
||||
|
||||
func (a *App[T]) GetQueryHandlers() 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
|
||||
}
|
||||
|
||||
+67
-74
@@ -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 {
|
||||
@@ -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,
|
||||
@@ -115,79 +110,77 @@ 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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
bz, err := json.Marshal(genesisJson)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal genesis: %w", err)
|
||||
}
|
||||
|
||||
return bz, nil
|
||||
},
|
||||
}
|
||||
|
||||
appManager, err := appManagerBuilder.Build()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build app manager: %w", err)
|
||||
}
|
||||
a.app.AppManager = appManager
|
||||
a.app.db,
|
||||
a.app.stf,
|
||||
a.initGenesis,
|
||||
a.exportGenesis,
|
||||
)
|
||||
|
||||
return a.app, nil
|
||||
}
|
||||
|
||||
// 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 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)
|
||||
}
|
||||
|
||||
bz, err := json.Marshal(genesisJson)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal genesis: %w", err)
|
||||
}
|
||||
|
||||
return bz, nil
|
||||
}
|
||||
|
||||
// AppBuilderOption is a function that can be passed to AppBuilder.Build to customize the resulting app.
|
||||
type AppBuilderOption[T transaction.Tx] func(*AppBuilder[T])
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user