refactor(server/v2): extend the use of generic transaction type all the way up (#20789)

This commit is contained in:
archbear 2024-06-27 06:18:25 -04:00 committed by GitHub
parent fe9157b1a3
commit 9e89aace91
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 230 additions and 181 deletions

View File

@ -19,7 +19,7 @@ import (
"cosmossdk.io/server/v2/stf"
)
var _ AppI[transaction.Tx] = (*App)(nil)
var _ AppI[transaction.Tx] = (*App[transaction.Tx])(nil)
// AppI is an interface that defines the methods required by the App.
type AppI[T transaction.Tx] interface {
@ -33,7 +33,7 @@ type AppI[T transaction.Tx] interface {
QueryWithState(ctx context.Context, state store.ReaderMap, request transaction.Msg) (transaction.Msg, error)
Logger() log.Logger
ModuleManager() *MM
ModuleManager() *MM[T]
Close() error
}
@ -46,11 +46,11 @@ type AppI[T transaction.Tx] interface {
// App can be used to create a hybrid app.go setup where some configuration is
// 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 struct {
*appmanager.AppManager[transaction.Tx]
type App[T transaction.Tx] struct {
*appmanager.AppManager[T]
// app manager dependencies
stf *stf.STF[transaction.Tx]
stf *stf.STF[T]
msgRouterBuilder *stf.MsgRouterBuilder
queryRouterBuilder *stf.MsgRouterBuilder
db Store
@ -64,47 +64,47 @@ type App struct {
storeKeys []string
interfaceRegistrar registry.InterfaceRegistrar
amino legacy.Amino
moduleManager *MM
moduleManager *MM[T]
}
// Logger returns the app logger.
func (a *App) Logger() log.Logger {
func (a *App[T]) Logger() log.Logger {
return a.logger
}
// ModuleManager returns the module manager.
func (a *App) ModuleManager() *MM {
func (a *App[T]) ModuleManager() *MM[T] {
return a.moduleManager
}
// DefaultGenesis returns a default genesis from the registered modules.
func (a *App) DefaultGenesis() map[string]json.RawMessage {
func (a *App[T]) DefaultGenesis() map[string]json.RawMessage {
return a.moduleManager.DefaultGenesis()
}
// LoadLatest loads the latest version.
func (a *App) LoadLatest() error {
func (a *App[T]) LoadLatest() error {
return a.db.LoadLatestVersion()
}
// LoadHeight loads a particular height
func (a *App) LoadHeight(height uint64) error {
func (a *App[T]) LoadHeight(height uint64) error {
return a.db.LoadVersion(height)
}
// Close is called in start cmd to gracefully cleanup resources.
func (a *App) Close() error {
func (a *App[T]) Close() error {
return nil
}
// GetStoreKeys returns all the app store keys.
func (a *App) GetStoreKeys() []string {
func (a *App[T]) GetStoreKeys() []string {
return a.storeKeys
}
// UnsafeFindStoreKey fetches a registered StoreKey from the App in linear time.
// NOTE: This should only be used in testing.
func (a *App) UnsafeFindStoreKey(storeKey string) (string, error) {
func (a *App[T]) UnsafeFindStoreKey(storeKey string) (string, error) {
i := slices.IndexFunc(a.storeKeys, func(s string) bool { return s == storeKey })
if i == -1 {
return "", errors.New("store key not found")
@ -114,19 +114,19 @@ func (a *App) UnsafeFindStoreKey(storeKey string) (string, error) {
}
// GetStore returns the app store.
func (a *App) GetStore() Store {
func (a *App[T]) GetStore() Store {
return a.db
}
// GetLogger returns the app logger.
func (a *App) GetLogger() log.Logger {
func (a *App[T]) GetLogger() log.Logger {
return a.logger
}
func (a *App) ExecuteGenesisTx(_ []byte) error {
func (a *App[T]) ExecuteGenesisTx(_ []byte) error {
panic("App.ExecuteGenesisTx not supported in runtime/v2")
}
func (a *App) GetAppManager() *appmanager.AppManager[transaction.Tx] {
func (a *App[T]) GetAppManager() *appmanager.AppManager[T] {
return a.AppManager
}

View File

@ -19,24 +19,24 @@ import (
// AppBuilder is a type that is injected into a container by the runtime/v2 module
// (as *AppBuilder) which can be used to create an app which is compatible with
// the existing app.go initialization conventions.
type AppBuilder struct {
app *App
type AppBuilder[T transaction.Tx] struct {
app *App[T]
storeOptions *rootstore.FactoryOptions
// the following fields are used to overwrite the default
branch func(state store.ReaderMap) store.WriterMap
txValidator func(ctx context.Context, tx transaction.Tx) error
postTxExec func(ctx context.Context, tx transaction.Tx, success bool) error
txValidator func(ctx context.Context, tx T) error
postTxExec func(ctx context.Context, tx T, success bool) error
}
// DefaultGenesis returns a default genesis from the registered AppModule's.
func (a *AppBuilder) DefaultGenesis() map[string]json.RawMessage {
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) RegisterModules(modules ...appmodulev2.AppModule) error {
func (a *AppBuilder[T]) RegisterModules(modules ...appmodulev2.AppModule) error {
for _, appModule := range modules {
if mod, ok := appModule.(appmodule.HasName); ok {
name := mod.Name()
@ -62,7 +62,7 @@ func (a *AppBuilder) RegisterModules(modules ...appmodulev2.AppModule) error {
// This method should only be used for registering extra stores
// wiich is necessary for modules that not registered using the app config.
// To be used in combination of RegisterModules.
func (a *AppBuilder) RegisterStores(keys ...string) {
func (a *AppBuilder[T]) RegisterStores(keys ...string) {
a.app.storeKeys = append(a.app.storeKeys, keys...)
if a.storeOptions != nil {
a.storeOptions.StoreKeys = append(a.storeOptions.StoreKeys, keys...)
@ -70,7 +70,7 @@ func (a *AppBuilder) RegisterStores(keys ...string) {
}
// Build builds an *App instance.
func (a *AppBuilder) Build(opts ...AppBuilderOption) (*App, error) {
func (a *AppBuilder[T]) Build(opts ...AppBuilderOption[T]) (*App[T], error) {
for _, opt := range opts {
opt(a)
}
@ -87,7 +87,7 @@ func (a *AppBuilder) Build(opts ...AppBuilderOption) (*App, error) {
// default post tx exec
if a.postTxExec == nil {
a.postTxExec = func(ctx context.Context, tx transaction.Tx, success bool) error {
a.postTxExec = func(ctx context.Context, tx T, success bool) error {
return nil
}
}
@ -98,7 +98,7 @@ func (a *AppBuilder) Build(opts ...AppBuilderOption) (*App, error) {
endBlocker, valUpdate := a.app.moduleManager.EndBlock()
stf, err := stf.NewSTF[transaction.Tx](
stf, err := stf.NewSTF[T](
a.app.logger.With("module", "stf"),
a.app.msgRouterBuilder,
a.app.queryRouterBuilder,
@ -122,7 +122,7 @@ func (a *AppBuilder) Build(opts ...AppBuilderOption) (*App, error) {
}
a.app.db = rs
appManagerBuilder := appmanager.Builder[transaction.Tx]{
appManagerBuilder := appmanager.Builder[T]{
STF: a.app.stf,
DB: a.app.db,
ValidateTxGasLimit: a.app.config.GasConfig.ValidateTxGasLimit,
@ -155,33 +155,33 @@ func (a *AppBuilder) Build(opts ...AppBuilderOption) (*App, error) {
}
// AppBuilderOption is a function that can be passed to AppBuilder.Build to customize the resulting app.
type AppBuilderOption func(*AppBuilder)
type AppBuilderOption[T transaction.Tx] func(*AppBuilder[T])
// AppBuilderWithBranch sets a custom branch implementation for the app.
func AppBuilderWithBranch(branch func(state store.ReaderMap) store.WriterMap) AppBuilderOption {
return func(a *AppBuilder) {
func AppBuilderWithBranch[T transaction.Tx](branch func(state store.ReaderMap) store.WriterMap) AppBuilderOption[T] {
return func(a *AppBuilder[T]) {
a.branch = branch
}
}
// AppBuilderWithTxValidator sets the tx validator for the app.
// It overrides all default tx validators defined by modules.
func AppBuilderWithTxValidator(txValidators func(ctx context.Context, tx transaction.Tx) error) AppBuilderOption {
return func(a *AppBuilder) {
func AppBuilderWithTxValidator[T transaction.Tx](txValidators func(ctx context.Context, tx T) error) AppBuilderOption[T] {
return func(a *AppBuilder[T]) {
a.txValidator = txValidators
}
}
// AppBuilderWithPostTxExec sets logic that will be executed after each transaction.
// When not provided, a no-op function will be used.
func AppBuilderWithPostTxExec(
func AppBuilderWithPostTxExec[T transaction.Tx](
postTxExec func(
ctx context.Context,
tx transaction.Tx,
tx T,
success bool,
) error,
) AppBuilderOption {
return func(a *AppBuilder) {
) AppBuilderOption[T] {
return func(a *AppBuilder[T]) {
a.postTxExec = postTxExec
}
}

View File

@ -25,7 +25,7 @@ import (
"cosmossdk.io/server/v2/stf"
)
type MM struct {
type MM[T transaction.Tx] struct {
logger log.Logger
config *runtimev2.Module
modules map[string]appmodulev2.AppModule
@ -34,11 +34,11 @@ type MM struct {
// NewModuleManager is the constructor for the module manager
// It handles all the interactions between the modules and the application
func NewModuleManager(
func NewModuleManager[T transaction.Tx](
logger log.Logger,
config *runtimev2.Module,
modules map[string]appmodulev2.AppModule,
) *MM {
) *MM[T] {
// good defaults for the module manager order
modulesName := maps.Keys(modules)
if len(config.PreBlockers) == 0 {
@ -63,7 +63,7 @@ func NewModuleManager(
config.OrderMigrations = defaultMigrationsOrder(modulesName)
}
mm := &MM{
mm := &MM[T]{
logger: logger,
config: config,
modules: modules,
@ -78,12 +78,12 @@ func NewModuleManager(
}
// Modules returns the modules registered in the module manager
func (m *MM) Modules() map[string]appmodulev2.AppModule {
func (m *MM[T]) Modules() map[string]appmodulev2.AppModule {
return m.modules
}
// RegisterLegacyAminoCodec registers all module codecs
func (m *MM) RegisterLegacyAminoCodec(cdc legacy.Amino) {
func (m *MM[T]) RegisterLegacyAminoCodec(cdc legacy.Amino) {
for _, b := range m.modules {
if mod, ok := b.(appmodule.HasAminoCodec); ok {
mod.RegisterLegacyAminoCodec(cdc)
@ -92,7 +92,7 @@ func (m *MM) RegisterLegacyAminoCodec(cdc legacy.Amino) {
}
// RegisterInterfaces registers all module interface types
func (m *MM) RegisterInterfaces(registry registry.InterfaceRegistrar) {
func (m *MM[T]) RegisterInterfaces(registry registry.InterfaceRegistrar) {
for _, b := range m.modules {
if mod, ok := b.(appmodulev2.HasRegisterInterfaces); ok {
mod.RegisterInterfaces(registry)
@ -101,7 +101,7 @@ func (m *MM) RegisterInterfaces(registry registry.InterfaceRegistrar) {
}
// DefaultGenesis provides default genesis information for all modules
func (m *MM) DefaultGenesis() map[string]json.RawMessage {
func (m *MM[T]) DefaultGenesis() map[string]json.RawMessage {
genesisData := make(map[string]json.RawMessage)
for name, b := range m.modules {
if mod, ok := b.(appmodule.HasGenesisBasics); ok {
@ -117,7 +117,7 @@ func (m *MM) DefaultGenesis() map[string]json.RawMessage {
}
// ValidateGenesis performs genesis state validation for all modules
func (m *MM) ValidateGenesis(genesisData map[string]json.RawMessage) error {
func (m *MM[T]) ValidateGenesis(genesisData map[string]json.RawMessage) error {
for name, b := range m.modules {
if mod, ok := b.(appmodule.HasGenesisBasics); ok {
if err := mod.ValidateGenesis(genesisData[mod.Name()]); err != nil {
@ -134,7 +134,7 @@ func (m *MM) ValidateGenesis(genesisData map[string]json.RawMessage) error {
}
// InitGenesisJSON performs init genesis functionality for modules from genesis data in JSON format
func (m *MM) InitGenesisJSON(
func (m *MM[T]) InitGenesisJSON(
ctx context.Context,
genesisData map[string]json.RawMessage,
txHandler func(json.RawMessage) error,
@ -190,7 +190,7 @@ func (m *MM) InitGenesisJSON(
}
// ExportGenesisForModules performs export genesis functionality for modules
func (m *MM) ExportGenesisForModules(
func (m *MM[T]) ExportGenesisForModules(
ctx context.Context,
modulesToExport ...string,
) (map[string]json.RawMessage, error) {
@ -247,7 +247,7 @@ func (m *MM) ExportGenesisForModules(
}
// checkModulesExists verifies that all modules in the list exist in the app
func (m *MM) checkModulesExists(moduleName []string) error {
func (m *MM[T]) checkModulesExists(moduleName []string) error {
for _, name := range moduleName {
if _, ok := m.modules[name]; !ok {
return fmt.Errorf("module %s does not exist", name)
@ -258,7 +258,7 @@ func (m *MM) checkModulesExists(moduleName []string) error {
}
// BeginBlock runs the begin-block logic of all modules
func (m *MM) BeginBlock() func(ctx context.Context) error {
func (m *MM[T]) BeginBlock() func(ctx context.Context) error {
return func(ctx context.Context) error {
for _, moduleName := range m.config.BeginBlockers {
if module, ok := m.modules[moduleName].(appmodulev2.HasBeginBlocker); ok {
@ -278,7 +278,7 @@ type hasABCIEndBlock interface {
}
// EndBlock runs the end-block logic of all modules and tx validator updates
func (m *MM) EndBlock() (
func (m *MM[T]) EndBlock() (
endBlockFunc func(ctx context.Context) error,
valUpdateFunc func(ctx context.Context) ([]appmodulev2.ValidatorUpdate, error),
) {
@ -336,8 +336,8 @@ func (m *MM) EndBlock() (
}
// PreBlocker runs the pre-block logic of all modules
func (m *MM) PreBlocker() func(ctx context.Context, txs []transaction.Tx) error {
return func(ctx context.Context, txs []transaction.Tx) error {
func (m *MM[T]) PreBlocker() func(ctx context.Context, txs []T) error {
return func(ctx context.Context, txs []T) error {
for _, moduleName := range m.config.PreBlockers {
if module, ok := m.modules[moduleName].(appmodulev2.HasPreBlocker); ok {
if err := module.PreBlock(ctx); err != nil {
@ -351,10 +351,10 @@ func (m *MM) PreBlocker() func(ctx context.Context, txs []transaction.Tx) error
}
// TxValidators validates incoming transactions
func (m *MM) TxValidators() func(ctx context.Context, tx transaction.Tx) error {
return func(ctx context.Context, tx transaction.Tx) error {
func (m *MM[T]) TxValidators() func(ctx context.Context, tx T) error {
return func(ctx context.Context, tx T) error {
for _, moduleName := range m.config.TxValidators {
if module, ok := m.modules[moduleName].(appmodulev2.HasTxValidator[transaction.Tx]); ok {
if module, ok := m.modules[moduleName].(appmodulev2.HasTxValidator[T]); ok {
if err := module.TxValidator(ctx, tx); err != nil {
return fmt.Errorf("failed to run tx validator for %s: %w", moduleName, err)
}
@ -367,7 +367,7 @@ func (m *MM) TxValidators() func(ctx context.Context, tx transaction.Tx) error {
// TODO write as descriptive godoc as module manager v1.
// TODO include feedback from https://github.com/cosmos/cosmos-sdk/issues/15120
func (m *MM) RunMigrations(ctx context.Context, fromVM appmodulev2.VersionMap) (appmodulev2.VersionMap, error) {
func (m *MM[T]) RunMigrations(ctx context.Context, fromVM appmodulev2.VersionMap) (appmodulev2.VersionMap, error) {
updatedVM := appmodulev2.VersionMap{}
for _, moduleName := range m.config.OrderMigrations {
module := m.modules[moduleName]
@ -417,7 +417,7 @@ func (m *MM) RunMigrations(ctx context.Context, fromVM appmodulev2.VersionMap) (
}
// RegisterServices registers all module services.
func (m *MM) RegisterServices(app *App) error {
func (m *MM[T]) RegisterServices(app *App[T]) error {
for _, module := range m.modules {
// register msg + query
if services, ok := module.(appmodule.HasServices); ok {
@ -441,7 +441,7 @@ func (m *MM) RegisterServices(app *App) error {
// validateConfig validates the module manager configuration
// it asserts that all modules are defined in the configuration and that no modules are forgotten
func (m *MM) validateConfig() error {
func (m *MM[T]) validateConfig() error {
if err := m.assertNoForgottenModules("PreBlockers", m.config.PreBlockers, func(moduleName string) bool {
module := m.modules[moduleName]
_, hasBlock := module.(appmodulev2.HasPreBlocker)
@ -472,7 +472,7 @@ func (m *MM) validateConfig() error {
if err := m.assertNoForgottenModules("TxValidators", m.config.TxValidators, func(moduleName string) bool {
module := m.modules[moduleName]
_, hasTxValidator := module.(appmodulev2.HasTxValidator[transaction.Tx])
_, hasTxValidator := module.(appmodulev2.HasTxValidator[T])
return !hasTxValidator
}); err != nil {
return err
@ -520,7 +520,7 @@ func (m *MM) validateConfig() error {
// assertNoForgottenModules checks that we didn't forget any modules in the *runtimev2.Module config.
// `pass` is a closure which allows one to omit modules from `moduleNames`.
// If you provide non-nil `pass` and it returns true, the module would not be subject of the assertion.
func (m *MM) assertNoForgottenModules(
func (m *MM[T]) assertNoForgottenModules(
setOrderFnName string,
moduleNames []string,
pass func(moduleName string) bool,
@ -549,7 +549,7 @@ func (m *MM) assertNoForgottenModules(
return nil
}
func registerServices(s appmodule.HasServices, app *App, registry *protoregistry.Files) error {
func registerServices[T transaction.Tx](s appmodule.HasServices, app *App[T], registry *protoregistry.Files) error {
c := &configurator{
stfQueryRouter: app.queryRouterBuilder,
stfMsgRouter: app.msgRouterBuilder,

View File

@ -23,6 +23,7 @@ import (
"cosmossdk.io/core/log"
"cosmossdk.io/core/registry"
"cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
"cosmossdk.io/depinject"
"cosmossdk.io/depinject/appconfig"
"cosmossdk.io/runtime/v2/services"
@ -31,18 +32,18 @@ import (
)
var (
_ appmodulev2.AppModule = appModule{}
_ appmodule.HasServices = appModule{}
_ appmodulev2.AppModule = appModule[transaction.Tx]{}
_ appmodule.HasServices = appModule[transaction.Tx]{}
)
type appModule struct {
app *App
type appModule[T transaction.Tx] struct {
app *App[T]
}
func (m appModule) IsOnePerModuleType() {}
func (m appModule) IsAppModule() {}
func (m appModule[T]) IsOnePerModuleType() {}
func (m appModule[T]) IsAppModule() {}
func (m appModule) RegisterServices(registar grpc.ServiceRegistrar) error {
func (m appModule[T]) RegisterServices(registar grpc.ServiceRegistrar) error {
autoCliQueryService, err := services.NewAutoCLIQueryService(m.app.moduleManager.modules)
if err != nil {
return err
@ -59,7 +60,7 @@ func (m appModule) RegisterServices(registar grpc.ServiceRegistrar) error {
return nil
}
func (m appModule) AutoCLIOptions() *autocliv1.ModuleOptions {
func (m appModule[T]) AutoCLIOptions() *autocliv1.ModuleOptions {
return &autocliv1.ModuleOptions{
Query: &autocliv1.ServiceCommandDescriptor{
Service: appv1alpha1.Query_ServiceDesc.ServiceName,
@ -96,22 +97,22 @@ func (m appModule) AutoCLIOptions() *autocliv1.ModuleOptions {
func init() {
appconfig.Register(&runtimev2.Module{},
appconfig.Provide(
ProvideAppBuilder,
ProvideEnvironment,
ProvideModuleManager,
ProvideGenesisTxHandler,
ProvideAppBuilder[transaction.Tx],
ProvideEnvironment[transaction.Tx],
ProvideModuleManager[transaction.Tx],
ProvideGenesisTxHandler[transaction.Tx],
ProvideCometService,
ProvideAppVersionModifier,
ProvideAppVersionModifier[transaction.Tx],
),
appconfig.Invoke(SetupAppBuilder),
)
}
func ProvideAppBuilder(
func ProvideAppBuilder[T transaction.Tx](
interfaceRegistrar registry.InterfaceRegistrar,
amino legacy.Amino,
) (
*AppBuilder,
*AppBuilder[T],
*stf.MsgRouterBuilder,
appmodulev2.AppModule,
protodesc.Resolver,
@ -128,16 +129,16 @@ func ProvideAppBuilder(
}
msgRouterBuilder := stf.NewMsgRouterBuilder()
app := &App{
app := &App[T]{
storeKeys: nil,
interfaceRegistrar: interfaceRegistrar,
amino: amino,
msgRouterBuilder: msgRouterBuilder,
queryRouterBuilder: stf.NewMsgRouterBuilder(), // TODO dedicated query router
}
appBuilder := &AppBuilder{app: app}
appBuilder := &AppBuilder[T]{app: app}
return appBuilder, msgRouterBuilder, appModule{app}, protoFiles, protoTypes
return appBuilder, msgRouterBuilder, appModule[T]{app}, protoFiles, protoTypes
}
type AppInputs struct {
@ -145,8 +146,8 @@ type AppInputs struct {
AppConfig *appv1alpha1.Config
Config *runtimev2.Module
AppBuilder *AppBuilder
ModuleManager *MM
AppBuilder *AppBuilder[transaction.Tx]
ModuleManager *MM[transaction.Tx]
InterfaceRegistrar registry.InterfaceRegistrar
LegacyAmino legacy.Amino
Logger log.Logger
@ -169,16 +170,16 @@ func SetupAppBuilder(inputs AppInputs) {
}
}
func ProvideModuleManager(
func ProvideModuleManager[T transaction.Tx](
logger log.Logger,
config *runtimev2.Module,
modules map[string]appmodulev2.AppModule,
) *MM {
return NewModuleManager(logger, config, modules)
) *MM[T] {
return NewModuleManager[T](logger, config, modules)
}
// ProvideEnvironment provides the environment for keeper modules, while maintaining backward compatibility and provide services directly as well.
func ProvideEnvironment(logger log.Logger, config *runtimev2.Module, key depinject.ModuleKey, appBuilder *AppBuilder) (
func ProvideEnvironment[T transaction.Tx](logger log.Logger, config *runtimev2.Module, key depinject.ModuleKey, appBuilder *AppBuilder[T]) (
appmodulev2.Environment,
store.KVStoreService,
store.MemoryStoreService,
@ -222,7 +223,7 @@ func ProvideEnvironment(logger log.Logger, config *runtimev2.Module, key depinje
return env, kvService, memKvService
}
func registerStoreKey(wrapper *AppBuilder, key string) {
func registerStoreKey[T transaction.Tx](wrapper *AppBuilder[T], key string) {
wrapper.app.storeKeys = append(wrapper.app.storeKeys, key)
}
@ -236,7 +237,7 @@ func storeKeyOverride(config *runtimev2.Module, moduleName string) *runtimev2.St
return nil
}
func ProvideGenesisTxHandler(appBuilder *AppBuilder) genesis.TxHandler {
func ProvideGenesisTxHandler[T transaction.Tx](appBuilder *AppBuilder[T]) genesis.TxHandler {
return appBuilder.app
}
@ -246,6 +247,6 @@ func ProvideCometService() comet.Service {
// ProvideAppVersionModifier returns nil, `app.VersionModifier` is a feature of BaseApp and neither used nor required for runtim/v2.
// nil is acceptable, see: https://github.com/cosmos/cosmos-sdk/blob/0a6ee406a02477ae8ccbfcbe1b51fc3930087f4c/x/upgrade/keeper/keeper.go#L438
func ProvideAppVersionModifier(app *AppBuilder) app.VersionModifier {
func ProvideAppVersionModifier[T transaction.Tx](app *AppBuilder[T]) app.VersionModifier {
return nil
}

View File

@ -23,7 +23,7 @@ import (
const serverName = "grpc-server"
type GRPCServer struct {
type GRPCServer[AppT serverv2.AppI[T], T transaction.Tx] struct {
logger log.Logger
config *Config
@ -35,13 +35,13 @@ type GRPCService interface {
RegisterGRPCServer(gogogrpc.Server)
}
func New() *GRPCServer {
return &GRPCServer{}
func New[AppT serverv2.AppI[T], T transaction.Tx]() *GRPCServer[AppT, T] {
return &GRPCServer[AppT, T]{}
}
// Init returns a correctly configured and initialized gRPC server.
// Note, the caller is responsible for starting the server.
func (g *GRPCServer) Init(appI serverv2.AppI[transaction.Tx], v *viper.Viper, logger log.Logger) error {
func (g *GRPCServer[AppT, T]) Init(appI AppT, v *viper.Viper, logger log.Logger) error {
cfg := DefaultConfig()
if v != nil {
if err := v.Sub(serverName).Unmarshal(&cfg); err != nil {
@ -68,11 +68,11 @@ func (g *GRPCServer) Init(appI serverv2.AppI[transaction.Tx], v *viper.Viper, lo
return nil
}
func (g *GRPCServer) Name() string {
func (g *GRPCServer[AppT, T]) Name() string {
return serverName
}
func (g *GRPCServer) Start(ctx context.Context) error {
func (g *GRPCServer[AppT, T]) Start(ctx context.Context) error {
listener, err := net.Listen("tcp", g.config.Address)
if err != nil {
return fmt.Errorf("failed to listen on address %s: %w", g.config.Address, err)
@ -95,14 +95,14 @@ func (g *GRPCServer) Start(ctx context.Context) error {
return err
}
func (g *GRPCServer) Stop(ctx context.Context) error {
func (g *GRPCServer[AppT, T]) Stop(ctx context.Context) error {
g.logger.Info("stopping gRPC server...", "address", g.config.Address)
g.grpcSrv.GracefulStop()
return nil
}
func (g *GRPCServer) Config() any {
func (g *GRPCServer[AppT, T]) Config() any {
if g.config == nil || g.config == (&Config{}) {
return DefaultConfig()
}

View File

@ -29,7 +29,7 @@ import (
"github.com/cosmos/cosmos-sdk/version"
)
func (s *CometBFTServer[T]) rpcClient(cmd *cobra.Command) (rpc.CometRPC, error) {
func (s *CometBFTServer[AppT, T]) rpcClient(cmd *cobra.Command) (rpc.CometRPC, error) {
if s.config.Standalone {
client, err := rpchttp.New(client.GetConfigFromCmd(cmd).RPC.ListenAddress)
if err != nil {
@ -52,7 +52,7 @@ func (s *CometBFTServer[T]) rpcClient(cmd *cobra.Command) (rpc.CometRPC, error)
}
// StatusCommand returns the command to return the status of the network.
func (s *CometBFTServer[T]) StatusCommand() *cobra.Command {
func (s *CometBFTServer[AppT, T]) StatusCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "status",
Short: "Query remote node for status",
@ -83,7 +83,7 @@ func (s *CometBFTServer[T]) StatusCommand() *cobra.Command {
}
// ShowNodeIDCmd - ported from CometBFT, dump node ID to stdout
func (s *CometBFTServer[T]) ShowNodeIDCmd() *cobra.Command {
func (s *CometBFTServer[AppT, T]) ShowNodeIDCmd() *cobra.Command {
return &cobra.Command{
Use: "show-node-id",
Short: "Show this node's ID",
@ -101,7 +101,7 @@ func (s *CometBFTServer[T]) ShowNodeIDCmd() *cobra.Command {
}
// ShowValidatorCmd - ported from CometBFT, show this node's validator info
func (s *CometBFTServer[T]) ShowValidatorCmd() *cobra.Command {
func (s *CometBFTServer[AppT, T]) ShowValidatorCmd() *cobra.Command {
cmd := cobra.Command{
Use: "show-validator",
Short: "Show this node's CometBFT validator info",
@ -135,7 +135,7 @@ func (s *CometBFTServer[T]) ShowValidatorCmd() *cobra.Command {
}
// ShowAddressCmd - show this node's validator address
func (s *CometBFTServer[T]) ShowAddressCmd() *cobra.Command {
func (s *CometBFTServer[AppT, T]) ShowAddressCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "show-address",
Short: "Shows this node's CometBFT validator consensus address",
@ -154,7 +154,7 @@ func (s *CometBFTServer[T]) ShowAddressCmd() *cobra.Command {
}
// VersionCmd prints CometBFT and ABCI version numbers.
func (s *CometBFTServer[T]) VersionCmd() *cobra.Command {
func (s *CometBFTServer[AppT, T]) VersionCmd() *cobra.Command {
return &cobra.Command{
Use: "version",
Short: "Print CometBFT libraries' version",
@ -182,7 +182,7 @@ func (s *CometBFTServer[T]) VersionCmd() *cobra.Command {
}
// QueryBlocksCmd returns a command to search through blocks by events.
func (s *CometBFTServer[T]) QueryBlocksCmd() *cobra.Command {
func (s *CometBFTServer[AppT, T]) QueryBlocksCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "blocks",
Short: "Query for paginated blocks that match a set of events",
@ -232,7 +232,7 @@ for. Each module documents its respective events under 'xx_events.md'.
}
// QueryBlockCmd implements the default command for a Block query.
func (s *CometBFTServer[T]) QueryBlockCmd() *cobra.Command {
func (s *CometBFTServer[AppT, T]) QueryBlockCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "block --type=[height|hash] [height|hash]",
Short: "Query for a committed block by height, hash, or event(s)",
@ -319,7 +319,7 @@ $ %s query block --%s=%s <hash>
}
// QueryBlockResultsCmd implements the default command for a BlockResults query.
func (s *CometBFTServer[T]) QueryBlockResultsCmd() *cobra.Command {
func (s *CometBFTServer[AppT, T]) QueryBlockResultsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "block-results [height]",
Short: "Query for a committed block's results by height",
@ -384,7 +384,7 @@ func parseOptionalHeight(heightStr string) (*int64, error) {
return &tmp, nil
}
func (s *CometBFTServer[T]) BootstrapStateCmd() *cobra.Command {
func (s *CometBFTServer[AppT, T]) BootstrapStateCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "bootstrap-state",
Short: "Bootstrap CometBFT state at an arbitrary block height using a light client",
@ -414,7 +414,7 @@ func (s *CometBFTServer[T]) BootstrapStateCmd() *cobra.Command {
func printOutput(cmd *cobra.Command, out []byte) error {
// Get flags output
outFlag, err := cmd.Flags().GetString(flags.FlagOutput)
outFlag, err := cmd.Flags().GetString(flags.FlagOutput)
if err != nil {
return err
}

View File

@ -45,11 +45,15 @@ const (
FlagTrace = "trace"
)
var _ serverv2.ServerComponent[transaction.Tx] = (*CometBFTServer[transaction.Tx])(nil)
var _ serverv2.HasCLICommands = (*CometBFTServer[transaction.Tx])(nil)
var _ serverv2.HasStartFlags = (*CometBFTServer[transaction.Tx])(nil)
var (
_ serverv2.ServerComponent[
serverv2.AppI[transaction.Tx], transaction.Tx,
] = (*CometBFTServer[serverv2.AppI[transaction.Tx], transaction.Tx])(nil)
_ serverv2.HasCLICommands = (*CometBFTServer[serverv2.AppI[transaction.Tx], transaction.Tx])(nil)
_ serverv2.HasStartFlags = (*CometBFTServer[serverv2.AppI[transaction.Tx], transaction.Tx])(nil)
)
type CometBFTServer[T transaction.Tx] struct {
type CometBFTServer[AppT serverv2.AppI[T], T transaction.Tx] struct {
Node *node.Node
App *Consensus[T]
logger log.Logger
@ -65,14 +69,14 @@ type App[T transaction.Tx] interface {
GetStore() types.Store
}
func New[T transaction.Tx](txCodec transaction.Codec[T]) *CometBFTServer[T] {
func New[AppT serverv2.AppI[T], T transaction.Tx](txCodec transaction.Codec[T]) *CometBFTServer[AppT, T] {
consensus := &Consensus[T]{txCodec: txCodec}
return &CometBFTServer[T]{
return &CometBFTServer[AppT, T]{
App: consensus,
}
}
func (s *CometBFTServer[T]) Init(appI serverv2.AppI[T], v *viper.Viper, logger log.Logger) error {
func (s *CometBFTServer[AppT, T]) Init(appI AppT, v *viper.Viper, logger log.Logger) error {
store := appI.GetStore().(types.Store)
cfg := Config{CmtConfig: GetConfigFromViper(v), ConsensusAuthority: appI.GetConsensusAuthority()}
@ -109,11 +113,11 @@ func (s *CometBFTServer[T]) Init(appI serverv2.AppI[T], v *viper.Viper, logger l
return nil
}
func (s *CometBFTServer[T]) Name() string {
func (s *CometBFTServer[AppT, T]) Name() string {
return "cometbft"
}
func (s *CometBFTServer[T]) Start(ctx context.Context) error {
func (s *CometBFTServer[AppT, T]) Start(ctx context.Context) error {
viper := ctx.Value(corectx.ViperContextKey{}).(*viper.Viper)
cometConfig := GetConfigFromViper(viper)
@ -152,7 +156,7 @@ func (s *CometBFTServer[T]) Start(ctx context.Context) error {
return s.Node.Start()
}
func (s *CometBFTServer[T]) Stop(context.Context) error {
func (s *CometBFTServer[AppT, T]) Stop(context.Context) error {
if s.Node != nil && s.Node.IsRunning() {
return s.Node.Stop()
}
@ -198,7 +202,7 @@ func getGenDocProvider(cfg *cmtcfg.Config) func() (node.ChecksummedGenesisDoc, e
}
}
func (s *CometBFTServer[T]) StartCmdFlags() *pflag.FlagSet {
func (s *CometBFTServer[AppT, T]) StartCmdFlags() *pflag.FlagSet {
flags := pflag.NewFlagSet("cometbft", pflag.ExitOnError)
flags.Bool(flagWithComet, true, "Run abci app embedded in-process with CometBFT")
flags.String(flagAddress, "tcp://127.0.0.1:26658", "Listen address")
@ -213,7 +217,7 @@ func (s *CometBFTServer[T]) StartCmdFlags() *pflag.FlagSet {
return flags
}
func (s *CometBFTServer[T]) CLICommands() serverv2.CLIConfig {
func (s *CometBFTServer[AppT, T]) CLICommands() serverv2.CLIConfig {
return serverv2.CLIConfig{
Commands: []*cobra.Command{
s.StatusCommand(),
@ -230,7 +234,7 @@ func (s *CometBFTServer[T]) CLICommands() serverv2.CLIConfig {
}
}
func (s *CometBFTServer[T]) WriteDefaultConfigAt(configPath string) error {
func (s *CometBFTServer[AppT, T]) WriteDefaultConfigAt(configPath string) error {
cometConfig := cmtcfg.DefaultConfig()
cmtcfg.WriteConfigFile(filepath.Join(configPath, "config.toml"), cometConfig)
return nil

View File

@ -33,7 +33,12 @@ func Execute(rootCmd *cobra.Command, envPrefix, defaultHome string) error {
return rootCmd.Execute()
}
func Commands(rootCmd *cobra.Command, newApp AppCreator[transaction.Tx], logger log.Logger, components ...ServerComponent[transaction.Tx]) (CLIConfig, error) {
func Commands[AppT AppI[T], T transaction.Tx](
rootCmd *cobra.Command,
newApp AppCreator[AppT, T],
logger log.Logger,
components ...ServerComponent[AppT, T],
) (CLIConfig, error) {
if len(components) == 0 {
return CLIConfig{}, errors.New("no components provided")
}
@ -94,7 +99,12 @@ func Commands(rootCmd *cobra.Command, newApp AppCreator[transaction.Tx], logger
return cmds, nil
}
func AddCommands(rootCmd *cobra.Command, newApp AppCreator[transaction.Tx], logger log.Logger, components ...ServerComponent[transaction.Tx]) error {
func AddCommands[AppT AppI[T], T transaction.Tx](
rootCmd *cobra.Command,
newApp AppCreator[AppT, T],
logger log.Logger,
components ...ServerComponent[AppT, T],
) error {
cmds, err := Commands(rootCmd, newApp, logger, components...)
if err != nil {
return err
@ -125,7 +135,7 @@ func AddCommands(rootCmd *cobra.Command, newApp AppCreator[transaction.Tx], logg
}
// configHandle writes the default config to the home directory if it does not exist and sets the server context
func configHandle(s *Server, home string, cmd *cobra.Command) error {
func configHandle[AppT AppI[T], T transaction.Tx](s *Server[AppT, T], home string, cmd *cobra.Command) error {
configDir := filepath.Join(home, "config")
// we need to check app.toml as the config folder can already exist for the client.toml

View File

@ -18,12 +18,12 @@ import (
)
// ServerComponent is a server module that can be started and stopped.
type ServerComponent[T transaction.Tx] interface {
type ServerComponent[AppT AppI[T], T transaction.Tx] interface {
Name() string
Start(context.Context) error
Stop(context.Context) error
Init(AppI[T], *viper.Viper, log.Logger) error
Init(AppT, *viper.Viper, log.Logger) error
}
// HasCLICommands is a server module that has CLI commands.
@ -41,7 +41,7 @@ type HasStartFlags interface {
StartCmdFlags() *pflag.FlagSet
}
var _ ServerComponent[transaction.Tx] = (*Server)(nil)
var _ ServerComponent[AppI[transaction.Tx], transaction.Tx] = (*Server[AppI[transaction.Tx], transaction.Tx])(nil)
// Configs returns a viper instance of the config file
func ReadConfig(configPath string) (*viper.Viper, error) {
@ -63,24 +63,26 @@ func ReadConfig(configPath string) (*viper.Viper, error) {
return v, nil
}
type Server struct {
type Server[AppT AppI[T], T transaction.Tx] struct {
logger log.Logger
components []ServerComponent[transaction.Tx]
components []ServerComponent[AppT, T]
}
func NewServer(logger log.Logger, components ...ServerComponent[transaction.Tx]) *Server {
return &Server{
func NewServer[AppT AppI[T], T transaction.Tx](
logger log.Logger, components ...ServerComponent[AppT, T],
) *Server[AppT, T] {
return &Server[AppT, T]{
logger: logger,
components: components,
}
}
func (s *Server) Name() string {
func (s *Server[AppT, T]) Name() string {
return "server"
}
// Start starts all components concurrently.
func (s *Server) Start(ctx context.Context) error {
func (s *Server[AppT, T]) Start(ctx context.Context) error {
s.logger.Info("starting servers...")
g, ctx := errgroup.WithContext(ctx)
@ -104,7 +106,7 @@ func (s *Server) Start(ctx context.Context) error {
}
// Stop stops all components concurrently.
func (s *Server) Stop(ctx context.Context) error {
func (s *Server[AppT, T]) Stop(ctx context.Context) error {
s.logger.Info("stopping servers...")
g, ctx := errgroup.WithContext(ctx)
@ -119,7 +121,7 @@ func (s *Server) Stop(ctx context.Context) error {
}
// CLICommands returns all CLI commands of all components.
func (s *Server) CLICommands() CLIConfig {
func (s *Server[AppT, T]) CLICommands() CLIConfig {
compart := func(name string, cmds ...*cobra.Command) *cobra.Command {
if len(cmds) == 1 && strings.HasPrefix(cmds[0].Use, name) {
return cmds[0]
@ -147,7 +149,7 @@ func (s *Server) CLICommands() CLIConfig {
}
// Configs returns all configs of all server components.
func (s *Server) Configs() map[string]any {
func (s *Server[AppT, T]) Configs() map[string]any {
cfgs := make(map[string]any)
for _, mod := range s.components {
if configmod, ok := mod.(HasConfig); ok {
@ -160,8 +162,8 @@ func (s *Server) Configs() map[string]any {
}
// Configs returns all configs of all server components.
func (s *Server) Init(appI AppI[transaction.Tx], v *viper.Viper, logger log.Logger) error {
var components []ServerComponent[transaction.Tx]
func (s *Server[AppT, T]) Init(appI AppT, v *viper.Viper, logger log.Logger) error {
var components []ServerComponent[AppT, T]
for _, mod := range s.components {
mod := mod
if err := mod.Init(appI, v, logger); err != nil {
@ -177,7 +179,7 @@ func (s *Server) Init(appI AppI[transaction.Tx], v *viper.Viper, logger log.Logg
// WriteConfig writes the config to the given path.
// Note: it does not use viper.WriteConfigAs because we do not want to store flag values in the config.
func (s *Server) WriteConfig(configPath string) error {
func (s *Server[AppT, T]) WriteConfig(configPath string) error {
cfgs := s.Configs()
b, err := toml.Marshal(cfgs)
if err != nil {
@ -206,7 +208,7 @@ func (s *Server) WriteConfig(configPath string) error {
}
// Flags returns all flags of all server components.
func (s *Server) StartFlags() []*pflag.FlagSet {
func (s *Server[AppT, T]) StartFlags() []*pflag.FlagSet {
flags := []*pflag.FlagSet{}
for _, mod := range s.components {
if startmod, ok := mod.(HasStartFlags); ok {

View File

@ -58,7 +58,7 @@ func TestServer(t *testing.T) {
}
logger := log.NewLogger(os.Stdout)
grpcServer := grpc.New()
grpcServer := grpc.New[serverv2.AppI[transaction.Tx], transaction.Tx]()
if err := grpcServer.Init(&mockApp[transaction.Tx]{}, v, logger); err != nil {
t.Log(err)
t.Fail()

View File

@ -9,7 +9,7 @@ import (
"cosmossdk.io/server/v2/appmanager"
)
type AppCreator[T transaction.Tx] func(log.Logger, *viper.Viper) AppI[T]
type AppCreator[AppT AppI[T], T transaction.Tx] func(log.Logger, *viper.Viper) AppT
type AppI[T transaction.Tx] interface {
GetAppManager() *appmanager.AppManager[T]

View File

@ -10,6 +10,7 @@ import (
coreapp "cosmossdk.io/core/app"
"cosmossdk.io/core/legacy"
"cosmossdk.io/core/log"
"cosmossdk.io/core/transaction"
"cosmossdk.io/depinject"
"cosmossdk.io/runtime/v2"
serverv2 "cosmossdk.io/server/v2"
@ -48,8 +49,8 @@ var DefaultNodeHome string
// SimApp extends an ABCI application, but with most of its parameters exported.
// They are exported for convenience in creating helper functions, as object
// capabilities aren't needed for testing.
type SimApp struct {
*runtime.App
type SimApp[T transaction.Tx] struct {
*runtime.App[T]
legacyAmino legacy.Amino
appCodec codec.Codec
txConfig client.TxConfig
@ -91,18 +92,18 @@ func AppConfig() depinject.Config {
}
// NewSimApp returns a reference to an initialized SimApp.
func NewSimApp(
func NewSimApp[T transaction.Tx](
logger log.Logger,
viper *viper.Viper,
) *SimApp {
) *SimApp[T] {
viper.Set(serverv2.FlagHome, DefaultNodeHome) // TODO possibly set earlier when viper is created
scRawDb, err := db.NewGoLevelDB("application", filepath.Join(DefaultNodeHome, "data"), nil)
if err != nil {
panic(err)
}
var (
app = &SimApp{}
appBuilder *runtime.AppBuilder
app = &SimApp[T]{}
appBuilder *runtime.AppBuilder[T]
// merge the AppConfig and other configuration in one config
appConfig = depinject.Configs(
@ -231,26 +232,26 @@ func NewSimApp(
//
// NOTE: This is solely to be used for testing purposes as it may be desirable
// for modules to register their own custom testing types.
func (app *SimApp) AppCodec() codec.Codec {
func (app *SimApp[T]) AppCodec() codec.Codec {
return app.appCodec
}
// InterfaceRegistry returns SimApp's InterfaceRegistry.
func (app *SimApp) InterfaceRegistry() coreapp.InterfaceRegistry {
func (app *SimApp[T]) InterfaceRegistry() coreapp.InterfaceRegistry {
return app.interfaceRegistry
}
// TxConfig returns SimApp's TxConfig.
func (app *SimApp) TxConfig() client.TxConfig {
func (app *SimApp[T]) TxConfig() client.TxConfig {
return app.txConfig
}
// GetConsensusAuthority gets the consensus authority.
func (app *SimApp) GetConsensusAuthority() string {
func (app *SimApp[T]) GetConsensusAuthority() string {
return app.ConsensusParamsKeeper.GetAuthority()
}
// GetStore gets the app store.
func (app *SimApp) GetStore() any {
func (app *SimApp[T]) GetStore() any {
return app.App.GetStore()
}

View File

@ -5,6 +5,6 @@ import (
)
// ExportAppStateAndValidators exports the state of the application for a genesis file.
func (app *SimApp) ExportAppStateAndValidators(forZeroHeight bool, jailAllowedAddrs, modulesToExport []string) (servertypes.ExportedApp, error) {
func (app *SimApp[T]) ExportAppStateAndValidators(forZeroHeight bool, jailAllowedAddrs, modulesToExport []string) (servertypes.ExportedApp, error) {
panic("not implemented")
}

View File

@ -32,30 +32,56 @@ import (
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
)
var _ transaction.Codec[transaction.Tx] = &temporaryTxDecoder{}
var _ transaction.Codec[transaction.Tx] = &temporaryTxDecoder[transaction.Tx]{}
type temporaryTxDecoder struct {
type temporaryTxDecoder[T transaction.Tx] struct {
txConfig client.TxConfig
}
// Decode implements transaction.Codec.
func (t *temporaryTxDecoder) Decode(bz []byte) (transaction.Tx, error) {
return t.txConfig.TxDecoder()(bz)
func (t *temporaryTxDecoder[T]) Decode(bz []byte) (T, error) {
var out T
tx, err := t.txConfig.TxDecoder()(bz)
if err != nil {
return out, err
}
var ok bool
out, ok = tx.(T)
if !ok {
return out, errors.New("unexpected Tx type")
}
return out, nil
}
// DecodeJSON implements transaction.Codec.
func (t *temporaryTxDecoder) DecodeJSON(bz []byte) (transaction.Tx, error) {
return t.txConfig.TxJSONDecoder()(bz)
func (t *temporaryTxDecoder[T]) DecodeJSON(bz []byte) (T, error) {
var out T
tx, err := t.txConfig.TxJSONDecoder()(bz)
if err != nil {
return out, err
}
var ok bool
out, ok = tx.(T)
if !ok {
return out, errors.New("unexpected Tx type")
}
return out, nil
}
func newApp(logger log.Logger, viper *viper.Viper) serverv2.AppI[transaction.Tx] {
return simapp.NewSimApp(logger, viper)
func newApp[AppT serverv2.AppI[T], T transaction.Tx](
logger log.Logger, viper *viper.Viper,
) AppT {
return serverv2.AppI[T](simapp.NewSimApp[T](logger, viper)).(AppT)
}
func initRootCmd(
func initRootCmd[AppT serverv2.AppI[T], T transaction.Tx](
rootCmd *cobra.Command,
txConfig client.TxConfig,
moduleManager *runtimev2.MM,
moduleManager *runtimev2.MM[T],
) {
cfg := sdk.GetConfig()
cfg.Seal()
@ -78,8 +104,8 @@ func initRootCmd(
rootCmd,
newApp,
logger,
cometbft.New(&temporaryTxDecoder{txConfig}),
grpc.New(),
cometbft.New[AppT, T](&temporaryTxDecoder[T]{txConfig}),
grpc.New[AppT, T](),
); err != nil {
panic(err)
}
@ -87,7 +113,7 @@ func initRootCmd(
// add keybase, auxiliary RPC, query, genesis, and tx child commands
rootCmd.AddCommand(
server.StatusCommand(),
genesisCommand(txConfig, moduleManager, appExport),
genesisCommand[T](txConfig, moduleManager, appExport[T]),
queryCommand(),
txCommand(),
keys.Commands(),
@ -96,9 +122,9 @@ func initRootCmd(
}
// genesisCommand builds genesis-related `simd genesis` command. Users may provide application specific commands as a parameter
func genesisCommand(
func genesisCommand[T transaction.Tx](
txConfig client.TxConfig,
moduleManager *runtimev2.MM,
moduleManager *runtimev2.MM[T],
appExport func(logger log.Logger,
height int64,
forZeroHeight bool,
@ -171,7 +197,7 @@ func txCommand() *cobra.Command {
}
// appExport creates a new simapp (optionally at a given height) and exports state.
func appExport(
func appExport[T transaction.Tx](
logger log.Logger,
height int64,
forZeroHeight bool,
@ -182,15 +208,15 @@ func appExport(
// overwrite the FlagInvCheckPeriod
viper.Set(server.FlagInvCheckPeriod, 1)
var simApp *simapp.SimApp
var simApp *simapp.SimApp[T]
if height != -1 {
simApp = simapp.NewSimApp(logger, viper)
simApp = simapp.NewSimApp[T](logger, viper)
if err := simApp.LoadHeight(uint64(height)); err != nil {
return servertypes.ExportedApp{}, err
}
} else {
simApp = simapp.NewSimApp(logger, viper)
simApp = simapp.NewSimApp[T](logger, viper)
}
return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport)

View File

@ -8,9 +8,11 @@ import (
"cosmossdk.io/client/v2/autocli"
"cosmossdk.io/core/address"
"cosmossdk.io/core/legacy"
"cosmossdk.io/core/transaction"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
"cosmossdk.io/runtime/v2"
serverv2 "cosmossdk.io/server/v2"
"cosmossdk.io/simapp/v2"
"cosmossdk.io/x/auth/tx"
authtxconfig "cosmossdk.io/x/auth/tx/config"
@ -24,10 +26,10 @@ import (
)
// NewRootCmd creates a new root command for simd. It is called once in the main function.
func NewRootCmd() *cobra.Command {
func NewRootCmd[AppT serverv2.AppI[T], T transaction.Tx]() *cobra.Command {
var (
autoCliOpts autocli.AppOptions
moduleManager *runtime.MM
moduleManager *runtime.MM[T]
clientCtx client.Context
)
@ -83,7 +85,7 @@ func NewRootCmd() *cobra.Command {
},
}
initRootCmd(rootCmd, clientCtx.TxConfig, moduleManager)
initRootCmd[AppT, T](rootCmd, clientCtx.TxConfig, moduleManager)
if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil {
panic(err)
}

View File

@ -6,6 +6,8 @@ import (
"github.com/stretchr/testify/require"
"cosmossdk.io/core/transaction"
serverv2 "cosmossdk.io/server/v2"
"cosmossdk.io/simapp/v2"
"cosmossdk.io/simapp/v2/simdv2/cmd"
@ -15,7 +17,7 @@ import (
)
func TestInitCmd(t *testing.T) {
rootCmd := cmd.NewRootCmd()
rootCmd := cmd.NewRootCmd[serverv2.AppI[transaction.Tx], transaction.Tx]()
rootCmd.SetArgs([]string{
"init", // Test the init cmd
"simapp-test", // Moniker
@ -28,7 +30,7 @@ func TestInitCmd(t *testing.T) {
func TestHomeFlagRegistration(t *testing.T) {
homeDir := "/tmp/foo"
rootCmd := cmd.NewRootCmd()
rootCmd := cmd.NewRootCmd[serverv2.AppI[transaction.Tx], transaction.Tx]()
rootCmd.SetArgs([]string{
"query",
fmt.Sprintf("--%s", flags.FlagHome),

View File

@ -4,13 +4,14 @@ import (
"fmt"
"os"
"cosmossdk.io/core/transaction"
serverv2 "cosmossdk.io/server/v2"
"cosmossdk.io/simapp/v2"
"cosmossdk.io/simapp/v2/simdv2/cmd"
)
func main() {
rootCmd := cmd.NewRootCmd()
rootCmd := cmd.NewRootCmd[serverv2.AppI[transaction.Tx], transaction.Tx]()
if err := serverv2.Execute(rootCmd, "", simapp.DefaultNodeHome); err != nil {
fmt.Fprintln(rootCmd.OutOrStderr(), err)
os.Exit(1)

View File

@ -20,7 +20,7 @@ import (
// v0.50.x to v0.51.x.
const UpgradeName = "v050-to-v051"
func (app *SimApp) RegisterUpgradeHandlers() {
func (app *SimApp[T]) RegisterUpgradeHandlers() {
app.UpgradeKeeper.SetUpgradeHandler(
UpgradeName,
func(ctx context.Context, _ upgradetypes.Plan, fromVM appmodule.VersionMap) (appmodule.VersionMap, error) {