mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-05 04:55:18 +00:00
cli: simplify resetting commands (#8312)
This commit is contained in:
@@ -19,7 +19,7 @@ Special thanks to external contributors on this release:
|
||||
- [rpc] \#7713 Remove unused options for websocket clients. (@creachadair)
|
||||
- [config] \#7930 Add new event subscription options and defaults. (@creachadair)
|
||||
- [rpc] \#7982 Add new Events interface and deprecate Subscribe. (@creachadair)
|
||||
- [cli] \#8081 make the reset command safe to use. (@marbar3778)
|
||||
- [cli] \#8081 make the reset command safe to use by intoducing `reset-state` command. Fixed by \#8259. (@marbar3778, @cmwaters)
|
||||
- [config] \#8222 default indexer configuration to null. (@creachadair)
|
||||
|
||||
- Apps
|
||||
|
||||
19
UPGRADING.md
19
UPGRADING.md
@@ -126,6 +126,25 @@ lays out the reasoning for the changes as well as [RFC
|
||||
009](https://tinyurl.com/rfc009) for a discussion of the complexities of
|
||||
upgrading consensus parameters.
|
||||
|
||||
### CLI Changes
|
||||
|
||||
The functionality around resetting a node has been extended to make it safer. The
|
||||
`unsafe-reset-all` command has been replaced by a `reset` command with four
|
||||
subcommands: `blockchain`, `peers`, `unsafe-signer` and `unsafe-all`.
|
||||
|
||||
- `tendermint reset blockchain`: Clears a node of all blocks, consensus state, evidence,
|
||||
and indexed transactions. NOTE: This command does not reset application state.
|
||||
If you need to rollback the last application state (to recover from application
|
||||
nondeterminism), see instead the `tendermint rollback` command.
|
||||
- `tendermint reset peers`: Clears the peer store, which persists information on peers used
|
||||
by the networking layer. This can be used to get rid of stale addresses or to switch
|
||||
to a predefined set of static peers.
|
||||
- `tendermint reset unsafe-signer`: Resets the watermark level of the PrivVal File signer
|
||||
allowing it to sign votes from the genesis height. This should only be used in testing as
|
||||
it can lead to the node double signing.
|
||||
- `tendermint reset unsafe-all`: A summation of the other three commands. This will delete
|
||||
the entire `data` directory which may include application data as well.
|
||||
|
||||
## v0.35
|
||||
|
||||
### ABCI Changes
|
||||
|
||||
@@ -13,81 +13,92 @@ import (
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
// MakeResetAllCommand constructs a command that removes the database of
|
||||
// MakeResetCommand constructs a command that removes the database of
|
||||
// the specified Tendermint core instance.
|
||||
func MakeResetAllCommand(conf *config.Config, logger log.Logger) *cobra.Command {
|
||||
func MakeResetCommand(conf *config.Config, logger log.Logger) *cobra.Command {
|
||||
var keyType string
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "unsafe-reset-all",
|
||||
Short: "(unsafe) Remove all the data and WAL, reset this node's validator to genesis state",
|
||||
resetCmd := &cobra.Command{
|
||||
Use: "reset",
|
||||
Short: "Set of commands to conveniently reset tendermint related data",
|
||||
}
|
||||
|
||||
resetBlocksCmd := &cobra.Command{
|
||||
Use: "blockchain",
|
||||
Short: "Removes all blocks, state, transactions and evidence stored by the tendermint node",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return resetAll(conf.DBDir(), conf.PrivValidator.KeyFile(),
|
||||
return ResetState(conf.DBDir(), logger)
|
||||
},
|
||||
}
|
||||
|
||||
resetPeersCmd := &cobra.Command{
|
||||
Use: "peers",
|
||||
Short: "Removes all peer addresses",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return ResetPeerStore(conf.DBDir())
|
||||
},
|
||||
}
|
||||
|
||||
resetSignerCmd := &cobra.Command{
|
||||
Use: "unsafe-signer",
|
||||
Short: "esets private validator signer state",
|
||||
Long: `Resets private validator signer state.
|
||||
Only use in testing. This can cause the node to double sign`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return ResetFilePV(conf.PrivValidator.KeyFile(), conf.PrivValidator.StateFile(), logger, keyType)
|
||||
},
|
||||
}
|
||||
|
||||
resetAllCmd := &cobra.Command{
|
||||
Use: "unsafe-all",
|
||||
Short: "Removes all tendermint data including signing state",
|
||||
Long: `Removes all tendermint data including signing state.
|
||||
Only use in testing. This can cause the node to double sign`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return ResetAll(conf.DBDir(), conf.PrivValidator.KeyFile(),
|
||||
conf.PrivValidator.StateFile(), logger, keyType)
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringVar(&keyType, "key", types.ABCIPubKeyTypeEd25519,
|
||||
"Key type to generate privval file with. Options: ed25519, secp256k1")
|
||||
|
||||
return cmd
|
||||
resetSignerCmd.Flags().StringVar(&keyType, "key", types.ABCIPubKeyTypeEd25519,
|
||||
"Signer key type. Options: ed25519, secp256k1")
|
||||
|
||||
resetAllCmd.Flags().StringVar(&keyType, "key", types.ABCIPubKeyTypeEd25519,
|
||||
"Signer key type. Options: ed25519, secp256k1")
|
||||
|
||||
resetCmd.AddCommand(resetBlocksCmd)
|
||||
resetCmd.AddCommand(resetPeersCmd)
|
||||
resetCmd.AddCommand(resetSignerCmd)
|
||||
resetCmd.AddCommand(resetAllCmd)
|
||||
|
||||
return resetCmd
|
||||
}
|
||||
|
||||
// MakeResetStateCommand constructs a command that removes the database of
|
||||
// the specified Tendermint core instance.
|
||||
func MakeResetStateCommand(conf *config.Config, logger log.Logger) *cobra.Command {
|
||||
var keyType string
|
||||
|
||||
return &cobra.Command{
|
||||
Use: "reset-state",
|
||||
Short: "Remove all the data and WAL",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return resetState(conf.DBDir(), logger, keyType)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func MakeResetPrivateValidatorCommand(conf *config.Config, logger log.Logger) *cobra.Command {
|
||||
var keyType string
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "unsafe-reset-priv-validator",
|
||||
Short: "(unsafe) Reset this node's validator to genesis state",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return resetFilePV(conf.PrivValidator.KeyFile(), conf.PrivValidator.StateFile(), logger, keyType)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVar(&keyType, "key", types.ABCIPubKeyTypeEd25519,
|
||||
"Key type to generate privval file with. Options: ed25519, secp256k1")
|
||||
return cmd
|
||||
|
||||
}
|
||||
|
||||
// XXX: this is totally unsafe.
|
||||
// it's only suitable for testnets.
|
||||
|
||||
// XXX: this is totally unsafe.
|
||||
// it's only suitable for testnets.
|
||||
|
||||
// resetAll removes address book files plus all data, and resets the privValdiator data.
|
||||
func resetAll(dbDir, privValKeyFile, privValStateFile string, logger log.Logger, keyType string) error {
|
||||
// ResetAll removes address book files plus all data, and resets the privValdiator data.
|
||||
// Exported for extenal CLI usage
|
||||
// XXX: this is unsafe and should only suitable for testnets.
|
||||
func ResetAll(dbDir, privValKeyFile, privValStateFile string, logger log.Logger, keyType string) error {
|
||||
if err := os.RemoveAll(dbDir); err == nil {
|
||||
logger.Info("Removed all blockchain history", "dir", dbDir)
|
||||
} else {
|
||||
logger.Error("error removing all blockchain history", "dir", dbDir, "err", err)
|
||||
}
|
||||
|
||||
return resetFilePV(privValKeyFile, privValStateFile, logger, keyType)
|
||||
if err := tmos.EnsureDir(dbDir, 0700); err != nil {
|
||||
logger.Error("unable to recreate dbDir", "err", err)
|
||||
}
|
||||
|
||||
// recreate the dbDir since the privVal state needs to live there
|
||||
return ResetFilePV(privValKeyFile, privValStateFile, logger, keyType)
|
||||
}
|
||||
|
||||
// resetState removes address book files plus all databases.
|
||||
func resetState(dbDir string, logger log.Logger, keyType string) error {
|
||||
// ResetState removes all blocks, tendermint state, indexed transactions and evidence.
|
||||
func ResetState(dbDir string, logger log.Logger) error {
|
||||
blockdb := filepath.Join(dbDir, "blockstore.db")
|
||||
state := filepath.Join(dbDir, "state.db")
|
||||
wal := filepath.Join(dbDir, "cs.wal")
|
||||
evidence := filepath.Join(dbDir, "evidence.db")
|
||||
txIndex := filepath.Join(dbDir, "tx_index.db")
|
||||
peerstore := filepath.Join(dbDir, "peerstore.db")
|
||||
|
||||
if tmos.FileExists(blockdb) {
|
||||
if err := os.RemoveAll(blockdb); err == nil {
|
||||
@@ -129,20 +140,13 @@ func resetState(dbDir string, logger log.Logger, keyType string) error {
|
||||
}
|
||||
}
|
||||
|
||||
if tmos.FileExists(peerstore) {
|
||||
if err := os.RemoveAll(peerstore); err == nil {
|
||||
logger.Info("Removed peerstore.db", "dir", peerstore)
|
||||
} else {
|
||||
logger.Error("error removing peerstore.db", "dir", peerstore, "err", err)
|
||||
}
|
||||
}
|
||||
if err := tmos.EnsureDir(dbDir, 0700); err != nil {
|
||||
logger.Error("unable to recreate dbDir", "err", err)
|
||||
}
|
||||
return nil
|
||||
return tmos.EnsureDir(dbDir, 0700)
|
||||
}
|
||||
|
||||
func resetFilePV(privValKeyFile, privValStateFile string, logger log.Logger, keyType string) error {
|
||||
// ResetFilePV loads the file private validator and resets the watermark to 0. If used on an existing network,
|
||||
// this can cause the node to double sign.
|
||||
// XXX: this is unsafe and should only suitable for testnets.
|
||||
func ResetFilePV(privValKeyFile, privValStateFile string, logger log.Logger, keyType string) error {
|
||||
if _, err := os.Stat(privValKeyFile); err == nil {
|
||||
pv, err := privval.LoadFilePVEmptyState(privValKeyFile, privValStateFile)
|
||||
if err != nil {
|
||||
@@ -166,3 +170,13 @@ func resetFilePV(privValKeyFile, privValStateFile string, logger log.Logger, key
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResetPeerStore removes the peer store containing all information used by the tendermint networking layer
|
||||
// In the case of a reset, new peers will need to be set either via the config or through the discovery mechanism
|
||||
func ResetPeerStore(dbDir string) error {
|
||||
peerstore := filepath.Join(dbDir, "peerstore.db")
|
||||
if tmos.FileExists(peerstore) {
|
||||
return os.RemoveAll(peerstore)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
62
cmd/tendermint/commands/reset_test.go
Normal file
62
cmd/tendermint/commands/reset_test.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
"github.com/tendermint/tendermint/privval"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
func Test_ResetAll(t *testing.T) {
|
||||
config := cfg.TestConfig()
|
||||
dir := t.TempDir()
|
||||
config.SetRoot(dir)
|
||||
logger := log.NewNopLogger()
|
||||
cfg.EnsureRoot(dir)
|
||||
require.NoError(t, initFilesWithConfig(context.Background(), config, logger, types.ABCIPubKeyTypeEd25519))
|
||||
pv, err := privval.LoadFilePV(config.PrivValidator.KeyFile(), config.PrivValidator.StateFile())
|
||||
require.NoError(t, err)
|
||||
pv.LastSignState.Height = 10
|
||||
require.NoError(t, pv.Save())
|
||||
require.NoError(t, ResetAll(config.DBDir(), config.PrivValidator.KeyFile(),
|
||||
config.PrivValidator.StateFile(), logger, types.ABCIPubKeyTypeEd25519))
|
||||
require.DirExists(t, config.DBDir())
|
||||
require.NoFileExists(t, filepath.Join(config.DBDir(), "block.db"))
|
||||
require.NoFileExists(t, filepath.Join(config.DBDir(), "state.db"))
|
||||
require.NoFileExists(t, filepath.Join(config.DBDir(), "evidence.db"))
|
||||
require.NoFileExists(t, filepath.Join(config.DBDir(), "tx_index.db"))
|
||||
require.FileExists(t, config.PrivValidator.StateFile())
|
||||
pv, err = privval.LoadFilePV(config.PrivValidator.KeyFile(), config.PrivValidator.StateFile())
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, int64(0), pv.LastSignState.Height)
|
||||
}
|
||||
|
||||
func Test_ResetState(t *testing.T) {
|
||||
config := cfg.TestConfig()
|
||||
dir := t.TempDir()
|
||||
config.SetRoot(dir)
|
||||
logger := log.NewNopLogger()
|
||||
cfg.EnsureRoot(dir)
|
||||
require.NoError(t, initFilesWithConfig(context.Background(), config, logger, types.ABCIPubKeyTypeEd25519))
|
||||
pv, err := privval.LoadFilePV(config.PrivValidator.KeyFile(), config.PrivValidator.StateFile())
|
||||
require.NoError(t, err)
|
||||
pv.LastSignState.Height = 10
|
||||
require.NoError(t, pv.Save())
|
||||
require.NoError(t, ResetState(config.DBDir(), logger))
|
||||
require.DirExists(t, config.DBDir())
|
||||
require.NoFileExists(t, filepath.Join(config.DBDir(), "block.db"))
|
||||
require.NoFileExists(t, filepath.Join(config.DBDir(), "state.db"))
|
||||
require.NoFileExists(t, filepath.Join(config.DBDir(), "evidence.db"))
|
||||
require.NoFileExists(t, filepath.Join(config.DBDir(), "tx_index.db"))
|
||||
require.FileExists(t, config.PrivValidator.StateFile())
|
||||
pv, err = privval.LoadFilePV(config.PrivValidator.KeyFile(), config.PrivValidator.StateFile())
|
||||
require.NoError(t, err)
|
||||
// private validator state should still be in tact.
|
||||
require.Equal(t, int64(10), pv.LastSignState.Height)
|
||||
}
|
||||
@@ -33,9 +33,7 @@ func main() {
|
||||
commands.MakeLightCommand(conf, logger),
|
||||
commands.MakeReplayCommand(conf, logger),
|
||||
commands.MakeReplayConsoleCommand(conf, logger),
|
||||
commands.MakeResetAllCommand(conf, logger),
|
||||
commands.MakeResetStateCommand(conf, logger),
|
||||
commands.MakeResetPrivateValidatorCommand(conf, logger),
|
||||
commands.MakeResetCommand(conf, logger),
|
||||
commands.MakeShowValidatorCommand(conf, logger),
|
||||
commands.MakeTestnetFilesCommand(conf, logger),
|
||||
commands.MakeShowNodeIDCommand(conf),
|
||||
|
||||
@@ -182,7 +182,7 @@ node example/counter.js
|
||||
In another window, reset and start `tendermint`:
|
||||
|
||||
```sh
|
||||
tendermint unsafe-reset-all
|
||||
tendermint reset unsafe-all
|
||||
tendermint start
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user