refactor(stf): remove RunWithCtx (#21739)
This commit is contained in:
+39
-9
@@ -3,6 +3,7 @@ package runtime
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
@@ -12,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"
|
||||
@@ -157,23 +159,51 @@ 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 := 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 {
|
||||
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)
|
||||
_, state, err := a.app.db.StateLatest()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get latest state: %w", err)
|
||||
}
|
||||
genesisCtx := services.NewGenesisContext(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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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=
|
||||
|
||||
+31
-7
@@ -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,8 @@ func ProvideEnvironment[T transaction.Tx](
|
||||
config *runtimev2.Module,
|
||||
key depinject.ModuleKey,
|
||||
appBuilder *AppBuilder[T],
|
||||
kvFactory store.KVStoreServiceFactory,
|
||||
headerService header.Service,
|
||||
) (
|
||||
appmodulev2.Environment,
|
||||
store.KVStoreService,
|
||||
@@ -197,7 +199,7 @@ 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)
|
||||
@@ -209,7 +211,7 @@ func ProvideEnvironment[T transaction.Tx](
|
||||
BranchService: stf.BranchService{},
|
||||
EventService: stf.NewEventService(),
|
||||
GasService: stf.NewGasMeterService(),
|
||||
HeaderService: stf.HeaderService{},
|
||||
HeaderService: headerService,
|
||||
QueryRouterService: stf.NewQueryRouterService(),
|
||||
MsgRouterService: stf.NewMsgRouterService([]byte(key.Name())),
|
||||
TransactionService: services.NewContextAwareTransactionService(),
|
||||
@@ -220,8 +222,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 +236,28 @@ func storeKeyOverride(config *runtimev2.Module, moduleName string) *runtimev2.St
|
||||
return nil
|
||||
}
|
||||
|
||||
func ProvideCometService() comet.Service {
|
||||
return &services.ContextAwareCometInfoService{}
|
||||
// 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 {
|
||||
return services.NewGenesisKVService(
|
||||
actor,
|
||||
stf.NewKVStoreService(actor),
|
||||
)
|
||||
}
|
||||
headerService header.Service = services.NewGenesisHeaderService(stf.HeaderService{})
|
||||
cometService comet.Service = &services.ContextAwareCometInfoService{}
|
||||
)
|
||||
return depinject.Supply(
|
||||
kvServiceFactory,
|
||||
headerService,
|
||||
cometService,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"cosmossdk.io/core/header"
|
||||
"cosmossdk.io/core/store"
|
||||
)
|
||||
|
||||
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,
|
||||
) (store.WriterMap, error) {
|
||||
ctx = context.WithValue(ctx, genesisContextKey, g)
|
||||
err := fn(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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,
|
||||
executionService store.KVStoreService,
|
||||
) *GenesisKVStoreService {
|
||||
return &GenesisKVStoreService{
|
||||
actor: actor,
|
||||
executionService: executionService,
|
||||
}
|
||||
}
|
||||
|
||||
// OpenKVStore implements store.KVStoreService.
|
||||
func (g *GenesisKVStoreService) OpenKVStore(ctx context.Context) store.KVStore {
|
||||
v := ctx.Value(genesisContextKey)
|
||||
if v == nil {
|
||||
return g.executionService.OpenKVStore(ctx)
|
||||
}
|
||||
genCtx, ok := v.(*genesisContext)
|
||||
if !ok {
|
||||
panic(fmt.Errorf("unexpected genesis context type: %T", v))
|
||||
}
|
||||
state, err := genCtx.state.GetWriter(g.actor)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
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 {
|
||||
return g.executionService.HeaderInfo(ctx)
|
||||
}
|
||||
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,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user