cosmos-sdk/server/start.go

241 lines
7.4 KiB
Go
Raw Normal View History

package server
// DONTCOVER
import (
"fmt"
"os"
"runtime/pprof"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/tendermint/tendermint/abci/server"
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
tmos "github.com/tendermint/tendermint/libs/os"
"github.com/tendermint/tendermint/node"
"github.com/tendermint/tendermint/p2p"
2018-06-05 18:04:16 -07:00
pvm "github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/proxy"
)
2019-01-18 08:45:20 -08:00
// Tendermint full-node start flags
const (
flagWithTendermint = "with-tendermint"
flagAddress = "address"
flagTraceStore = "trace-store"
flagPruning = "pruning"
flagPruningKeepEvery = "pruning-keep-every"
flagPruningSnapshotEvery = "pruning-snapshot-every"
flagCPUProfile = "cpu-profile"
FlagMinGasPrices = "minimum-gas-prices"
FlagHaltHeight = "halt-height"
FlagHaltTime = "halt-time"
FlagInterBlockCache = "inter-block-cache"
FlagUnsafeSkipUpgrades = "unsafe-skip-upgrades"
)
var errPruningWithGranularOptions = fmt.Errorf("%s flag is not compatible with granular options as %s or %s", flagPruning, flagPruningKeepEvery, flagPruningSnapshotEvery)
var errPruningGranularOptions = fmt.Errorf("%s and %s must be set together", flagPruningSnapshotEvery, flagPruningKeepEvery)
// StartCmd runs the service passed in, either stand-alone or in-process with
// Tendermint.
2018-04-27 17:36:11 -07:00
func StartCmd(ctx *Context, appCreator AppCreator) *cobra.Command {
cmd := &cobra.Command{
Use: "start",
Short: "Run the full node",
Long: `Run the full node application with Tendermint in or out of process. By
default, the application will run with Tendermint in process.
Pruning options can be provided via the '--pruning' flag. The options are as follows:
syncable: only those states not needed for state syncing will be deleted (flushes every 100th to disk and keeps every 10000th)
nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node)
everything: all saved states will be deleted, storing only the current state
Node halting configurations exist in the form of two flags: '--halt-height' and '--halt-time'. During
the ABCI Commit phase, the node will check if the current block height is greater than or equal to
the halt-height or if the current block time is greater than or equal to the halt-time. If so, the
node will attempt to gracefully shutdown and the block will not be committed. In addition, the node
will not be able to commit subsequent blocks.
For profiling and benchmarking purposes, CPU profiling can be enabled via the '--cpu-profile' flag
which accepts a path for the resulting pprof file.
`,
PreRunE: func(cmd *cobra.Command, args []string) error {
return checkPruningParams()
},
2018-04-21 19:26:46 -07:00
RunE: func(cmd *cobra.Command, args []string) error {
if !viper.GetBool(flagWithTendermint) {
ctx.Logger.Info("starting ABCI without Tendermint")
2018-04-21 19:26:46 -07:00
return startStandAlone(ctx, appCreator)
}
ctx.Logger.Info("starting ABCI with Tendermint")
2018-07-01 12:10:45 -07:00
_, err := startInProcess(ctx, appCreator)
return err
2018-04-21 19:26:46 -07:00
},
}
2018-04-21 19:26:46 -07:00
// core flags for the ABCI application
cmd.Flags().Bool(flagWithTendermint, true, "Run abci app embedded in-process with tendermint")
cmd.Flags().String(flagAddress, "tcp://0.0.0.0:26658", "Listen address")
cmd.Flags().String(flagTraceStore, "", "Enable KVStore tracing to an output file")
2018-07-12 18:20:26 -07:00
cmd.Flags().String(flagPruning, "syncable", "Pruning strategy: syncable, nothing, everything")
2020-02-27 06:56:07 -08:00
cmd.Flags().Int64(flagPruningKeepEvery, 0, "Define the state number that will be kept")
cmd.Flags().Int64(flagPruningSnapshotEvery, 0, "Defines the state that will be snapshot for pruning")
2019-01-18 08:45:20 -08:00
cmd.Flags().String(
FlagMinGasPrices, "",
"Minimum gas prices to accept for transactions; Any fee in a tx must meet this minimum (e.g. 0.01photino;0.0001stake)",
2019-01-18 08:45:20 -08:00
)
cmd.Flags().IntSlice(FlagUnsafeSkipUpgrades, []int{}, "Skip a set of upgrade heights to continue the old binary")
cmd.Flags().Uint64(FlagHaltHeight, 0, "Block height at which to gracefully halt the chain and shutdown the node")
cmd.Flags().Uint64(FlagHaltTime, 0, "Minimum block time (in Unix seconds) at which to gracefully halt the chain and shutdown the node")
cmd.Flags().Bool(FlagInterBlockCache, true, "Enable inter-block caching")
cmd.Flags().String(flagCPUProfile, "", "Enable CPU profiling and write to the provided file")
// add support for all Tendermint-specific command line options
tcmd.AddNodeFlags(cmd)
return cmd
}
// checkPruningParams checks that the provided pruning params are correct
func checkPruningParams() error {
if !viper.IsSet(flagPruning) && !viper.IsSet(flagPruningKeepEvery) && !viper.IsSet(flagPruningSnapshotEvery) {
2020-02-27 06:56:07 -08:00
return nil // Use default
}
if viper.IsSet(flagPruning) {
if viper.IsSet(flagPruningKeepEvery) || viper.IsSet(flagPruningSnapshotEvery) {
return errPruningWithGranularOptions
}
return nil
}
if !(viper.IsSet(flagPruningKeepEvery) && viper.IsSet(flagPruningSnapshotEvery)) {
return errPruningGranularOptions
}
return nil
}
2018-04-27 17:36:11 -07:00
func startStandAlone(ctx *Context, appCreator AppCreator) error {
addr := viper.GetString(flagAddress)
2018-02-21 09:56:04 -08:00
home := viper.GetString("home")
traceWriterFile := viper.GetString(flagTraceStore)
db, err := openDB(home)
2018-02-21 09:56:04 -08:00
if err != nil {
return err
}
traceWriter, err := openTraceWriter(traceWriterFile)
if err != nil {
return err
}
app := appCreator(ctx.Logger, db, traceWriter)
2018-02-21 09:56:04 -08:00
svr, err := server.NewServer(addr, "socket", app)
if err != nil {
return fmt.Errorf("error creating listener: %v", err)
}
2018-04-21 19:26:46 -07:00
svr.SetLogger(ctx.Logger.With("module", "abci-server"))
err = svr.Start()
if err != nil {
tmos.Exit(err.Error())
}
tmos.TrapSignal(ctx.Logger, func() {
// cleanup
err = svr.Stop()
if err != nil {
tmos.Exit(err.Error())
}
})
// run forever (the node will not be returned)
select {}
}
2018-07-01 12:10:45 -07:00
func startInProcess(ctx *Context, appCreator AppCreator) (*node.Node, error) {
2018-04-21 19:26:46 -07:00
cfg := ctx.Config
2018-02-21 09:56:04 -08:00
home := cfg.RootDir
traceWriterFile := viper.GetString(flagTraceStore)
db, err := openDB(home)
2018-02-21 09:56:04 -08:00
if err != nil {
2018-07-01 12:10:45 -07:00
return nil, err
2018-02-21 09:56:04 -08:00
}
traceWriter, err := openTraceWriter(traceWriterFile)
if err != nil {
return nil, err
}
app := appCreator(ctx.Logger, db, traceWriter)
2018-02-21 09:56:04 -08:00
nodeKey, err := p2p.LoadOrGenNodeKey(cfg.NodeKeyFile())
if err != nil {
return nil, err
}
UpgradeOldPrivValFile(cfg)
// create & start tendermint node
tmNode, err := node.NewNode(
cfg,
pvm.LoadOrGenFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile()),
nodeKey,
2018-02-21 09:56:04 -08:00
proxy.NewLocalClientCreator(app),
node.DefaultGenesisDocProviderFunc(cfg),
node.DefaultDBProvider,
node.DefaultMetricsProvider(cfg.Instrumentation),
ctx.Logger.With("module", "node"),
)
if err != nil {
2018-07-01 12:10:45 -07:00
return nil, err
}
if err := tmNode.Start(); err != nil {
2018-07-01 12:10:45 -07:00
return nil, err
}
var cpuProfileCleanup func()
if cpuProfile := viper.GetString(flagCPUProfile); cpuProfile != "" {
f, err := os.Create(cpuProfile)
if err != nil {
return nil, err
}
ctx.Logger.Info("starting CPU profiler", "profile", cpuProfile)
if err := pprof.StartCPUProfile(f); err != nil {
return nil, err
}
cpuProfileCleanup = func() {
ctx.Logger.Info("stopping CPU profiler", "profile", cpuProfile)
pprof.StopCPUProfile()
f.Close()
}
}
TrapSignal(func() {
if tmNode.IsRunning() {
_ = tmNode.Stop()
}
if cpuProfileCleanup != nil {
cpuProfileCleanup()
}
ctx.Logger.Info("exiting...")
})
// run forever (the node will not be returned)
select {}
}