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"
2020-06-26 09:30:49 -07:00
"time"
2019-02-08 11:37:46 -08:00
2018-02-14 11:04:34 -08:00
"github.com/spf13/cobra"
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"
2020-06-15 10:39:09 -07:00
"github.com/tendermint/tendermint/rpc/client/local"
"github.com/cosmos/cosmos-sdk/client"
2020-07-05 09:56:17 -07:00
"github.com/cosmos/cosmos-sdk/client/flags"
2020-06-15 10:39:09 -07:00
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/server/api"
"github.com/cosmos/cosmos-sdk/server/config"
2020-06-22 13:31:33 -07:00
storetypes "github.com/cosmos/cosmos-sdk/store/types"
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-06-22 13:31:33 -07:00
flagWithTendermint = "with-tendermint"
flagAddress = "address"
flagTraceStore = "trace-store"
flagCPUProfile = "cpu-profile"
FlagMinGasPrices = "minimum-gas-prices"
FlagHaltHeight = "halt-height"
FlagHaltTime = "halt-time"
FlagInterBlockCache = "inter-block-cache"
FlagUnsafeSkipUpgrades = "unsafe-skip-upgrades"
2020-07-05 09:56:17 -07:00
FlagTrace = "trace"
FlagInvCheckPeriod = "inv-check-period"
2020-06-22 13:31:33 -07:00
FlagPruning = "pruning"
FlagPruningKeepRecent = "pruning-keep-recent"
FlagPruningKeepEvery = "pruning-keep-every"
FlagPruningInterval = "pruning-interval"
2018-02-14 11:04:34 -08:00
)
2018-07-12 16:58:51 -07:00
// StartCmd runs the service passed in, either stand-alone or in-process with
// Tendermint.
2020-07-20 08:12:33 -07:00
func StartCmd ( appCreator AppCreator , defaultNodeHome string ) * 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 .
2020-06-22 13:31:33 -07:00
Pruning options can be provided via the ' -- pruning ' flag or alternatively with ' -- pruning - keep - recent ' ,
' pruning - keep - every ' , and ' pruning - interval ' together .
2020-02-27 07:05:10 -08:00
For ' -- pruning ' the options are as follows :
2019-09-09 07:08:10 -07:00
2020-06-22 13:31:33 -07:00
default : the last 100 states are kept in addition to every 500 th state ; pruning at 10 block intervals
2019-09-09 07:08:10 -07:00
nothing : all historic states will be saved , nothing will be deleted ( i . e . archiving node )
2020-06-22 13:31:33 -07:00
everything : all saved states will be deleted , storing only the current state ; pruning at 10 block intervals
custom : allow pruning options to be manually specified through ' pruning - keep - recent ' , ' pruning - keep - every ' , and ' pruning - interval '
2019-09-09 07:08:10 -07:00
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-07-07 08:40:46 -07:00
PreRunE : func ( cmd * cobra . Command , _ [ ] string ) error {
serverCtx := GetServerContextFromCmd ( cmd )
// Bind flags to the Context's Viper so the app construction can set
// options accordingly.
serverCtx . Viper . BindPFlags ( cmd . Flags ( ) )
_ , err := GetPruningOptionsFromFlags ( serverCtx . Viper )
2020-04-14 08:24:27 -07:00
return err
2020-02-27 03:01:27 -08:00
} ,
2020-07-07 08:40:46 -07:00
RunE : func ( cmd * cobra . Command , _ [ ] string ) error {
serverCtx := GetServerContextFromCmd ( cmd )
clientCtx := client . GetClientContextFromCmd ( cmd )
2020-07-05 09:56:17 -07:00
withTM , _ := cmd . Flags ( ) . GetBool ( flagWithTendermint )
if ! withTM {
2020-07-07 08:40:46 -07:00
serverCtx . Logger . Info ( "starting ABCI without Tendermint" )
return startStandAlone ( serverCtx , appCreator )
2018-04-21 19:26:46 -07:00
}
2018-07-12 16:58:51 -07:00
2020-07-07 08:40:46 -07:00
serverCtx . Logger . Info ( "starting ABCI with Tendermint" )
2018-07-12 16:58:51 -07:00
2020-07-07 08:40:46 -07:00
err := startInProcess ( serverCtx , clientCtx . JSONMarshaler , appCreator )
2018-07-01 12:10:45 -07:00
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
2020-07-20 08:12:33 -07:00
cmd . Flags ( ) . String ( flags . FlagHome , defaultNodeHome , "The application home directory" )
2018-07-12 16:58:51 -07:00
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" )
2020-07-05 09:56:17 -07: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)" )
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" )
2020-07-05 09:56:17 -07:00
cmd . Flags ( ) . Bool ( FlagTrace , false , "Provide full stack traces for errors in ABCI Log" )
2020-06-22 13:31:33 -07:00
cmd . Flags ( ) . String ( FlagPruning , storetypes . PruningOptionDefault , "Pruning strategy (default|nothing|everything|custom)" )
cmd . Flags ( ) . Uint64 ( FlagPruningKeepRecent , 0 , "Number of recent heights to keep on disk (ignored if pruning is not 'custom')" )
cmd . Flags ( ) . Uint64 ( FlagPruningKeepEvery , 0 , "Offset heights to keep on disk after 'keep-every' (ignored if pruning is not 'custom')" )
cmd . Flags ( ) . Uint64 ( FlagPruningInterval , 0 , "Height interval at which pruned heights are removed from disk (ignored if pruning is not 'custom')" )
2020-07-05 09:56:17 -07:00
cmd . Flags ( ) . Uint ( FlagInvCheckPeriod , 0 , "Assert registered invariants every N blocks" )
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 {
2020-07-05 09:56:17 -07:00
addr := ctx . Viper . GetString ( flagAddress )
home := ctx . Viper . GetString ( flags . FlagHome )
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
}
2020-07-05 09:56:17 -07:00
traceWriterFile := ctx . Viper . GetString ( flagTraceStore )
2018-10-10 15:45:41 -07:00
traceWriter , err := openTraceWriter ( traceWriterFile )
if err != nil {
return err
}
2020-07-05 09:56:17 -07:00
app := appCreator ( ctx . Logger , db , traceWriter , ctx . Viper )
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-07-07 08:40:46 -07:00
TrapSignal ( func ( ) {
if err = svr . Stop ( ) ; 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
}
2020-06-15 10:39:09 -07:00
func startInProcess ( ctx * Context , cdc codec . JSONMarshaler , appCreator AppCreator ) 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-07-05 09:56:17 -07:00
traceWriterFile := ctx . 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 {
2020-05-02 12:26:59 -07:00
return 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 {
2020-05-02 12:26:59 -07:00
return err
2018-10-10 15:45:41 -07:00
}
2020-07-05 09:56:17 -07:00
app := appCreator ( ctx . Logger , db , traceWriter , ctx . Viper )
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 {
2020-05-02 12:26:59 -07:00
return err
2018-10-03 08:48:23 -07:00
}
2020-06-15 10:39:09 -07:00
genDocProvider := node . DefaultGenesisDocProviderFunc ( cfg )
2018-07-12 16:58:51 -07:00
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 ) ,
2020-06-15 10:39:09 -07:00
genDocProvider ,
2018-02-14 11:04:34 -08:00
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 {
2020-05-02 12:26:59 -07:00
return err
2018-02-14 11:04:34 -08:00
}
2019-08-30 08:46:48 -07:00
if err := tmNode . Start ( ) ; err != nil {
2020-05-02 12:26:59 -07:00
return err
2018-02-14 11:04:34 -08:00
}
2020-06-16 10:31:35 -07:00
var apiSrv * api . Server
2020-06-26 09:30:49 -07:00
2020-07-05 09:56:17 -07:00
config := config . GetConfig ( ctx . Viper )
2020-06-16 10:31:35 -07:00
if config . API . Enable {
2020-06-15 10:39:09 -07:00
genDoc , err := genDocProvider ( )
if err != nil {
return err
}
2020-06-26 09:30:49 -07:00
clientCtx := client . Context { } .
2020-06-15 10:39:09 -07:00
WithHomeDir ( home ) .
WithChainID ( genDoc . ChainID ) .
WithJSONMarshaler ( cdc ) .
WithClient ( local . New ( tmNode ) ) .
WithTrustNode ( true )
2020-06-26 09:30:49 -07:00
apiSrv = api . New ( clientCtx , ctx . Logger . With ( "module" , "api-server" ) )
2020-06-15 10:39:09 -07:00
app . RegisterAPIRoutes ( apiSrv )
2020-06-26 09:30:49 -07:00
errCh := make ( chan error )
go func ( ) {
if err := apiSrv . Start ( config ) ; err != nil {
errCh <- err
}
} ( )
select {
case err := <- errCh :
2020-06-15 10:39:09 -07:00
return err
2020-06-26 09:30:49 -07:00
case <- time . After ( 5 * time . Second ) : // assume server started successfully
2020-06-15 10:39:09 -07:00
}
}
2019-08-30 08:46:48 -07:00
var cpuProfileCleanup func ( )
2020-07-05 09:56:17 -07:00
if cpuProfile := ctx . Viper . GetString ( flagCPUProfile ) ; cpuProfile != "" {
2019-08-30 08:46:48 -07:00
f , err := os . Create ( cpuProfile )
if err != nil {
2020-05-02 12:26:59 -07:00
return err
2019-08-30 08:46:48 -07:00
}
ctx . Logger . Info ( "starting CPU profiler" , "profile" , cpuProfile )
if err := pprof . StartCPUProfile ( f ) ; err != nil {
2020-05-02 12:26:59 -07:00
return err
2019-08-30 08:46:48 -07:00
}
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 ( )
}
2020-06-16 10:31:35 -07:00
if apiSrv != nil {
_ = apiSrv . Close ( )
}
2019-08-30 08:46:48 -07:00
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
}