Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(server): add custom start handler #19854

Merged
merged 1 commit into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i

### Improvements

* (server) [#19854](https://github.com/cosmos/cosmos-sdk/pull/19854) Add customizability to start command.
* Add `StartCmdOptions` in `server.AddCommands` instead of `servertypes.ModuleInitFlags`. To set custom flags set them in the `StartCmdOptions` struct on the `AddFlags` field.
* Add `StartCommandHandler` to `StartCmdOptions` to allow custom start command handlers. Users now have total control over how the app starts.
* (types) [#19672](https://github.com/cosmos/cosmos-sdk/pull/19672) `PreBlock` now returns only an error for consistency with server/v2. The SDK has upgraded x/upgrade accordingly. `ResponsePreBlock` hence has been removed.
* (server) [#19455](https://github.com/cosmos/cosmos-sdk/pull/19455) Allow calling back into the application struct in PostSetup.
* (types) [#19512](https://github.com/cosmos/cosmos-sdk/pull/19512) The notion of basic manager does not exist anymore (and all related helpers).
Expand Down Expand Up @@ -102,6 +105,7 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i

### API Breaking Changes

* (server) [#19854](https://github.com/cosmos/cosmos-sdk/pull/19854) Remove `servertypes.ModuleInitFlags` types and from `server.AddCommands` as `StartCmdOptions` already achieves the same goal.
julienrbrt marked this conversation as resolved.
Show resolved Hide resolved
* (types) [#19792](https://github.com/cosmos/cosmos-sdk/pull/19792) In `MsgSimulatorFn` `sdk.Context` argument is replaced for an `address.Codec`. It also returns an error.
* (types) [#19742](https://github.com/cosmos/cosmos-sdk/pull/19742) Removes the use of `Accounts.String`
* `SimulationState` now has address and validator codecs as fields.
Expand Down
7 changes: 7 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ clientCtx = clientCtx.

Refer to SimApp `root_v2.go` and `root.go` for an example with an app v2 and a legacy app.

Additionally, a simplification of the start command leads to the following change:

```diff
- server.AddCommands(rootCmd, newApp, func(startCmd *cobra.Command) {})
+ server.AddCommands(rootCmd, newApp, server.StartCmdOptions[servertypes.Application]{})
```

#### Server (`app.go`)

##### Module Manager
Expand Down
4 changes: 2 additions & 2 deletions docs/build/building-apps/05-app-testnet.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,8 @@ Before we can run the testnet we must plug everything together.
in `root.go`, in the `initRootCmd` function we add:

```diff
server.AddCommands(rootCmd, simapp.DefaultNodeHome, newApp, createMerlinAppAndExport, addModuleInitFlags)
++ server.AddTestnetCreatorCommand(rootCmd, simapp.DefaultNodeHome, newTestnetApp, addModuleInitFlags)
server.AddCommands(rootCmd, simapp.DefaultNodeHome, newApp, createMerlinAppAndExport)
julienrbrt marked this conversation as resolved.
Show resolved Hide resolved
+server.AddTestnetCreatorCommand(rootCmd, simapp.DefaultNodeHome, newTestnetApp)
```

Next we will add a newTestnetApp helper function:
Expand Down
31 changes: 16 additions & 15 deletions server/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ type StartCmdOptions[T types.Application] struct {
PostSetupStandalone func(app T, svrCtx *Context, clientCtx client.Context, ctx context.Context, g *errgroup.Group) error
// AddFlags add custom flags to start cmd
AddFlags func(cmd *cobra.Command)
// StartCommandHanlder can be used to customize the start command handler
StartCommandHandler func(svrCtx *Context, clientCtx client.Context, appCreator types.AppCreator[T], inProcessConsensus bool, opts StartCmdOptions[T]) error
}

// StartCmd runs the service passed in, either stand-alone or in-process with
Expand All @@ -139,6 +141,10 @@ func StartCmdWithOptions[T types.Application](appCreator types.AppCreator[T], op
opts.DBOpener = OpenDB
}

if opts.StartCommandHandler == nil {
opts.StartCommandHandler = start
}

cmd := &cobra.Command{
Use: "start",
Short: "Run the full node",
Expand Down Expand Up @@ -187,7 +193,7 @@ is performed. Note, when enabled, gRPC will also be automatically enabled.
}

err = wrapCPUProfile(serverCtx, func() error {
return start(serverCtx, clientCtx, appCreator, withCMT, opts)
return opts.StartCommandHandler(serverCtx, clientCtx, appCreator, withCMT, opts)
})

serverCtx.Logger.Debug("received quit signal")
Expand Down Expand Up @@ -270,10 +276,7 @@ func startStandAlone[T types.Application](svrCtx *Context, svrCfg serverconfig.C
return err
}

cmtCfg := svrCtx.Config
home := cmtCfg.RootDir

err = startAPIServer(ctx, g, cmtCfg, svrCfg, clientCtx, svrCtx, app, home, grpcSrv, metrics)
err = startAPIServer(ctx, g, svrCfg, clientCtx, svrCtx, app, svrCtx.Config.RootDir, grpcSrv, metrics)
julienrbrt marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return err
}
Expand Down Expand Up @@ -304,8 +307,6 @@ func startInProcess[T types.Application](svrCtx *Context, svrCfg serverconfig.Co
metrics *telemetry.Metrics, opts StartCmdOptions[T],
) error {
cmtCfg := svrCtx.Config
home := cmtCfg.RootDir

gRPCOnly := svrCtx.Viper.GetBool(flagGRPCOnly)

g, ctx := getCtx(svrCtx, true)
Expand Down Expand Up @@ -341,7 +342,7 @@ func startInProcess[T types.Application](svrCtx *Context, svrCfg serverconfig.Co
return err
}

err = startAPIServer(ctx, g, cmtCfg, svrCfg, clientCtx, svrCtx, app, home, grpcSrv, metrics)
err = startAPIServer(ctx, g, svrCfg, clientCtx, svrCtx, app, cmtCfg.RootDir, grpcSrv, metrics)
julienrbrt marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return err
}
Expand Down Expand Up @@ -504,7 +505,6 @@ func startGrpcServer(
func startAPIServer(
ctx context.Context,
g *errgroup.Group,
cmtCfg *cmtcfg.Config,
svrCfg serverconfig.Config,
clientCtx client.Context,
svrCtx *Context,
Expand Down Expand Up @@ -612,7 +612,7 @@ func startApp[T types.Application](svrCtx *Context, appCreator types.AppCreator[

if isTestnet, ok := svrCtx.Viper.Get(KeyIsTestnet).(bool); ok && isTestnet {
var appPtr *T
appPtr, err = testnetify[T](svrCtx, home, appCreator, db, traceWriter)
appPtr, err = testnetify[T](svrCtx, appCreator, db, traceWriter)
if err != nil {
return app, traceCleanupFn, err
}
Expand All @@ -639,6 +639,10 @@ func InPlaceTestnetCreator[T types.Application](testnetAppCreator types.AppCreat
opts.DBOpener = OpenDB
}

if opts.StartCommandHandler == nil {
opts.StartCommandHandler = start
}

cmd := &cobra.Command{
Use: "in-place-testnet [newChainID] [newOperatorAddress]",
Short: "Create and start a testnet from current local state",
Expand Down Expand Up @@ -703,7 +707,7 @@ you want to test the upgrade handler itself.
serverCtx.Viper.Set(KeyNewOpAddr, newOperatorAddress)

err = wrapCPUProfile(serverCtx, func() error {
return start(serverCtx, clientCtx, testnetAppCreator, withCMT, opts)
return opts.StartCommandHandler(serverCtx, clientCtx, testnetAppCreator, withCMT, opts)
})

serverCtx.Logger.Debug("received quit signal")
Expand All @@ -726,7 +730,7 @@ you want to test the upgrade handler itself.

// testnetify modifies both state and blockStore, allowing the provided operator address and local validator key to control the network
// that the state in the data folder represents. The chainID of the local genesis file is modified to match the provided chainID.
func testnetify[T types.Application](ctx *Context, home string, testnetAppCreator types.AppCreator[T], db dbm.DB, traceWriter io.WriteCloser) (*T, error) {
func testnetify[T types.Application](ctx *Context, testnetAppCreator types.AppCreator[T], db dbm.DB, traceWriter io.WriteCloser) (*T, error) {
config := ctx.Config

newChainID, ok := ctx.Viper.Get(KeyNewChainID).(string)
Expand Down Expand Up @@ -772,9 +776,6 @@ func testnetify[T types.Application](ctx *Context, home string, testnetAppCreato
return nil, err
}
validatorAddress := userPubKey.Address()
if err != nil {
return nil, err
}

stateStore := sm.NewStore(stateDB, sm.StoreOptions{
DiscardABCIResponses: config.Storage.DiscardABCIResponses,
Expand Down
4 changes: 0 additions & 4 deletions server/types/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
cmttypes "github.com/cometbft/cometbft/types"
dbm "github.com/cosmos/cosmos-db"
"github.com/cosmos/gogoproto/grpc"
"github.com/spf13/cobra"

"cosmossdk.io/log"
"cosmossdk.io/store/snapshots"
Expand Down Expand Up @@ -68,9 +67,6 @@ type (
// application using various configurations.
AppCreator[T Application] func(log.Logger, dbm.DB, io.Writer, AppOptions) T

// ModuleInitFlags takes a start command and adds modules specific init flags.
ModuleInitFlags func(startCmd *cobra.Command)

// ExportedApp represents an exported app state, along with
// validators, consensus params and latest app height.
ExportedApp struct {
Expand Down
17 changes: 9 additions & 8 deletions server/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ func interceptConfigs(rootViper *viper.Viper, customAppTemplate string, customCo
}

// AddCommands add server commands
func AddCommands[T types.Application](rootCmd *cobra.Command, appCreator types.AppCreator[T], addStartFlags types.ModuleInitFlags) {
Copy link
Member Author

@julienrbrt julienrbrt Mar 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We had two ways to do the same things for flags: Using StartCmdOptions and setting AddFlags and then calling StartCmdWithOptions. Or use AddCommands with custom flags on the start command. This concatenates the possibilities in one.
Note, the backport to v0.50 won't contain that breaking change ( AddCommandsWithStartCmdOptions will do what AddCommands does for v0.51)

func AddCommands[T types.Application](rootCmd *cobra.Command, appCreator types.AppCreator[T], opts StartCmdOptions[T]) {
cometCmd := &cobra.Command{
Use: "comet",
Aliases: []string{"cometbft", "tendermint"},
Expand All @@ -341,11 +341,7 @@ func AddCommands[T types.Application](rootCmd *cobra.Command, appCreator types.A
BootstrapStateCmd(appCreator),
)

startCmd := StartCmd(appCreator)
if addStartFlags != nil {
addStartFlags(startCmd)
}

startCmd := StartCmdWithOptions(appCreator, opts)
rootCmd.AddCommand(
startCmd,
cometCmd,
Expand All @@ -354,10 +350,15 @@ func AddCommands[T types.Application](rootCmd *cobra.Command, appCreator types.A
)
}

// AddCommandsWithStartCmdOptions adds server commands with the provided StartCmdOptions.
// Deprecated: Use AddCommands directly instead.
func AddCommandsWithStartCmdOptions[T types.Application](rootCmd *cobra.Command, appCreator types.AppCreator[T], opts StartCmdOptions[T]) {
AddCommands(rootCmd, appCreator, opts)
}

// AddTestnetCreatorCommand allows chains to create a testnet from the state existing in their node's data directory.
func AddTestnetCreatorCommand[T types.Application](rootCmd *cobra.Command, appCreator types.AppCreator[T], addStartFlags types.ModuleInitFlags) {
func AddTestnetCreatorCommand[T types.Application](rootCmd *cobra.Command, appCreator types.AppCreator[T]) {
testnetCreateCmd := InPlaceTestnetCreator(appCreator)
addStartFlags(testnetCreateCmd)
rootCmd.AddCommand(testnetCreateCmd)
}

Expand Down
6 changes: 1 addition & 5 deletions simapp/simd/cmd/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ import (
"github.com/cosmos/cosmos-sdk/client/pruning"
"github.com/cosmos/cosmos-sdk/client/rpc"
"github.com/cosmos/cosmos-sdk/client/snapshot"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/server"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -35,8 +33,6 @@ import (
func initRootCmd(
rootCmd *cobra.Command,
txConfig client.TxConfig,
interfaceRegistry codectypes.InterfaceRegistry,
appCodec codec.Codec,
moduleManager *module.Manager,
) {
cfg := sdk.GetConfig()
Expand All @@ -51,7 +47,7 @@ func initRootCmd(
snapshot.Cmd(newApp),
)

server.AddCommands(rootCmd, newApp, func(startCmd *cobra.Command) {})
server.AddCommands(rootCmd, newApp, server.StartCmdOptions[servertypes.Application]{})

// add keybase, auxiliary RPC, query, genesis, and tx child commands
rootCmd.AddCommand(
Expand Down
2 changes: 1 addition & 1 deletion simapp/simd/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func NewRootCmd() *cobra.Command {
},
}

initRootCmd(rootCmd, encodingConfig.TxConfig, encodingConfig.InterfaceRegistry, encodingConfig.Codec, tempApp.ModuleManager)
initRootCmd(rootCmd, encodingConfig.TxConfig, tempApp.ModuleManager)

// autocli opts
customClientTemplate, customClientConfig := initClientConfig()
Expand Down
2 changes: 1 addition & 1 deletion simapp/simd/cmd/root_di.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func NewRootCmd() *cobra.Command {
},
}

initRootCmd(rootCmd, clientCtx.TxConfig, clientCtx.InterfaceRegistry, clientCtx.Codec, moduleManager)
initRootCmd(rootCmd, clientCtx.TxConfig, moduleManager)

if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil {
panic(err)
Expand Down
Loading