Skip to content

Commit

Permalink
Merge PR #4059: Add support for graceful halt via server config
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderbez authored Apr 23, 2019
1 parent 4bf9d2b commit c6cb84c
Show file tree
Hide file tree
Showing 10 changed files with 58 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#3981 Add support to gracefully halt a node at a given height
via the node's `halt-height` config or CLI value.
27 changes: 24 additions & 3 deletions baseapp/baseapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package baseapp
import (
"fmt"
"io"
"os"
"reflect"
"runtime/debug"
"strings"
Expand Down Expand Up @@ -81,6 +82,9 @@ type BaseApp struct {

// flag for sealing options and parameters to a BaseApp
sealed bool

// height at which to halt the chain and gracefully shutdown
haltHeight uint64
}

var _ abci.Application = (*BaseApp)(nil)
Expand Down Expand Up @@ -230,6 +234,10 @@ func (app *BaseApp) setMinGasPrices(gasPrices sdk.DecCoins) {
app.minGasPrices = gasPrices
}

func (app *BaseApp) setHaltHeight(height uint64) {
app.haltHeight = height
}

// Router returns the router of the BaseApp.
func (app *BaseApp) Router() Router {
if app.sealed {
Expand Down Expand Up @@ -885,7 +893,13 @@ func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBloc
return
}

// Commit implements the ABCI interface.
// Commit implements the ABCI interface. It will commit all state that exists in
// the deliver state's multi-store and includes the resulting commit ID in the
// returned abci.ResponseCommit. Commit will set the check state based on the
// latest header and reset the deliver state. Also, if a non-zero halt height is
// defined in config, Commit will execute a deferred function call to check
// against that height and gracefully halt if it matches the latest committed
// height.
func (app *BaseApp) Commit() (res abci.ResponseCommit) {
header := app.deliverState.ctx.BlockHeader()

Expand All @@ -896,13 +910,20 @@ func (app *BaseApp) Commit() (res abci.ResponseCommit) {

// Reset the Check state to the latest committed.
//
// NOTE: safe because Tendermint holds a lock on the mempool for Commit.
// Use the header from this latest block.
// NOTE: This is safe because Tendermint holds a lock on the mempool for
// Commit. Use the header from this latest block.
app.setCheckState(header)

// empty/reset the deliver state
app.deliverState = nil

defer func() {
if app.haltHeight > 0 && uint64(header.Height) == app.haltHeight {
app.logger.Info("halting node per configuration", "height", app.haltHeight)
os.Exit(0)
}
}()

return abci.ResponseCommit{
Data: commitID.Hash,
}
Expand Down
5 changes: 5 additions & 0 deletions baseapp/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ func SetMinGasPrices(gasPricesStr string) func(*BaseApp) {
return func(bap *BaseApp) { bap.setMinGasPrices(gasPrices) }
}

// SetHaltHeight returns a BaseApp option function that sets the halt height.
func SetHaltHeight(height uint64) func(*BaseApp) {
return func(bap *BaseApp) { bap.setHaltHeight(height) }
}

func (app *BaseApp) SetName(name string) {
if app.sealed {
panic("SetName() on sealed BaseApp")
Expand Down
1 change: 1 addition & 0 deletions cmd/gaia/cmd/gaiad/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application
logger, db, traceStore, true, invCheckPeriod,
baseapp.SetPruning(store.NewPruningOptionsFromString(viper.GetString("pruning"))),
baseapp.SetMinGasPrices(viper.GetString(server.FlagMinGasPrices)),
baseapp.SetHaltHeight(uint64(viper.GetInt(server.FlagHaltHeight))),
)
}

Expand Down
2 changes: 2 additions & 0 deletions cmd/gaia/init/testnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@ func initTestnet(config *tmconfig.Config, cdc *codec.Codec) error {
return err
}

// TODO: Rename config file to server.toml as it's not particular to Gaia
// (REF: https://github.com/cosmos/cosmos-sdk/issues/4125).
gaiaConfigFilePath := filepath.Join(nodeDir, "config/gaiad.toml")
srvconfig.WriteConfigFile(gaiaConfigFilePath, gaiaConfig)
}
Expand Down
9 changes: 9 additions & 0 deletions docs/cosmos-hub/validators/validator-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,15 @@ You should also be able to see your validator on the [Explorer](https://explorec
To be in the validator set, you need to have more total voting power than the 100th validator.
:::

## Halting Your Validator

When attempting to perform routine maintenance or planning for an upcoming coordinated
upgrade, it can be useful to have your validator systematically and gracefully halt.
You can achieve this by either setting the `halt-height` to the height at which
you want your node to shutdown or by passing the `--halt-height` flag to `gaiad`.
The node will shutdown with a zero exit code at that given height after committing
the block.

## Common Problems

### Problem #1: My validator has `voting_power: 0`
Expand Down
5 changes: 5 additions & 0 deletions server/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ type BaseConfig struct {
// transaction. A transaction's fees must meet the minimum of any denomination
// specified in this config (e.g. 0.25token1;0.0001token2).
MinGasPrices string `mapstructure:"minimum-gas-prices"`

// HaltHeight contains a non-zero height at which a node will gracefully halt
// and shutdown that can be used to assist upgrades and testing.
HaltHeight uint64 `mapstructure:"halt-height"`
}

// Config defines the server's top level configuration
Expand Down Expand Up @@ -56,6 +60,7 @@ func DefaultConfig() *Config {
return &Config{
BaseConfig{
MinGasPrices: defaultMinGasPrices,
HaltHeight: 0,
},
}
}
4 changes: 4 additions & 0 deletions server/config/toml.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ const defaultConfigTemplate = `# This is a TOML config file.
# transaction. A transaction's fees must meet the minimum of any denomination
# specified in this config (e.g. 0.25token1;0.0001token2).
minimum-gas-prices = "{{ .BaseConfig.MinGasPrices }}"
# HaltHeight contains a non-zero height at which a node will gracefully halt
# and shutdown that can be used to assist upgrades and testing.
halt-height = {{ .BaseConfig.HaltHeight }}
`

var configTemplate *template.Template
Expand Down
2 changes: 2 additions & 0 deletions server/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const (
flagTraceStore = "trace-store"
flagPruning = "pruning"
FlagMinGasPrices = "minimum-gas-prices"
FlagHaltHeight = "halt-height"
)

// StartCmd runs the service passed in, either stand-alone or in-process with
Expand Down Expand Up @@ -53,6 +54,7 @@ func StartCmd(ctx *Context, appCreator AppCreator) *cobra.Command {
FlagMinGasPrices, "",
"Minimum gas prices to accept for transactions; Any fee in a tx must meet this minimum (e.g. 0.01photino;0.0001stake)",
)
cmd.Flags().Uint64(FlagHaltHeight, 0, "Height at which to gracefully halt the chain and shutdown the node")

// add support for all Tendermint-specific command line options
tcmd.AddNodeFlags(cmd)
Expand Down
5 changes: 4 additions & 1 deletion server/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,10 @@ func interceptLoadConfig() (conf *cfg.Config, err error) {
conf, err = tcmd.ParseConfig() // NOTE: ParseConfig() creates dir/files as necessary.
}

// create a default gaia config file if it does not exist
// create a default Gaia config file if it does not exist
//
// TODO: Rename config file to server.toml as it's not particular to Gaia
// (REF: https://github.com/cosmos/cosmos-sdk/issues/4125).
gaiaConfigFilePath := filepath.Join(rootDir, "config/gaiad.toml")
if _, err := os.Stat(gaiaConfigFilePath); os.IsNotExist(err) {
gaiaConf, _ := config.ParseConfig()
Expand Down

0 comments on commit c6cb84c

Please sign in to comment.