2018-02-14 11:04:34 -08:00
package server
2019-08-30 08:46:48 -07:00
// DONTCOVER
2018-02-14 11:04:34 -08:00
import (
2019-02-08 11:37:46 -08:00
"fmt"
2019-08-30 08:46:48 -07:00
"os"
"runtime/pprof"
2019-02-08 11:37:46 -08:00
2018-02-14 11:04:34 -08:00
"github.com/spf13/cobra"
"github.com/spf13/viper"
2018-06-28 17:54:47 -07:00
"github.com/tendermint/tendermint/abci/server"
2018-02-14 11:04:34 -08:00
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
2020-01-16 13:46:51 -08:00
tmos "github.com/tendermint/tendermint/libs/os"
2018-02-14 11:04:34 -08:00
"github.com/tendermint/tendermint/node"
2018-10-03 08:48:23 -07:00
"github.com/tendermint/tendermint/p2p"
2018-06-05 18:04:16 -07:00
pvm "github.com/tendermint/tendermint/privval"
2018-06-13 12:13:22 -07:00
"github.com/tendermint/tendermint/proxy"
2018-02-14 11:04:34 -08:00
)
2019-01-18 08:45:20 -08:00
// Tendermint full-node start flags
2018-02-14 11:04:34 -08:00
const (
2020-02-27 03:01:27 -08:00
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"
2018-02-14 11:04:34 -08:00
)
2020-02-27 03:01:27 -08:00
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 )
2020-02-27 03:18:21 -08:00
var errPruningOptionsRequired = fmt . Errorf ( "pruning options required" )
2020-02-27 03:01:27 -08:00
2018-07-12 16:58:51 -07:00
// 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 {
2018-02-14 11:04:34 -08:00
cmd := & cobra . Command {
Use : "start" ,
Short : "Run the full node" ,
2019-09-09 07:08:10 -07:00
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 :
2020-02-06 12:58:32 -08:00
syncable : only those states not needed for state syncing will be deleted ( flushes every 100 th to disk and keeps every 10000 th )
2019-09-09 07:08:10 -07:00
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 .
` ,
2020-02-27 03:01:27 -08:00
PreRunE : func ( cmd * cobra . Command , args [ ] string ) error {
2020-02-27 03:18:21 -08:00
if ! viper . IsSet ( flagPruning ) && ! viper . IsSet ( flagPruningKeepEvery ) && ! viper . IsSet ( flagPruningSnapshotEvery ) {
return errPruningOptionsRequired
}
2020-02-27 03:01:27 -08:00
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-21 19:26:46 -07:00
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
if ! viper . GetBool ( flagWithTendermint ) {
2019-08-30 08:46:48 -07:00
ctx . Logger . Info ( "starting ABCI without Tendermint" )
2018-04-21 19:26:46 -07:00
return startStandAlone ( ctx , appCreator )
}
2018-07-12 16:58:51 -07:00
2019-08-30 08:46:48 -07:00
ctx . Logger . Info ( "starting ABCI with Tendermint" )
2018-07-12 16:58:51 -07:00
2018-07-01 12:10:45 -07:00
_ , err := startInProcess ( ctx , appCreator )
return err
2018-04-21 19:26:46 -07:00
} ,
2018-02-14 11:04:34 -08:00
}
2018-04-21 19:26:46 -07:00
2018-07-12 16:58:51 -07:00
// core flags for the ABCI application
cmd . Flags ( ) . Bool ( flagWithTendermint , true , "Run abci app embedded in-process with tendermint" )
2018-06-13 15:13:51 -07:00
cmd . Flags ( ) . String ( flagAddress , "tcp://0.0.0.0:26658" , "Listen address" )
2018-07-12 16:58:51 -07:00
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" )
2019-01-18 08:45:20 -08:00
cmd . Flags ( ) . String (
FlagMinGasPrices , "" ,
2019-02-07 18:14:54 -08:00
"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
)
2020-01-03 06:37:29 -08:00
cmd . Flags ( ) . IntSlice ( FlagUnsafeSkipUpgrades , [ ] int { } , "Skip a set of upgrade heights to continue the old binary" )
2019-09-09 07:08:10 -07:00
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" )
2019-09-04 10:33:32 -07:00
cmd . Flags ( ) . Bool ( FlagInterBlockCache , true , "Enable inter-block caching" )
2019-08-30 08:46:48 -07:00
cmd . Flags ( ) . String ( flagCPUProfile , "" , "Enable CPU profiling and write to the provided file" )
2018-02-14 11:04:34 -08:00
2018-07-12 16:58:51 -07:00
// add support for all Tendermint-specific command line options
2018-02-14 11:04:34 -08:00
tcmd . AddNodeFlags ( cmd )
return cmd
}
2018-04-27 17:36:11 -07:00
func startStandAlone ( ctx * Context , appCreator AppCreator ) error {
2018-02-14 11:04:34 -08:00
addr := viper . GetString ( flagAddress )
2018-02-21 09:56:04 -08:00
home := viper . GetString ( "home" )
2018-10-10 15:45:41 -07:00
traceWriterFile := viper . GetString ( flagTraceStore )
2018-07-12 16:58:51 -07:00
2018-10-10 15:45:41 -07:00
db , err := openDB ( home )
2018-02-21 09:56:04 -08:00
if err != nil {
return err
}
2018-10-10 15:45:41 -07:00
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 )
2018-02-14 11:04:34 -08:00
if err != nil {
2019-02-08 11:37:46 -08:00
return fmt . Errorf ( "error creating listener: %v" , err )
2018-02-14 11:04:34 -08:00
}
2018-07-12 16:58:51 -07:00
2018-04-21 19:26:46 -07:00
svr . SetLogger ( ctx . Logger . With ( "module" , "abci-server" ) )
2018-07-12 16:58:51 -07:00
2018-06-28 15:52:10 -07:00
err = svr . Start ( )
if err != nil {
2020-01-16 13:46:51 -08:00
tmos . Exit ( err . Error ( ) )
2018-06-28 15:52:10 -07:00
}
2018-02-14 11:04:34 -08:00
2020-01-16 13:46:51 -08:00
tmos . TrapSignal ( ctx . Logger , func ( ) {
2018-07-12 16:58:51 -07:00
// cleanup
2018-06-28 15:52:10 -07:00
err = svr . Stop ( )
if err != nil {
2020-01-16 13:46:51 -08:00
tmos . Exit ( err . Error ( ) )
2018-06-28 15:52:10 -07:00
}
2018-02-14 11:04:34 -08:00
} )
2019-08-11 15:42:10 -07:00
// run forever (the node will not be returned)
select { }
2018-02-14 11:04:34 -08:00
}
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
2018-07-12 16:58:51 -07:00
2020-01-03 06:37:29 -08:00
traceWriterFile := viper . GetString ( flagTraceStore )
2018-10-10 15:45:41 -07:00
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
}
2020-01-03 06:37:29 -08:00
2018-10-10 15:45:41 -07: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
2018-10-03 08:48:23 -07:00
nodeKey , err := p2p . LoadOrGenNodeKey ( cfg . NodeKeyFile ( ) )
if err != nil {
return nil , err
}
2019-01-11 09:19:01 -08:00
UpgradeOldPrivValFile ( cfg )
2019-08-30 08:46:48 -07:00
2018-07-12 16:58:51 -07:00
// create & start tendermint node
tmNode , err := node . NewNode (
cfg ,
2019-01-11 09:19:01 -08:00
pvm . LoadOrGenFilePV ( cfg . PrivValidatorKeyFile ( ) , cfg . PrivValidatorStateFile ( ) ) ,
2018-10-03 08:48:23 -07:00
nodeKey ,
2018-02-21 09:56:04 -08:00
proxy . NewLocalClientCreator ( app ) ,
2018-02-14 11:04:34 -08:00
node . DefaultGenesisDocProviderFunc ( cfg ) ,
node . DefaultDBProvider ,
2018-08-12 00:33:48 -07:00
node . DefaultMetricsProvider ( cfg . Instrumentation ) ,
2018-07-12 16:58:51 -07:00
ctx . Logger . With ( "module" , "node" ) ,
)
2018-02-14 11:04:34 -08:00
if err != nil {
2018-07-01 12:10:45 -07:00
return nil , err
2018-02-14 11:04:34 -08:00
}
2019-08-30 08:46:48 -07:00
if err := tmNode . Start ( ) ; err != nil {
2018-07-01 12:10:45 -07:00
return nil , err
2018-02-14 11:04:34 -08:00
}
2019-08-30 08:46:48 -07:00
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 ( )
}
}
2018-11-04 18:28:38 -08:00
TrapSignal ( func ( ) {
if tmNode . IsRunning ( ) {
_ = tmNode . Stop ( )
}
2019-08-30 08:46:48 -07:00
if cpuProfileCleanup != nil {
cpuProfileCleanup ( )
}
ctx . Logger . Info ( "exiting..." )
2018-11-04 18:28:38 -08:00
} )
// run forever (the node will not be returned)
select { }
2018-02-14 11:04:34 -08:00
}