From a9773384255e9fa0417ab588ada9ea4b06ea3ed8 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Sun, 15 Sep 2024 14:32:16 -0500 Subject: [PATCH 01/13] refactor(stf): rm RunWithCtx --- core/header/service.go | 6 +- core/store/service.go | 4 + runtime/v2/builder.go | 55 +++++++++++--- runtime/v2/genesis.go | 114 +++++++++++++++++++++++++++++ runtime/v2/go.mod | 1 + runtime/v2/module.go | 37 ++++++++-- server/v2/appmanager/appmanager.go | 59 ++++++++++----- server/v2/appmanager/genesis.go | 18 ++++- simapp/v2/app_di.go | 1 + simapp/v2/go.mod | 1 + simapp/v2/simdv2/cmd/root_di.go | 17 ++++- 11 files changed, 267 insertions(+), 46 deletions(-) create mode 100644 runtime/v2/genesis.go diff --git a/core/header/service.go b/core/header/service.go index 15e6d4257425..29ee248f1389 100644 --- a/core/header/service.go +++ b/core/header/service.go @@ -13,6 +13,8 @@ type Service interface { HeaderInfo(context.Context) Info } +type HeaderServiceFactory func() Service + // Info defines a struct that contains information about the header type Info struct { Height int64 // Height returns the height of the block @@ -35,7 +37,7 @@ func (i *Info) Bytes() ([]byte, error) { // Encode Hash if len(i.Hash) != hashSize { - return nil, errors.New("invalid hash size") + return nil, errors.New("invalid Hash size") } buf = append(buf, i.Hash...) @@ -47,7 +49,7 @@ func (i *Info) Bytes() ([]byte, error) { // Encode AppHash if len(i.AppHash) != hashSize { - return nil, errors.New("invalid hash size") + return nil, errors.New("invalid AppHash size") } buf = append(buf, i.AppHash...) diff --git a/core/store/service.go b/core/store/service.go index 11eeaf0de9b3..60d4c023cc30 100644 --- a/core/store/service.go +++ b/core/store/service.go @@ -10,6 +10,8 @@ type KVStoreService interface { OpenKVStore(context.Context) KVStore } +type KVStoreServiceFactory func([]byte) KVStoreService + // MemoryStoreService represents a unique, non-forgeable handle to a memory-backed // KVStore. It should be provided as a module-scoped dependency by the runtime // module being used to build the app. @@ -18,6 +20,8 @@ type MemoryStoreService interface { OpenMemoryStore(context.Context) KVStore } +type MemoryStoreServiceFactory func([]byte) MemoryStoreService + // TransientStoreService represents a unique, non-forgeable handle to a memory-backed // KVStore which is reset at the start of every block. It should be provided as // a module-scoped dependency by the runtime module being used to build the app. diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index 0a1b279330de..5120725bea19 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -3,6 +3,7 @@ package runtime import ( "context" "encoding/json" + "errors" "fmt" "io" "path/filepath" @@ -45,7 +46,13 @@ func (a *AppBuilder[T]) RegisterModules(modules map[string]appmodulev2.AppModule // if a (legacy) module implements the HasName interface, check that the name matches if mod, ok := appModule.(interface{ Name() string }); ok { if name != mod.Name() { - a.app.logger.Warn(fmt.Sprintf("module name %q does not match name returned by HasName: %q", name, mod.Name())) + a.app.logger.Warn( + fmt.Sprintf( + "module name %q does not match name returned by HasName: %q", + name, + mod.Name(), + ), + ) } } @@ -157,20 +164,38 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { 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) error { + 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 fmt.Errorf("failed to read import state: %w", err) + return nil, fmt.Errorf("failed to read import state: %w", err) } - var genesisState map[string]json.RawMessage - if err = json.Unmarshal(bz, &genesisState); err != nil { - return err + var genesisJSON map[string]json.RawMessage + if err = json.Unmarshal(bz, &genesisJSON); err != nil { + return nil, err } - if err = a.app.moduleManager.InitGenesisJSON(ctx, genesisState, txHandler); err != nil { - return fmt.Errorf("failed to init genesis: %w", err) + + v, zeroState, err := a.app.db.StateLatest() + if err != nil { + return nil, fmt.Errorf("unable to get latest state: %w", err) } - return nil + 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 := makeGenesisContext(a.branch(zeroState)) + genesisState, err := genesisCtx.Run(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: func(ctx context.Context, version uint64) ([]byte, error) { genesisJson, err := a.app.moduleManager.ExportGenesisForModules(ctx) @@ -200,7 +225,9 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { type AppBuilderOption[T transaction.Tx] func(*AppBuilder[T]) // AppBuilderWithBranch sets a custom branch implementation for the app. -func AppBuilderWithBranch[T transaction.Tx](branch func(state store.ReaderMap) store.WriterMap) AppBuilderOption[T] { +func AppBuilderWithBranch[T transaction.Tx]( + branch func(state store.ReaderMap) store.WriterMap, +) AppBuilderOption[T] { return func(a *AppBuilder[T]) { a.branch = branch } @@ -208,7 +235,9 @@ func AppBuilderWithBranch[T transaction.Tx](branch func(state store.ReaderMap) s // AppBuilderWithTxValidator sets the tx validator for the app. // It overrides all default tx validators defined by modules. -func AppBuilderWithTxValidator[T transaction.Tx](txValidators func(ctx context.Context, tx T) error) AppBuilderOption[T] { +func AppBuilderWithTxValidator[T transaction.Tx]( + txValidators func(ctx context.Context, tx T) error, +) AppBuilderOption[T] { return func(a *AppBuilder[T]) { a.txValidator = txValidators } @@ -216,7 +245,9 @@ func AppBuilderWithTxValidator[T transaction.Tx](txValidators func(ctx context.C // AppBuilderWithPostTxExec sets logic that will be executed after each transaction. // When not provided, a no-op function will be used. -func AppBuilderWithPostTxExec[T transaction.Tx](postTxExec func(ctx context.Context, tx T, success bool) error) AppBuilderOption[T] { +func AppBuilderWithPostTxExec[T transaction.Tx]( + postTxExec func(ctx context.Context, tx T, success bool) error, +) AppBuilderOption[T] { return func(a *AppBuilder[T]) { a.postTxExec = postTxExec } diff --git a/runtime/v2/genesis.go b/runtime/v2/genesis.go new file mode 100644 index 000000000000..0dea54c97790 --- /dev/null +++ b/runtime/v2/genesis.go @@ -0,0 +1,114 @@ +package runtime + +import ( + "context" + "fmt" + + "cosmossdk.io/core/header" + "cosmossdk.io/core/store" +) + +var _ store.KVStoreService = (*GenesisKVStoreServie)(nil) + +type genesisContextKeyType struct{} + +var genesisContextKey = genesisContextKeyType{} + +type genesisContext struct { + state store.WriterMap + didRun bool +} + +func makeGenesisContext(state store.WriterMap) genesisContext { + return genesisContext{ + state: state, + } +} + +func (g *genesisContext) Run( + ctx context.Context, + fn func(ctx context.Context) error, +) (store.WriterMap, error) { + ctx = context.WithValue(ctx, genesisContextKey, g) + err := fn(ctx) + if err != nil { + return nil, err + } + g.didRun = true + return g.state, nil +} + +type GenesisKVStoreServie struct { + genesisCapable bool + actor []byte + execution store.KVStoreService +} + +func NewGenesisKVService( + actor []byte, + execution store.KVStoreService, +) *GenesisKVStoreServie { + return &GenesisKVStoreServie{ + genesisCapable: true, + actor: actor, + execution: execution, + } +} + +// OpenKVStore implements store.KVStoreService. +func (g *GenesisKVStoreServie) OpenKVStore(ctx context.Context) store.KVStore { + if !g.genesisCapable { + return g.execution.OpenKVStore(ctx) + } + v := ctx.Value(genesisContextKey) + if v == nil { + return g.execution.OpenKVStore(ctx) + } + genCtx, ok := v.(*genesisContext) + if !ok { + panic(fmt.Errorf("unexpected genesis context type: %T", v)) + } + if genCtx.didRun { + g.genesisCapable = false + return g.execution.OpenKVStore(ctx) + } + state, err := genCtx.state.GetWriter(g.actor) + if err != nil { + panic(err) + } + return state +} + +type GenesisHeaderService struct { + genesisCapable bool + executionService header.Service +} + +// HeaderInfo implements header.Service. +func (g *GenesisHeaderService) HeaderInfo(ctx context.Context) header.Info { + if !g.genesisCapable { + return g.executionService.HeaderInfo(ctx) + } + v := ctx.Value(genesisContextKey) + if v == nil { + return g.executionService.HeaderInfo(ctx) + } + genCtx, ok := v.(*genesisContext) + if !ok { + panic(fmt.Errorf("unexpected genesis context type: %T", v)) + } + if genCtx.didRun { + g.genesisCapable = false + return g.executionService.HeaderInfo(ctx) + } + return header.Info{} +} + +func NewGenesisHeaderService(executionService header.Service) *GenesisHeaderService { + return &GenesisHeaderService{ + genesisCapable: true, + executionService: executionService, + } +} + +var _ header.Service = (*GenesisHeaderService)(nil) diff --git a/runtime/v2/go.mod b/runtime/v2/go.mod index 4327d9d1c3e9..f4d68948f661 100644 --- a/runtime/v2/go.mod +++ b/runtime/v2/go.mod @@ -5,6 +5,7 @@ go 1.23 // server v2 integration replace ( cosmossdk.io/api => ../../api + cosmossdk.io/core => ../../core cosmossdk.io/core/testing => ../../core/testing cosmossdk.io/server/v2/appmanager => ../../server/v2/appmanager cosmossdk.io/server/v2/stf => ../../server/v2/stf diff --git a/runtime/v2/module.go b/runtime/v2/module.go index 8db0f557a57b..f07da52abcbe 100644 --- a/runtime/v2/module.go +++ b/runtime/v2/module.go @@ -16,6 +16,7 @@ import ( reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1" appmodulev2 "cosmossdk.io/core/appmodule/v2" "cosmossdk.io/core/comet" + "cosmossdk.io/core/header" "cosmossdk.io/core/registry" "cosmossdk.io/core/server" "cosmossdk.io/core/store" @@ -96,7 +97,6 @@ func init() { ProvideAppBuilder[transaction.Tx], ProvideEnvironment[transaction.Tx], ProvideModuleManager[transaction.Tx], - ProvideCometService, ), appconfig.Invoke(SetupAppBuilder), ) @@ -176,6 +176,9 @@ func ProvideEnvironment[T transaction.Tx]( config *runtimev2.Module, key depinject.ModuleKey, appBuilder *AppBuilder[T], + kvFactory store.KVStoreServiceFactory, + memFactory store.MemoryStoreServiceFactory, + headerFactory header.HeaderServiceFactory, ) ( appmodulev2.Environment, store.KVStoreService, @@ -197,11 +200,11 @@ func ProvideEnvironment[T transaction.Tx]( } registerStoreKey(appBuilder, kvStoreKey) - kvService = stf.NewKVStoreService([]byte(kvStoreKey)) + kvService = kvFactory([]byte(kvStoreKey)) memStoreKey := fmt.Sprintf("memory:%s", key.Name()) registerStoreKey(appBuilder, memStoreKey) - memKvService = stf.NewMemoryStoreService([]byte(memStoreKey)) + memKvService = memFactory([]byte(memStoreKey)) } env := appmodulev2.Environment{ @@ -209,7 +212,7 @@ func ProvideEnvironment[T transaction.Tx]( BranchService: stf.BranchService{}, EventService: stf.NewEventService(), GasService: stf.NewGasMeterService(), - HeaderService: stf.HeaderService{}, + HeaderService: headerFactory(), QueryRouterService: stf.NewQueryRouterService(), MsgRouterService: stf.NewMsgRouterService([]byte(key.Name())), TransactionService: services.NewContextAwareTransactionService(), @@ -220,8 +223,8 @@ func ProvideEnvironment[T transaction.Tx]( return env, kvService, memKvService } -func registerStoreKey[T transaction.Tx](wrapper *AppBuilder[T], key string) { - wrapper.app.storeKeys = append(wrapper.app.storeKeys, key) +func registerStoreKey[T transaction.Tx](builder *AppBuilder[T], key string) { + builder.app.storeKeys = append(builder.app.storeKeys, key) } func storeKeyOverride(config *runtimev2.Module, moduleName string) *runtimev2.StoreKeyConfig { @@ -234,6 +237,24 @@ func storeKeyOverride(config *runtimev2.Module, moduleName string) *runtimev2.St return nil } -func ProvideCometService() comet.Service { - return &services.ContextAwareCometInfoService{} +func DefaultServiceBindings() depinject.Config { + var ( + kvServiceFactory store.KVStoreServiceFactory = func(actor []byte) store.KVStoreService { + return NewGenesisKVService( + actor, + stf.NewKVStoreService(actor), + ) + } + memStoreServiceFactory store.MemoryStoreServiceFactory = stf.NewMemoryStoreService + headerServiceFactory header.HeaderServiceFactory = func() header.Service { + return NewGenesisHeaderService(stf.HeaderService{}) + } + cometService comet.Service = &services.ContextAwareCometInfoService{} + ) + return depinject.Supply( + kvServiceFactory, + memStoreServiceFactory, + cometService, + headerServiceFactory, + ) } diff --git a/server/v2/appmanager/appmanager.go b/server/v2/appmanager/appmanager.go index e367c7d8fbfe..ca6ab55b03ed 100644 --- a/server/v2/appmanager/appmanager.go +++ b/server/v2/appmanager/appmanager.go @@ -43,25 +43,19 @@ func (a AppManager[T]) InitGenesis( initGenesisJSON []byte, txDecoder transaction.Codec[T], ) (*server.BlockResponse, corestore.WriterMap, error) { - v, zeroState, err := a.db.StateLatest() - if err != nil { - return nil, 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, nil, errors.New("cannot init genesis on non-zero state") - } - var genTxs []T - genesisState, err := a.stf.RunWithCtx(ctx, zeroState, func(ctx context.Context) error { - return a.initGenesis(ctx, bytes.NewBuffer(initGenesisJSON), func(jsonTx json.RawMessage) error { + genesisState, err := a.initGenesis( + ctx, + bytes.NewBuffer(initGenesisJSON), + func(jsonTx json.RawMessage) error { genTx, err := txDecoder.DecodeJSON(jsonTx) if err != nil { return fmt.Errorf("failed to decode genesis transaction: %w", err) } genTxs = append(genTxs, genTx) return nil - }) - }) + }, + ) if err != nil { return nil, nil, fmt.Errorf("failed to import genesis state: %w", err) } @@ -70,7 +64,11 @@ func (a AppManager[T]) InitGenesis( blockResponse, blockZeroState, err := a.stf.DeliverBlock(ctx, blockRequest, genesisState) if err != nil { - return blockResponse, nil, fmt.Errorf("failed to deliver block %d: %w", blockRequest.Height, err) + return blockResponse, nil, fmt.Errorf( + "failed to deliver block %d: %w", + blockRequest.Height, + err, + ) } // after executing block 0, we extract the changes and apply them to the genesis state. @@ -81,7 +79,10 @@ func (a AppManager[T]) InitGenesis( err = genesisState.ApplyStateChanges(stateChanges) if err != nil { - return nil, nil, fmt.Errorf("failed to apply block zero state changes to genesis state: %w", err) + return nil, nil, fmt.Errorf( + "failed to apply block zero state changes to genesis state: %w", + err, + ) } return blockResponse, genesisState, err @@ -120,11 +121,19 @@ func (a AppManager[T]) DeliverBlock( ) (*server.BlockResponse, corestore.WriterMap, error) { latestVersion, currentState, err := a.db.StateLatest() if err != nil { - return nil, nil, fmt.Errorf("unable to create new state for height %d: %w", block.Height, err) + return nil, nil, fmt.Errorf( + "unable to create new state for height %d: %w", + block.Height, + err, + ) } if latestVersion+1 != block.Height { - return nil, nil, fmt.Errorf("invalid DeliverBlock height wanted %d, got %d", latestVersion+1, block.Height) + return nil, nil, fmt.Errorf( + "invalid DeliverBlock height wanted %d, got %d", + latestVersion+1, + block.Height, + ) } blockResponse, newState, err := a.stf.DeliverBlock(ctx, block, currentState) @@ -148,18 +157,30 @@ func (a AppManager[T]) ValidateTx(ctx context.Context, tx T) (server.TxResult, e } // Simulate runs validation and execution flow of a Tx. -func (a AppManager[T]) Simulate(ctx context.Context, tx T) (server.TxResult, corestore.WriterMap, error) { +func (a AppManager[T]) Simulate( + ctx context.Context, + tx T, +) (server.TxResult, corestore.WriterMap, error) { _, state, err := a.db.StateLatest() if err != nil { return server.TxResult{}, nil, err } - result, cs := a.stf.Simulate(ctx, state, a.config.SimulationGasLimit, tx) // TODO: check if this is done in the antehandler + result, cs := a.stf.Simulate( + ctx, + state, + a.config.SimulationGasLimit, + tx, + ) // TODO: check if this is done in the antehandler return result, cs, nil } // Query queries the application at the provided version. // CONTRACT: Version must always be provided, if 0, get latest -func (a AppManager[T]) Query(ctx context.Context, version uint64, request transaction.Msg) (transaction.Msg, error) { +func (a AppManager[T]) Query( + ctx context.Context, + version uint64, + request transaction.Msg, +) (transaction.Msg, error) { // if version is provided attempt to do a height query. if version != 0 { queryState, err := a.db.StateAt(version) diff --git a/server/v2/appmanager/genesis.go b/server/v2/appmanager/genesis.go index 8acad003b694..989ae442a9b9 100644 --- a/server/v2/appmanager/genesis.go +++ b/server/v2/appmanager/genesis.go @@ -4,11 +4,25 @@ import ( "context" "encoding/json" "io" + + "cosmossdk.io/core/store" ) type ( // ExportGenesis is a function type that represents the export of the genesis state. ExportGenesis func(ctx context.Context, version uint64) ([]byte, error) - // InitGenesis is a function type that represents the initialization of the genesis state. - InitGenesis func(ctx context.Context, src io.Reader, txHandler func(json.RawMessage) error) error + + // InitGenesis is a function that will run at application genesis, it will be called with + // the following arguments: + // - ctx: the context of the genesis operation + // - src: the source containing the raw genesis state + // - txHandler: a function capable of decoding a json tx, will be run for each genesis + // transaction + // + // It must return a map of the dirty state after the genesis operation. + InitGenesis func( + ctx context.Context, + src io.Reader, + txHandler func(json.RawMessage) error, + ) (store.WriterMap, error) ) diff --git a/simapp/v2/app_di.go b/simapp/v2/app_di.go index 733ab1ffc829..3c4e9f5db5b3 100644 --- a/simapp/v2/app_di.go +++ b/simapp/v2/app_di.go @@ -71,6 +71,7 @@ func NewSimApp[T transaction.Tx]( // merge the AppConfig and other configuration in one config appConfig = depinject.Configs( AppConfig(), + runtime.DefaultServiceBindings(), depinject.Supply( logger, viper, diff --git a/simapp/v2/go.mod b/simapp/v2/go.mod index e4003e4c9012..d61f3c214d3c 100644 --- a/simapp/v2/go.mod +++ b/simapp/v2/go.mod @@ -286,6 +286,7 @@ replace ( // server v2 integration replace ( cosmossdk.io/api => ../../api + cosmossdk.io/core => ../../core cosmossdk.io/core/testing => ../../core/testing cosmossdk.io/runtime/v2 => ../../runtime/v2 cosmossdk.io/server/v2 => ../../server/v2 diff --git a/simapp/v2/simdv2/cmd/root_di.go b/simapp/v2/simdv2/cmd/root_di.go index fd5b62b9384b..130130b8e57f 100644 --- a/simapp/v2/simdv2/cmd/root_di.go +++ b/simapp/v2/simdv2/cmd/root_di.go @@ -37,6 +37,7 @@ func NewRootCmd[T transaction.Tx]() *cobra.Command { if err := depinject.Inject( depinject.Configs( simapp.AppConfig(), + runtime.DefaultServiceBindings(), depinject.Supply(log.NewNopLogger()), depinject.Provide( codec.ProvideInterfaceRegistry, @@ -69,7 +70,11 @@ func NewRootCmd[T transaction.Tx]() *cobra.Command { } customClientTemplate, customClientConfig := initClientConfig() - clientCtx, err = config.CreateClientConfig(clientCtx, customClientTemplate, customClientConfig) + clientCtx, err = config.CreateClientConfig( + clientCtx, + customClientTemplate, + customClientConfig, + ) if err != nil { return err } @@ -108,7 +113,9 @@ func ProvideClientContext( amino, ok := legacyAmino.(*codec.LegacyAmino) if !ok { - panic("registry.AminoRegistrar must be an *codec.LegacyAmino instance for legacy ClientContext") + panic( + "registry.AminoRegistrar must be an *codec.LegacyAmino instance for legacy ClientContext", + ) } clientCtx := client.Context{}. @@ -125,7 +132,11 @@ func ProvideClientContext( // Read the config to overwrite the default values with the values from the config file customClientTemplate, customClientConfig := initClientConfig() - clientCtx, err = config.CreateClientConfig(clientCtx, customClientTemplate, customClientConfig) + clientCtx, err = config.CreateClientConfig( + clientCtx, + customClientTemplate, + customClientConfig, + ) if err != nil { panic(err) } From 30814acab941a5d566f30164bc56ffc72ddcdf2f Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Sun, 15 Sep 2024 14:45:05 -0500 Subject: [PATCH 02/13] migrate export genesis and remove stf.RunWithCtx --- .vscode/launch.json | 2 +- runtime/v2/builder.go | 12 ++++++++- runtime/v2/genesis.go | 24 +++++------------- server/v2/appmanager/appmanager.go | 24 +++--------------- server/v2/appmanager/types.go | 8 ------ server/v2/stf/stf.go | 39 ++++++++++++++++++------------ 6 files changed, 44 insertions(+), 65 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index a5e7a729457b..5e7c4837581e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -18,7 +18,7 @@ "request": "launch", "mode": "debug", "program": "${workspaceFolder}/simapp/v2/simdv2", - "args": ["start"], + "args": ["genesis", "export"], "buildFlags": "" }, { diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index 5120725bea19..fc370a2ffe11 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -198,7 +198,17 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { return genesisState, err }, ExportGenesis: func(ctx context.Context, version uint64) ([]byte, error) { - genesisJson, err := a.app.moduleManager.ExportGenesisForModules(ctx) + _, state, err := a.app.db.StateLatest() + if err != nil { + return nil, fmt.Errorf("unable to get latest state: %w", err) + } + genesisCtx := makeGenesisContext(a.branch(state)) + + var genesisJson map[string]json.RawMessage + _, err = genesisCtx.Run(ctx, func(ctx context.Context) error { + genesisJson, err = a.app.moduleManager.ExportGenesisForModules(ctx) + return err + }) if err != nil { return nil, fmt.Errorf("failed to export genesis: %w", err) } diff --git a/runtime/v2/genesis.go b/runtime/v2/genesis.go index 0dea54c97790..5bb2fef72b7b 100644 --- a/runtime/v2/genesis.go +++ b/runtime/v2/genesis.go @@ -39,9 +39,8 @@ func (g *genesisContext) Run( } type GenesisKVStoreServie struct { - genesisCapable bool - actor []byte - execution store.KVStoreService + actor []byte + executionService store.KVStoreService } func NewGenesisKVService( @@ -49,28 +48,23 @@ func NewGenesisKVService( execution store.KVStoreService, ) *GenesisKVStoreServie { return &GenesisKVStoreServie{ - genesisCapable: true, - actor: actor, - execution: execution, + actor: actor, + executionService: execution, } } // OpenKVStore implements store.KVStoreService. func (g *GenesisKVStoreServie) OpenKVStore(ctx context.Context) store.KVStore { - if !g.genesisCapable { - return g.execution.OpenKVStore(ctx) - } v := ctx.Value(genesisContextKey) if v == nil { - return g.execution.OpenKVStore(ctx) + return g.executionService.OpenKVStore(ctx) } genCtx, ok := v.(*genesisContext) if !ok { panic(fmt.Errorf("unexpected genesis context type: %T", v)) } if genCtx.didRun { - g.genesisCapable = false - return g.execution.OpenKVStore(ctx) + return g.executionService.OpenKVStore(ctx) } state, err := genCtx.state.GetWriter(g.actor) if err != nil { @@ -80,15 +74,11 @@ func (g *GenesisKVStoreServie) OpenKVStore(ctx context.Context) store.KVStore { } type GenesisHeaderService struct { - genesisCapable bool executionService header.Service } // HeaderInfo implements header.Service. func (g *GenesisHeaderService) HeaderInfo(ctx context.Context) header.Info { - if !g.genesisCapable { - return g.executionService.HeaderInfo(ctx) - } v := ctx.Value(genesisContextKey) if v == nil { return g.executionService.HeaderInfo(ctx) @@ -98,7 +88,6 @@ func (g *GenesisHeaderService) HeaderInfo(ctx context.Context) header.Info { panic(fmt.Errorf("unexpected genesis context type: %T", v)) } if genCtx.didRun { - g.genesisCapable = false return g.executionService.HeaderInfo(ctx) } return header.Info{} @@ -106,7 +95,6 @@ func (g *GenesisHeaderService) HeaderInfo(ctx context.Context) header.Info { func NewGenesisHeaderService(executionService header.Service) *GenesisHeaderService { return &GenesisHeaderService{ - genesisCapable: true, executionService: executionService, } } diff --git a/server/v2/appmanager/appmanager.go b/server/v2/appmanager/appmanager.go index ca6ab55b03ed..869d7e6d1dba 100644 --- a/server/v2/appmanager/appmanager.go +++ b/server/v2/appmanager/appmanager.go @@ -90,29 +90,11 @@ func (a AppManager[T]) InitGenesis( // ExportGenesis exports the genesis state of the application. func (a AppManager[T]) ExportGenesis(ctx context.Context, version uint64) ([]byte, error) { - zeroState, err := a.db.StateAt(version) - if err != nil { - return nil, fmt.Errorf("unable to get latest state: %w", err) - } - - bz := make([]byte, 0) - _, err = a.stf.RunWithCtx(ctx, zeroState, func(ctx context.Context) error { - if a.exportGenesis == nil { - return errors.New("export genesis function not set") - } - - bz, err = a.exportGenesis(ctx, version) - if err != nil { - return fmt.Errorf("failed to export genesis state: %w", err) - } - - return nil - }) - if err != nil { - return nil, fmt.Errorf("failed to export genesis state: %w", err) + if a.exportGenesis == nil { + return nil, errors.New("export genesis function not set") } - return bz, nil + return a.exportGenesis(ctx, version) } func (a AppManager[T]) DeliverBlock( diff --git a/server/v2/appmanager/types.go b/server/v2/appmanager/types.go index 149f190f353e..1e769c13ff9c 100644 --- a/server/v2/appmanager/types.go +++ b/server/v2/appmanager/types.go @@ -40,12 +40,4 @@ type StateTransitionFunction[T transaction.Tx] interface { gasLimit uint64, req transaction.Msg, ) (transaction.Msg, error) - - // RunWithCtx executes the provided closure within a context. - // TODO: remove - RunWithCtx( - ctx context.Context, - state store.ReaderMap, - closure func(ctx context.Context) error, - ) (store.WriterMap, error) } diff --git a/server/v2/stf/stf.go b/server/v2/stf/stf.go index e32a8f33293e..02b5f941f9c5 100644 --- a/server/v2/stf/stf.go +++ b/server/v2/stf/stf.go @@ -202,7 +202,14 @@ func (s STF[T]) deliverTx( } } - execResp, execGas, execEvents, err := s.execTx(ctx, state, gasLimit-validateGas, tx, execMode, hi) + execResp, execGas, execEvents, err := s.execTx( + ctx, + state, + gasLimit-validateGas, + tx, + execMode, + hi, + ) return server.TxResult{ Events: append(validationEvents, execEvents...), GasUsed: execGas + validateGas, @@ -250,7 +257,14 @@ func (s STF[T]) execTx( ) ([]transaction.Msg, uint64, []event.Event, error) { execState := s.branchFn(state) - msgsResp, gasUsed, runTxMsgsEvents, txErr := s.runTxMsgs(ctx, execState, gasLimit, tx, execMode, hi) + msgsResp, gasUsed, runTxMsgsEvents, txErr := s.runTxMsgs( + ctx, + execState, + gasLimit, + tx, + execMode, + hi, + ) if txErr != nil { // in case of error during message execution, we do not apply the exec state. // instead we run the post exec handler in a new branchFn from the initial state. @@ -430,7 +444,13 @@ func (s STF[T]) ValidateTx( tx T, ) server.TxResult { validationState := s.branchFn(state) - gasUsed, events, err := s.validateTx(ctx, validationState, gasLimit, tx, transaction.ExecModeCheck) + gasUsed, events, err := s.validateTx( + ctx, + validationState, + gasLimit, + tx, + transaction.ExecModeCheck, + ) return server.TxResult{ Events: events, GasUsed: gasUsed, @@ -456,19 +476,6 @@ func (s STF[T]) Query( return s.queryRouter.Invoke(queryCtx, req) } -// RunWithCtx is made to support genesis, if genesis was just the execution of messages instead -// of being something custom then we would not need this. PLEASE DO NOT USE. -// TODO: Remove -func (s STF[T]) RunWithCtx( - ctx context.Context, - state store.ReaderMap, - closure func(ctx context.Context) error, -) (store.WriterMap, error) { - branchedState := s.branchFn(state) - stfCtx := s.makeContext(ctx, nil, branchedState, internal.ExecModeFinalize) - return branchedState, closure(stfCtx) -} - // clone clones STF. func (s STF[T]) clone() STF[T] { return STF[T]{ From ef50b4f036c65064b7fa5aff96a1d3a705c8e9c0 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Sun, 15 Sep 2024 22:16:08 -0500 Subject: [PATCH 03/13] revert line wrapping --- runtime/v2/builder.go | 20 +++---------- server/v2/appmanager/appmanager.go | 47 +++++------------------------- server/v2/stf/stf.go | 26 ++--------------- simapp/v2/simdv2/cmd/root_di.go | 16 ++-------- 4 files changed, 18 insertions(+), 91 deletions(-) diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index fc370a2ffe11..f21c38639e20 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -46,13 +46,7 @@ func (a *AppBuilder[T]) RegisterModules(modules map[string]appmodulev2.AppModule // if a (legacy) module implements the HasName interface, check that the name matches if mod, ok := appModule.(interface{ Name() string }); ok { if name != mod.Name() { - a.app.logger.Warn( - fmt.Sprintf( - "module name %q does not match name returned by HasName: %q", - name, - mod.Name(), - ), - ) + a.app.logger.Warn(fmt.Sprintf("module name %q does not match name returned by HasName: %q", name, mod.Name())) } } @@ -235,9 +229,7 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { type AppBuilderOption[T transaction.Tx] func(*AppBuilder[T]) // AppBuilderWithBranch sets a custom branch implementation for the app. -func AppBuilderWithBranch[T transaction.Tx]( - branch func(state store.ReaderMap) store.WriterMap, -) AppBuilderOption[T] { +func AppBuilderWithBranch[T transaction.Tx](branch func(state store.ReaderMap) store.WriterMap) AppBuilderOption[T] { return func(a *AppBuilder[T]) { a.branch = branch } @@ -245,9 +237,7 @@ func AppBuilderWithBranch[T transaction.Tx]( // AppBuilderWithTxValidator sets the tx validator for the app. // It overrides all default tx validators defined by modules. -func AppBuilderWithTxValidator[T transaction.Tx]( - txValidators func(ctx context.Context, tx T) error, -) AppBuilderOption[T] { +func AppBuilderWithTxValidator[T transaction.Tx](txValidators func(ctx context.Context, tx T) error) AppBuilderOption[T] { return func(a *AppBuilder[T]) { a.txValidator = txValidators } @@ -255,9 +245,7 @@ func AppBuilderWithTxValidator[T transaction.Tx]( // AppBuilderWithPostTxExec sets logic that will be executed after each transaction. // When not provided, a no-op function will be used. -func AppBuilderWithPostTxExec[T transaction.Tx]( - postTxExec func(ctx context.Context, tx T, success bool) error, -) AppBuilderOption[T] { +func AppBuilderWithPostTxExec[T transaction.Tx](postTxExec func(ctx context.Context, tx T, success bool) error) AppBuilderOption[T] { return func(a *AppBuilder[T]) { a.postTxExec = postTxExec } diff --git a/server/v2/appmanager/appmanager.go b/server/v2/appmanager/appmanager.go index 869d7e6d1dba..6a5f96ec5fa9 100644 --- a/server/v2/appmanager/appmanager.go +++ b/server/v2/appmanager/appmanager.go @@ -64,11 +64,7 @@ func (a AppManager[T]) InitGenesis( blockResponse, blockZeroState, err := a.stf.DeliverBlock(ctx, blockRequest, genesisState) if err != nil { - return blockResponse, nil, fmt.Errorf( - "failed to deliver block %d: %w", - blockRequest.Height, - err, - ) + return blockResponse, nil, fmt.Errorf("failed to deliver block %d: %w", blockRequest.Height, err) } // after executing block 0, we extract the changes and apply them to the genesis state. @@ -79,10 +75,7 @@ func (a AppManager[T]) InitGenesis( err = genesisState.ApplyStateChanges(stateChanges) if err != nil { - return nil, nil, fmt.Errorf( - "failed to apply block zero state changes to genesis state: %w", - err, - ) + return nil, nil, fmt.Errorf("failed to apply block zero state changes to genesis state: %w", err) } return blockResponse, genesisState, err @@ -103,19 +96,11 @@ func (a AppManager[T]) DeliverBlock( ) (*server.BlockResponse, corestore.WriterMap, error) { latestVersion, currentState, err := a.db.StateLatest() if err != nil { - return nil, nil, fmt.Errorf( - "unable to create new state for height %d: %w", - block.Height, - err, - ) + return nil, nil, fmt.Errorf("unable to create new state for height %d: %w", block.Height, err) } if latestVersion+1 != block.Height { - return nil, nil, fmt.Errorf( - "invalid DeliverBlock height wanted %d, got %d", - latestVersion+1, - block.Height, - ) + return nil, nil, fmt.Errorf("invalid DeliverBlock height wanted %d, got %d", latestVersion+1, block.Height) } blockResponse, newState, err := a.stf.DeliverBlock(ctx, block, currentState) @@ -139,30 +124,18 @@ func (a AppManager[T]) ValidateTx(ctx context.Context, tx T) (server.TxResult, e } // Simulate runs validation and execution flow of a Tx. -func (a AppManager[T]) Simulate( - ctx context.Context, - tx T, -) (server.TxResult, corestore.WriterMap, error) { +func (a AppManager[T]) Simulate(ctx context.Context, tx T) (server.TxResult, corestore.WriterMap, error) { _, state, err := a.db.StateLatest() if err != nil { return server.TxResult{}, nil, err } - result, cs := a.stf.Simulate( - ctx, - state, - a.config.SimulationGasLimit, - tx, - ) // TODO: check if this is done in the antehandler + result, cs := a.stf.Simulate(ctx, state, a.config.SimulationGasLimit, tx) // TODO: check if this is done in the antehandler return result, cs, nil } // Query queries the application at the provided version. // CONTRACT: Version must always be provided, if 0, get latest -func (a AppManager[T]) Query( - ctx context.Context, - version uint64, - request transaction.Msg, -) (transaction.Msg, error) { +func (a AppManager[T]) Query(ctx context.Context, version uint64, request transaction.Msg) (transaction.Msg, error) { // if version is provided attempt to do a height query. if version != 0 { queryState, err := a.db.StateAt(version) @@ -183,10 +156,6 @@ func (a AppManager[T]) Query( // QueryWithState executes a query with the provided state. This allows to process a query // independently of the db state. For example, it can be used to process a query with temporary // and uncommitted state -func (a AppManager[T]) QueryWithState( - ctx context.Context, - state corestore.ReaderMap, - request transaction.Msg, -) (transaction.Msg, error) { +func (a AppManager[T]) QueryWithState(ctx context.Context, state corestore.ReaderMap, request transaction.Msg) (transaction.Msg, error) { return a.stf.Query(ctx, state, a.config.QueryGasLimit, request) } diff --git a/server/v2/stf/stf.go b/server/v2/stf/stf.go index 02b5f941f9c5..06a993fd91e3 100644 --- a/server/v2/stf/stf.go +++ b/server/v2/stf/stf.go @@ -202,14 +202,7 @@ func (s STF[T]) deliverTx( } } - execResp, execGas, execEvents, err := s.execTx( - ctx, - state, - gasLimit-validateGas, - tx, - execMode, - hi, - ) + execResp, execGas, execEvents, err := s.execTx(ctx, state, gasLimit-validateGas, tx, execMode, hi) return server.TxResult{ Events: append(validationEvents, execEvents...), GasUsed: execGas + validateGas, @@ -257,14 +250,7 @@ func (s STF[T]) execTx( ) ([]transaction.Msg, uint64, []event.Event, error) { execState := s.branchFn(state) - msgsResp, gasUsed, runTxMsgsEvents, txErr := s.runTxMsgs( - ctx, - execState, - gasLimit, - tx, - execMode, - hi, - ) + msgsResp, gasUsed, runTxMsgsEvents, txErr := s.runTxMsgs(ctx, execState, gasLimit, tx, execMode, hi) if txErr != nil { // in case of error during message execution, we do not apply the exec state. // instead we run the post exec handler in a new branchFn from the initial state. @@ -444,13 +430,7 @@ func (s STF[T]) ValidateTx( tx T, ) server.TxResult { validationState := s.branchFn(state) - gasUsed, events, err := s.validateTx( - ctx, - validationState, - gasLimit, - tx, - transaction.ExecModeCheck, - ) + gasUsed, events, err := s.validateTx(ctx, validationState, gasLimit, tx, transaction.ExecModeCheck) return server.TxResult{ Events: events, GasUsed: gasUsed, diff --git a/simapp/v2/simdv2/cmd/root_di.go b/simapp/v2/simdv2/cmd/root_di.go index 130130b8e57f..1ad834b53a5a 100644 --- a/simapp/v2/simdv2/cmd/root_di.go +++ b/simapp/v2/simdv2/cmd/root_di.go @@ -70,11 +70,7 @@ func NewRootCmd[T transaction.Tx]() *cobra.Command { } customClientTemplate, customClientConfig := initClientConfig() - clientCtx, err = config.CreateClientConfig( - clientCtx, - customClientTemplate, - customClientConfig, - ) + clientCtx, err = config.CreateClientConfig(clientCtx, customClientTemplate, customClientConfig) if err != nil { return err } @@ -113,9 +109,7 @@ func ProvideClientContext( amino, ok := legacyAmino.(*codec.LegacyAmino) if !ok { - panic( - "registry.AminoRegistrar must be an *codec.LegacyAmino instance for legacy ClientContext", - ) + panic("registry.AminoRegistrar must be an *codec.LegacyAmino instance for legacy ClientContext") } clientCtx := client.Context{}. @@ -132,11 +126,7 @@ func ProvideClientContext( // Read the config to overwrite the default values with the values from the config file customClientTemplate, customClientConfig := initClientConfig() - clientCtx, err = config.CreateClientConfig( - clientCtx, - customClientTemplate, - customClientConfig, - ) + clientCtx, err = config.CreateClientConfig(clientCtx, customClientTemplate, customClientConfig) if err != nil { panic(err) } From 177a0da035c57387905b197fa5594c59f747c71f Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 16 Sep 2024 08:57:51 -0500 Subject: [PATCH 04/13] small refactor move genesis services --- runtime/v2/builder.go | 5 +++-- runtime/v2/module.go | 4 ++-- runtime/v2/{ => services}/genesis.go | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) rename runtime/v2/{ => services}/genesis.go (96%) diff --git a/runtime/v2/builder.go b/runtime/v2/builder.go index f21c38639e20..65b128572c33 100644 --- a/runtime/v2/builder.go +++ b/runtime/v2/builder.go @@ -13,6 +13,7 @@ import ( "cosmossdk.io/core/server" "cosmossdk.io/core/store" "cosmossdk.io/core/transaction" + "cosmossdk.io/runtime/v2/services" "cosmossdk.io/server/v2/appmanager" "cosmossdk.io/server/v2/stf" "cosmossdk.io/server/v2/stf/branch" @@ -180,7 +181,7 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { 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 := makeGenesisContext(a.branch(zeroState)) + genesisCtx := services.NewGenesisContext(a.branch(zeroState)) genesisState, err := genesisCtx.Run(ctx, func(ctx context.Context) error { err = a.app.moduleManager.InitGenesisJSON(ctx, genesisJSON, txHandler) if err != nil { @@ -196,7 +197,7 @@ func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) { if err != nil { return nil, fmt.Errorf("unable to get latest state: %w", err) } - genesisCtx := makeGenesisContext(a.branch(state)) + genesisCtx := services.NewGenesisContext(a.branch(state)) var genesisJson map[string]json.RawMessage _, err = genesisCtx.Run(ctx, func(ctx context.Context) error { diff --git a/runtime/v2/module.go b/runtime/v2/module.go index f07da52abcbe..60e2e2c96878 100644 --- a/runtime/v2/module.go +++ b/runtime/v2/module.go @@ -240,14 +240,14 @@ func storeKeyOverride(config *runtimev2.Module, moduleName string) *runtimev2.St func DefaultServiceBindings() depinject.Config { var ( kvServiceFactory store.KVStoreServiceFactory = func(actor []byte) store.KVStoreService { - return NewGenesisKVService( + return services.NewGenesisKVService( actor, stf.NewKVStoreService(actor), ) } memStoreServiceFactory store.MemoryStoreServiceFactory = stf.NewMemoryStoreService headerServiceFactory header.HeaderServiceFactory = func() header.Service { - return NewGenesisHeaderService(stf.HeaderService{}) + return services.NewGenesisHeaderService(stf.HeaderService{}) } cometService comet.Service = &services.ContextAwareCometInfoService{} ) diff --git a/runtime/v2/genesis.go b/runtime/v2/services/genesis.go similarity index 96% rename from runtime/v2/genesis.go rename to runtime/v2/services/genesis.go index 5bb2fef72b7b..7a0839e48322 100644 --- a/runtime/v2/genesis.go +++ b/runtime/v2/services/genesis.go @@ -1,4 +1,4 @@ -package runtime +package services import ( "context" @@ -19,7 +19,7 @@ type genesisContext struct { didRun bool } -func makeGenesisContext(state store.WriterMap) genesisContext { +func NewGenesisContext(state store.WriterMap) genesisContext { return genesisContext{ state: state, } From 45ff83a1f96147ce32577ad54da29784be6522be Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 16 Sep 2024 08:58:35 -0500 Subject: [PATCH 05/13] go mod tidy all --- runtime/v2/go.sum | 2 -- simapp/v2/go.sum | 2 -- 2 files changed, 4 deletions(-) diff --git a/runtime/v2/go.sum b/runtime/v2/go.sum index 30d27ab50056..6a4643be1e08 100644 --- a/runtime/v2/go.sum +++ b/runtime/v2/go.sum @@ -2,8 +2,6 @@ buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.34.2-20240701160653-fed buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.34.2-20240701160653-fedbb9acfd2f.2/go.mod h1:1+3gJj2NvZ1mTLAtHu+lMhOjGgQPiCKCeo+9MBww0Eo= buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88ef6483f90f.2 h1:b7EEYTUHmWSBEyISHlHvXbJPqtKiHRuUignL1tsHnNQ= buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88ef6483f90f.2/go.mod h1:HqcXMSa5qnNuakaMUo+hWhF51mKbcrZxGl9Vp5EeJXc= -cosmossdk.io/core v1.0.0-alpha.2 h1:epU0Xwces4Rgl5bMhHHkXGaGDcyucNGlC/JDH+Suckg= -cosmossdk.io/core v1.0.0-alpha.2/go.mod h1:abgLjeFLhtuKIYZWSPlVUgQBrKObO7ULV35KYfexE90= cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050= cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8= cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 h1:IQNdY2kB+k+1OM2DvqFG1+UgeU1JzZrWtwuWzI3ZfwA= diff --git a/simapp/v2/go.sum b/simapp/v2/go.sum index ede14d58a04e..4856648b3768 100644 --- a/simapp/v2/go.sum +++ b/simapp/v2/go.sum @@ -192,8 +192,6 @@ cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xX cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cosmossdk.io/core v1.0.0-alpha.2 h1:epU0Xwces4Rgl5bMhHHkXGaGDcyucNGlC/JDH+Suckg= -cosmossdk.io/core v1.0.0-alpha.2/go.mod h1:abgLjeFLhtuKIYZWSPlVUgQBrKObO7ULV35KYfexE90= cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050= cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= From 16a0e996cc6b8e4d134ab41829bad46e81fd8f1d Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 16 Sep 2024 08:59:08 -0500 Subject: [PATCH 06/13] revert vscode change --- .vscode/launch.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 5e7c4837581e..a5e7a729457b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -18,7 +18,7 @@ "request": "launch", "mode": "debug", "program": "${workspaceFolder}/simapp/v2/simdv2", - "args": ["genesis", "export"], + "args": ["start"], "buildFlags": "" }, { From 9fe10204d02b15d7096857aa272fc2f650d3c09d Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 16 Sep 2024 09:41:36 -0500 Subject: [PATCH 07/13] update genesis service --- runtime/v2/services/genesis.go | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/runtime/v2/services/genesis.go b/runtime/v2/services/genesis.go index 7a0839e48322..8f09520336ab 100644 --- a/runtime/v2/services/genesis.go +++ b/runtime/v2/services/genesis.go @@ -15,8 +15,7 @@ type genesisContextKeyType struct{} var genesisContextKey = genesisContextKeyType{} type genesisContext struct { - state store.WriterMap - didRun bool + state store.WriterMap } func NewGenesisContext(state store.WriterMap) genesisContext { @@ -34,7 +33,6 @@ func (g *genesisContext) Run( if err != nil { return nil, err } - g.didRun = true return g.state, nil } @@ -63,9 +61,6 @@ func (g *GenesisKVStoreServie) OpenKVStore(ctx context.Context) store.KVStore { if !ok { panic(fmt.Errorf("unexpected genesis context type: %T", v)) } - if genCtx.didRun { - return g.executionService.OpenKVStore(ctx) - } state, err := genCtx.state.GetWriter(g.actor) if err != nil { panic(err) @@ -83,13 +78,6 @@ func (g *GenesisHeaderService) HeaderInfo(ctx context.Context) header.Info { if v == nil { return g.executionService.HeaderInfo(ctx) } - genCtx, ok := v.(*genesisContext) - if !ok { - panic(fmt.Errorf("unexpected genesis context type: %T", v)) - } - if genCtx.didRun { - return g.executionService.HeaderInfo(ctx) - } return header.Info{} } From 80db042ec6f6773f706ccb8bf1c04e6e31eecb6e Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 16 Sep 2024 10:15:46 -0500 Subject: [PATCH 08/13] clean up --- core/header/service.go | 2 -- core/store/service.go | 5 +++-- runtime/v2/module.go | 17 ++++++----------- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/core/header/service.go b/core/header/service.go index 29ee248f1389..8d36087a059c 100644 --- a/core/header/service.go +++ b/core/header/service.go @@ -13,8 +13,6 @@ type Service interface { HeaderInfo(context.Context) Info } -type HeaderServiceFactory func() Service - // Info defines a struct that contains information about the header type Info struct { Height int64 // Height returns the height of the block diff --git a/core/store/service.go b/core/store/service.go index 60d4c023cc30..6faec8bdb0ce 100644 --- a/core/store/service.go +++ b/core/store/service.go @@ -10,6 +10,9 @@ type KVStoreService interface { OpenKVStore(context.Context) KVStore } +// KVStoreServiceFactory is a function that creates a new KVStoreService. +// It can be used to override the default KVStoreService bindings for cases +// where an application must supply a custom stateful backend. type KVStoreServiceFactory func([]byte) KVStoreService // MemoryStoreService represents a unique, non-forgeable handle to a memory-backed @@ -20,8 +23,6 @@ type MemoryStoreService interface { OpenMemoryStore(context.Context) KVStore } -type MemoryStoreServiceFactory func([]byte) MemoryStoreService - // TransientStoreService represents a unique, non-forgeable handle to a memory-backed // KVStore which is reset at the start of every block. It should be provided as // a module-scoped dependency by the runtime module being used to build the app. diff --git a/runtime/v2/module.go b/runtime/v2/module.go index 60e2e2c96878..9f55024af893 100644 --- a/runtime/v2/module.go +++ b/runtime/v2/module.go @@ -177,8 +177,7 @@ func ProvideEnvironment[T transaction.Tx]( key depinject.ModuleKey, appBuilder *AppBuilder[T], kvFactory store.KVStoreServiceFactory, - memFactory store.MemoryStoreServiceFactory, - headerFactory header.HeaderServiceFactory, + headerService header.Service, ) ( appmodulev2.Environment, store.KVStoreService, @@ -204,7 +203,7 @@ func ProvideEnvironment[T transaction.Tx]( memStoreKey := fmt.Sprintf("memory:%s", key.Name()) registerStoreKey(appBuilder, memStoreKey) - memKvService = memFactory([]byte(memStoreKey)) + memKvService = stf.NewMemoryStoreService([]byte(memStoreKey)) } env := appmodulev2.Environment{ @@ -212,7 +211,7 @@ func ProvideEnvironment[T transaction.Tx]( BranchService: stf.BranchService{}, EventService: stf.NewEventService(), GasService: stf.NewGasMeterService(), - HeaderService: headerFactory(), + HeaderService: headerService, QueryRouterService: stf.NewQueryRouterService(), MsgRouterService: stf.NewMsgRouterService([]byte(key.Name())), TransactionService: services.NewContextAwareTransactionService(), @@ -245,16 +244,12 @@ func DefaultServiceBindings() depinject.Config { stf.NewKVStoreService(actor), ) } - memStoreServiceFactory store.MemoryStoreServiceFactory = stf.NewMemoryStoreService - headerServiceFactory header.HeaderServiceFactory = func() header.Service { - return services.NewGenesisHeaderService(stf.HeaderService{}) - } - cometService comet.Service = &services.ContextAwareCometInfoService{} + headerService header.Service = services.NewGenesisHeaderService(stf.HeaderService{}) + cometService comet.Service = &services.ContextAwareCometInfoService{} ) return depinject.Supply( kvServiceFactory, - memStoreServiceFactory, + headerService, cometService, - headerServiceFactory, ) } From 57ec23946fcc6c8322393c2b11ec56996e78dcd7 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 16 Sep 2024 10:17:02 -0500 Subject: [PATCH 09/13] fix typo --- runtime/v2/services/genesis.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/runtime/v2/services/genesis.go b/runtime/v2/services/genesis.go index 8f09520336ab..72db330667c7 100644 --- a/runtime/v2/services/genesis.go +++ b/runtime/v2/services/genesis.go @@ -8,7 +8,7 @@ import ( "cosmossdk.io/core/store" ) -var _ store.KVStoreService = (*GenesisKVStoreServie)(nil) +var _ store.KVStoreService = (*GenesisKVStoreService)(nil) type genesisContextKeyType struct{} @@ -36,7 +36,7 @@ func (g *genesisContext) Run( return g.state, nil } -type GenesisKVStoreServie struct { +type GenesisKVStoreService struct { actor []byte executionService store.KVStoreService } @@ -44,15 +44,15 @@ type GenesisKVStoreServie struct { func NewGenesisKVService( actor []byte, execution store.KVStoreService, -) *GenesisKVStoreServie { - return &GenesisKVStoreServie{ +) *GenesisKVStoreService { + return &GenesisKVStoreService{ actor: actor, executionService: execution, } } // OpenKVStore implements store.KVStoreService. -func (g *GenesisKVStoreServie) OpenKVStore(ctx context.Context) store.KVStore { +func (g *GenesisKVStoreService) OpenKVStore(ctx context.Context) store.KVStore { v := ctx.Value(genesisContextKey) if v == nil { return g.executionService.OpenKVStore(ctx) From c20649d97f996c0d6c90295c541fbb1aef519110 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 16 Sep 2024 11:18:01 -0500 Subject: [PATCH 10/13] fix test --- server/v2/cometbft/abci_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/v2/cometbft/abci_test.go b/server/v2/cometbft/abci_test.go index 0a4f1b16f975..991611ccfc62 100644 --- a/server/v2/cometbft/abci_test.go +++ b/server/v2/cometbft/abci_test.go @@ -686,8 +686,8 @@ func setUpConsensus(t *testing.T, gasLimit uint64, mempool mempool.Mempool[mock. ValidateTxGasLimit: gasLimit, QueryGasLimit: gasLimit, SimulationGasLimit: gasLimit, - InitGenesis: func(ctx context.Context, src io.Reader, txHandler func(json.RawMessage) error) error { - return nil + InitGenesis: func(ctx context.Context, src io.Reader, txHandler func(json.RawMessage) error) (store.WriterMap, error) { + return nil, nil }, } From ea930ac0020410431b3e92f7cd8a7c8f1bfc76f8 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 16 Sep 2024 12:33:21 -0500 Subject: [PATCH 11/13] fix test --- server/v2/cometbft/abci_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/v2/cometbft/abci_test.go b/server/v2/cometbft/abci_test.go index 991611ccfc62..79892729da5e 100644 --- a/server/v2/cometbft/abci_test.go +++ b/server/v2/cometbft/abci_test.go @@ -687,7 +687,9 @@ func setUpConsensus(t *testing.T, gasLimit uint64, mempool mempool.Mempool[mock. QueryGasLimit: gasLimit, SimulationGasLimit: gasLimit, InitGenesis: func(ctx context.Context, src io.Reader, txHandler func(json.RawMessage) error) (store.WriterMap, error) { - return nil, nil + _, st, err := mockStore.StateLatest() + require.NoError(t, err) + return branch.DefaultNewWriterMap(st), nil }, } From 2489e8de9dfabf0064b3aa2740f52ea91fcad379 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Mon, 16 Sep 2024 13:28:45 -0500 Subject: [PATCH 12/13] docs --- runtime/v2/module.go | 8 ++++++++ runtime/v2/services/genesis.go | 27 ++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/runtime/v2/module.go b/runtime/v2/module.go index 9f55024af893..d4a9b4b534d9 100644 --- a/runtime/v2/module.go +++ b/runtime/v2/module.go @@ -236,6 +236,14 @@ func storeKeyOverride(config *runtimev2.Module, moduleName string) *runtimev2.St return nil } +// DefaultServiceBindings provides default services for the following service interfaces: +// - store.KVStoreServiceFactory +// - header.Service +// - comet.Service +// +// They are all required. For most use cases these default services bindings should be sufficient. +// Power users (or tests) may wish to provide their own services bindings, in which case they must +// supply implementations for each of the above interfaces. func DefaultServiceBindings() depinject.Config { var ( kvServiceFactory store.KVStoreServiceFactory = func(actor []byte) store.KVStoreService { diff --git a/runtime/v2/services/genesis.go b/runtime/v2/services/genesis.go index 72db330667c7..79ebd92852f8 100644 --- a/runtime/v2/services/genesis.go +++ b/runtime/v2/services/genesis.go @@ -8,22 +8,31 @@ import ( "cosmossdk.io/core/store" ) -var _ store.KVStoreService = (*GenesisKVStoreService)(nil) +var ( + _ store.KVStoreService = (*GenesisKVStoreService)(nil) + _ header.Service = (*GenesisHeaderService)(nil) +) type genesisContextKeyType struct{} var genesisContextKey = genesisContextKeyType{} +// genesisContext is a context that is used during genesis initialization. +// it backs the store.KVStoreService and header.Service interface implementations +// defined in this file. type genesisContext struct { state store.WriterMap } +// NewGenesisContext creates a new genesis context. func NewGenesisContext(state store.WriterMap) genesisContext { return genesisContext{ state: state, } } +// Run runs the provided function within the genesis context and returns an +// updated store.WriterMap containing the state modifications made during InitGenesis. func (g *genesisContext) Run( ctx context.Context, fn func(ctx context.Context) error, @@ -36,18 +45,23 @@ func (g *genesisContext) Run( return g.state, nil } +// GenesisKVStoreService is a store.KVStoreService implementation that is used during +// genesis initialization. It wraps an inner execution context store.KVStoreService. type GenesisKVStoreService struct { actor []byte executionService store.KVStoreService } +// NewGenesisKVService creates a new GenesisKVStoreService. +// - actor is the module store key. +// - executionService is the store.KVStoreService to use when the genesis context is not active. func NewGenesisKVService( actor []byte, - execution store.KVStoreService, + executionService store.KVStoreService, ) *GenesisKVStoreService { return &GenesisKVStoreService{ actor: actor, - executionService: execution, + executionService: executionService, } } @@ -68,11 +82,14 @@ func (g *GenesisKVStoreService) OpenKVStore(ctx context.Context) store.KVStore { return state } +// GenesisHeaderService is a header.Service implementation that is used during +// genesis initialization. It wraps an inner execution context header.Service. type GenesisHeaderService struct { executionService header.Service } // HeaderInfo implements header.Service. +// During genesis initialization, it returns an empty header.Info. func (g *GenesisHeaderService) HeaderInfo(ctx context.Context) header.Info { v := ctx.Value(genesisContextKey) if v == nil { @@ -81,10 +98,10 @@ func (g *GenesisHeaderService) HeaderInfo(ctx context.Context) header.Info { return header.Info{} } +// NewGenesisHeaderService creates a new GenesisHeaderService. +// - executionService is the header.Service to use when the genesis context is not active. func NewGenesisHeaderService(executionService header.Service) *GenesisHeaderService { return &GenesisHeaderService{ executionService: executionService, } } - -var _ header.Service = (*GenesisHeaderService)(nil) From 284ba5757cbec78325f69e974b723d4e8b21e4ef Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Thu, 19 Sep 2024 16:23:59 -0500 Subject: [PATCH 13/13] go mod tidy all --- runtime/v2/go.sum | 2 -- simapp/v2/go.sum | 2 -- 2 files changed, 4 deletions(-) diff --git a/runtime/v2/go.sum b/runtime/v2/go.sum index e00a3c9f8791..7c0cf21111dc 100644 --- a/runtime/v2/go.sum +++ b/runtime/v2/go.sum @@ -2,8 +2,6 @@ buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.34.2-20240701160653-fed buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.34.2-20240701160653-fedbb9acfd2f.2/go.mod h1:1+3gJj2NvZ1mTLAtHu+lMhOjGgQPiCKCeo+9MBww0Eo= buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88ef6483f90f.2 h1:b7EEYTUHmWSBEyISHlHvXbJPqtKiHRuUignL1tsHnNQ= buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.34.2-20240130113600-88ef6483f90f.2/go.mod h1:HqcXMSa5qnNuakaMUo+hWhF51mKbcrZxGl9Vp5EeJXc= -cosmossdk.io/core v1.0.0-alpha.3 h1:pnxaYAas7llXgVz1lM7X6De74nWrhNKnB3yMKe4OUUA= -cosmossdk.io/core v1.0.0-alpha.3/go.mod h1:3u9cWq1FAVtiiCrDPpo4LhR+9V6k/ycSG4/Y/tREWCY= cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050= cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8= cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 h1:IQNdY2kB+k+1OM2DvqFG1+UgeU1JzZrWtwuWzI3ZfwA= diff --git a/simapp/v2/go.sum b/simapp/v2/go.sum index 65aa48935acf..5afb5cc1d30b 100644 --- a/simapp/v2/go.sum +++ b/simapp/v2/go.sum @@ -192,8 +192,6 @@ cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xX cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cosmossdk.io/core v1.0.0-alpha.3 h1:pnxaYAas7llXgVz1lM7X6De74nWrhNKnB3yMKe4OUUA= -cosmossdk.io/core v1.0.0-alpha.3/go.mod h1:3u9cWq1FAVtiiCrDPpo4LhR+9V6k/ycSG4/Y/tREWCY= cosmossdk.io/depinject v1.0.0 h1:dQaTu6+O6askNXO06+jyeUAnF2/ssKwrrszP9t5q050= cosmossdk.io/depinject v1.0.0/go.mod h1:zxK/h3HgHoA/eJVtiSsoaRaRA2D5U4cJ5thIG4ssbB8= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0=