Browse Source

privval: return errors on loadFilePV (#6185)

## Description

- return errors on `loadFilePv`

closes #6182
pull/6191/head
Marko 4 years ago
committed by GitHub
parent
commit
e2384a00ce
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 65 additions and 32 deletions
  1. +1
    -0
      CHANGELOG_PENDING.md
  2. +5
    -1
      cmd/priv_val_server/main.go
  3. +5
    -1
      cmd/tendermint/commands/init.go
  4. +15
    -11
      cmd/tendermint/commands/reset_priv_validator.go
  5. +4
    -1
      cmd/tendermint/commands/show_validator.go
  6. +4
    -1
      cmd/tendermint/commands/testnet.go
  7. +6
    -3
      consensus/replay_test.go
  8. +9
    -9
      privval/file.go
  9. +2
    -1
      privval/file_test.go
  10. +5
    -2
      test/e2e/app/main.go
  11. +4
    -1
      tools/tm-signer-harness/internal/test_harness.go
  12. +5
    -1
      tools/tm-signer-harness/main.go

+ 1
- 0
CHANGELOG_PENDING.md View File

@ -72,6 +72,7 @@ Friendly reminder, we have a [bug bounty program](https://hackerone.com/tendermi
- [node] \#6059 Validate and complete genesis doc before saving to state store (@silasdavis) - [node] \#6059 Validate and complete genesis doc before saving to state store (@silasdavis)
- [state] \#6067 Batch save state data (@githubsands & @cmwaters) - [state] \#6067 Batch save state data (@githubsands & @cmwaters)
- [libs/log] \#6174 Include timestamp (`ts` field; `time.RFC3339Nano` format) in JSON logger output (@melekes) - [libs/log] \#6174 Include timestamp (`ts` field; `time.RFC3339Nano` format) in JSON logger output (@melekes)
- [privval/file] \#6185 Return error on `LoadFilePV`, `LoadFilePVEmptyState`. Allows for better programmatic control of Tendermint.
### BUG FIXES ### BUG FIXES


+ 5
- 1
cmd/priv_val_server/main.go View File

@ -64,7 +64,11 @@ func main() {
"rootCA", *rootCA, "rootCA", *rootCA,
) )
pv := privval.LoadFilePV(*privValKeyPath, *privValStatePath)
pv, err := privval.LoadFilePV(*privValKeyPath, *privValStatePath)
if err != nil {
fmt.Fprint(os.Stderr, err)
os.Exit(1)
}
opts := []grpc.ServerOption{} opts := []grpc.ServerOption{}
if !*insecure { if !*insecure {


+ 5
- 1
cmd/tendermint/commands/init.go View File

@ -43,7 +43,11 @@ func initFilesWithConfig(config *cfg.Config) error {
err error err error
) )
if tmos.FileExists(privValKeyFile) { if tmos.FileExists(privValKeyFile) {
pv = privval.LoadFilePV(privValKeyFile, privValStateFile)
pv, err = privval.LoadFilePV(privValKeyFile, privValStateFile)
if err != nil {
return err
}
logger.Info("Found private validator", "keyFile", privValKeyFile, logger.Info("Found private validator", "keyFile", privValKeyFile,
"stateFile", privValStateFile) "stateFile", privValStateFile)
} else { } else {


+ 15
- 11
cmd/tendermint/commands/reset_priv_validator.go View File

@ -17,7 +17,7 @@ var ResetAllCmd = &cobra.Command{
Use: "unsafe-reset-all", Use: "unsafe-reset-all",
Aliases: []string{"unsafe_reset_all"}, Aliases: []string{"unsafe_reset_all"},
Short: "(unsafe) Remove all the data and WAL, reset this node's validator to genesis state", Short: "(unsafe) Remove all the data and WAL, reset this node's validator to genesis state",
Run: resetAll,
RunE: resetAll,
PreRun: deprecateSnakeCase, PreRun: deprecateSnakeCase,
} }
@ -34,26 +34,26 @@ var ResetPrivValidatorCmd = &cobra.Command{
Use: "unsafe-reset-priv-validator", Use: "unsafe-reset-priv-validator",
Aliases: []string{"unsafe_reset_priv_validator"}, Aliases: []string{"unsafe_reset_priv_validator"},
Short: "(unsafe) Reset this node's validator to genesis state", Short: "(unsafe) Reset this node's validator to genesis state",
Run: resetPrivValidator,
RunE: resetPrivValidator,
PreRun: deprecateSnakeCase, PreRun: deprecateSnakeCase,
} }
// XXX: this is totally unsafe. // XXX: this is totally unsafe.
// it's only suitable for testnets. // it's only suitable for testnets.
func resetAll(cmd *cobra.Command, args []string) {
ResetAll(config.DBDir(), config.P2P.AddrBookFile(), config.PrivValidatorKeyFile(),
func resetAll(cmd *cobra.Command, args []string) error {
return ResetAll(config.DBDir(), config.P2P.AddrBookFile(), config.PrivValidatorKeyFile(),
config.PrivValidatorStateFile(), logger) config.PrivValidatorStateFile(), logger)
} }
// XXX: this is totally unsafe. // XXX: this is totally unsafe.
// it's only suitable for testnets. // it's only suitable for testnets.
func resetPrivValidator(cmd *cobra.Command, args []string) {
resetFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile(), logger)
func resetPrivValidator(cmd *cobra.Command, args []string) error {
return resetFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile(), logger)
} }
// ResetAll removes address book files plus all data, and resets the privValdiator data. // ResetAll removes address book files plus all data, and resets the privValdiator data.
// Exported so other CLI tools can use it. // Exported so other CLI tools can use it.
func ResetAll(dbDir, addrBookFile, privValKeyFile, privValStateFile string, logger log.Logger) {
func ResetAll(dbDir, addrBookFile, privValKeyFile, privValStateFile string, logger log.Logger) error {
if keepAddrBook { if keepAddrBook {
logger.Info("The address book remains intact") logger.Info("The address book remains intact")
} else { } else {
@ -68,24 +68,28 @@ func ResetAll(dbDir, addrBookFile, privValKeyFile, privValStateFile string, logg
if err := tmos.EnsureDir(dbDir, 0700); err != nil { if err := tmos.EnsureDir(dbDir, 0700); err != nil {
logger.Error("unable to recreate dbDir", "err", err) logger.Error("unable to recreate dbDir", "err", err)
} }
resetFilePV(privValKeyFile, privValStateFile, logger)
return resetFilePV(privValKeyFile, privValStateFile, logger)
} }
func resetFilePV(privValKeyFile, privValStateFile string, logger log.Logger) {
func resetFilePV(privValKeyFile, privValStateFile string, logger log.Logger) error {
if _, err := os.Stat(privValKeyFile); err == nil { if _, err := os.Stat(privValKeyFile); err == nil {
pv := privval.LoadFilePVEmptyState(privValKeyFile, privValStateFile)
pv, err := privval.LoadFilePVEmptyState(privValKeyFile, privValStateFile)
if err != nil {
return err
}
pv.Reset() pv.Reset()
logger.Info("Reset private validator file to genesis state", "keyFile", privValKeyFile, logger.Info("Reset private validator file to genesis state", "keyFile", privValKeyFile,
"stateFile", privValStateFile) "stateFile", privValStateFile)
} else { } else {
pv, err := privval.GenFilePV(privValKeyFile, privValStateFile, keyType) pv, err := privval.GenFilePV(privValKeyFile, privValStateFile, keyType)
if err != nil { if err != nil {
panic(err)
return err
} }
pv.Save() pv.Save()
logger.Info("Generated private validator file", "keyFile", privValKeyFile, logger.Info("Generated private validator file", "keyFile", privValKeyFile,
"stateFile", privValStateFile) "stateFile", privValStateFile)
} }
return nil
} }
func removeAddrBook(addrBookFile string, logger log.Logger) { func removeAddrBook(addrBookFile string, logger log.Logger) {


+ 4
- 1
cmd/tendermint/commands/show_validator.go View File

@ -47,7 +47,10 @@ func showValidator(cmd *cobra.Command, args []string) error {
return fmt.Errorf("private validator file %s does not exist", keyFilePath) return fmt.Errorf("private validator file %s does not exist", keyFilePath)
} }
pv := privval.LoadFilePV(keyFilePath, config.PrivValidatorStateFile())
pv, err := privval.LoadFilePV(keyFilePath, config.PrivValidatorStateFile())
if err != nil {
return err
}
pubKey, err = pv.GetPubKey() pubKey, err = pv.GetPubKey()
if err != nil { if err != nil {


+ 4
- 1
cmd/tendermint/commands/testnet.go View File

@ -144,7 +144,10 @@ func testnetFiles(cmd *cobra.Command, args []string) error {
pvKeyFile := filepath.Join(nodeDir, config.BaseConfig.PrivValidatorKey) pvKeyFile := filepath.Join(nodeDir, config.BaseConfig.PrivValidatorKey)
pvStateFile := filepath.Join(nodeDir, config.BaseConfig.PrivValidatorState) pvStateFile := filepath.Join(nodeDir, config.BaseConfig.PrivValidatorState)
pv := privval.LoadFilePV(pvKeyFile, pvStateFile)
pv, err := privval.LoadFilePV(pvKeyFile, pvStateFile)
if err != nil {
return err
}
pubKey, err := pv.GetPubKey() pubKey, err := pv.GetPubKey()
if err != nil { if err != nil {


+ 6
- 3
consensus/replay_test.go View File

@ -672,7 +672,8 @@ func testHandshakeReplay(t *testing.T, config *cfg.Config, nBlocks int, mode uin
walFile := tempWALWithData(walBody) walFile := tempWALWithData(walBody)
config.Consensus.SetWalFile(walFile) config.Consensus.SetWalFile(walFile)
privVal := privval.LoadFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile())
privVal, err := privval.LoadFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile())
require.NoError(t, err)
wal, err := NewWAL(walFile) wal, err := NewWAL(walFile)
require.NoError(t, err) require.NoError(t, err)
@ -884,7 +885,8 @@ func TestHandshakePanicsIfAppReturnsWrongAppHash(t *testing.T) {
// - 0x03 // - 0x03
config := ResetConfig("handshake_test_") config := ResetConfig("handshake_test_")
t.Cleanup(func() { os.RemoveAll(config.RootDir) }) t.Cleanup(func() { os.RemoveAll(config.RootDir) })
privVal := privval.LoadFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile())
privVal, err := privval.LoadFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile())
require.NoError(t, err)
const appVersion = 0x0 const appVersion = 0x0
pubKey, err := privVal.GetPubKey() pubKey, err := privVal.GetPubKey()
require.NoError(t, err) require.NoError(t, err)
@ -1220,7 +1222,8 @@ func TestHandshakeUpdatesValidators(t *testing.T) {
config := ResetConfig("handshake_test_") config := ResetConfig("handshake_test_")
t.Cleanup(func() { _ = os.RemoveAll(config.RootDir) }) t.Cleanup(func() { _ = os.RemoveAll(config.RootDir) })
privVal := privval.LoadFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile())
privVal, err := privval.LoadFilePV(config.PrivValidatorKeyFile(), config.PrivValidatorStateFile())
require.NoError(t, err)
pubKey, err := privVal.GetPubKey() pubKey, err := privVal.GetPubKey()
require.NoError(t, err) require.NoError(t, err)
stateDB, state, store := stateAndStore(config, pubKey, 0x0) stateDB, state, store := stateAndStore(config, pubKey, 0x0)


+ 9
- 9
privval/file.go View File

@ -185,26 +185,26 @@ func GenFilePV(keyFilePath, stateFilePath, keyType string) (*FilePV, error) {
// LoadFilePV loads a FilePV from the filePaths. The FilePV handles double // LoadFilePV loads a FilePV from the filePaths. The FilePV handles double
// signing prevention by persisting data to the stateFilePath. If either file path // signing prevention by persisting data to the stateFilePath. If either file path
// does not exist, the program will exit. // does not exist, the program will exit.
func LoadFilePV(keyFilePath, stateFilePath string) *FilePV {
func LoadFilePV(keyFilePath, stateFilePath string) (*FilePV, error) {
return loadFilePV(keyFilePath, stateFilePath, true) return loadFilePV(keyFilePath, stateFilePath, true)
} }
// LoadFilePVEmptyState loads a FilePV from the given keyFilePath, with an empty LastSignState. // LoadFilePVEmptyState loads a FilePV from the given keyFilePath, with an empty LastSignState.
// If the keyFilePath does not exist, the program will exit. // If the keyFilePath does not exist, the program will exit.
func LoadFilePVEmptyState(keyFilePath, stateFilePath string) *FilePV {
func LoadFilePVEmptyState(keyFilePath, stateFilePath string) (*FilePV, error) {
return loadFilePV(keyFilePath, stateFilePath, false) return loadFilePV(keyFilePath, stateFilePath, false)
} }
// If loadState is true, we load from the stateFilePath. Otherwise, we use an empty LastSignState. // If loadState is true, we load from the stateFilePath. Otherwise, we use an empty LastSignState.
func loadFilePV(keyFilePath, stateFilePath string, loadState bool) *FilePV {
func loadFilePV(keyFilePath, stateFilePath string, loadState bool) (*FilePV, error) {
keyJSONBytes, err := ioutil.ReadFile(keyFilePath) keyJSONBytes, err := ioutil.ReadFile(keyFilePath)
if err != nil { if err != nil {
tmos.Exit(err.Error())
return nil, err
} }
pvKey := FilePVKey{} pvKey := FilePVKey{}
err = tmjson.Unmarshal(keyJSONBytes, &pvKey) err = tmjson.Unmarshal(keyJSONBytes, &pvKey)
if err != nil { if err != nil {
tmos.Exit(fmt.Sprintf("Error reading PrivValidator key from %v: %v\n", keyFilePath, err))
return nil, fmt.Errorf("error reading PrivValidator key from %v: %w", keyFilePath, err)
} }
// overwrite pubkey and address for convenience // overwrite pubkey and address for convenience
@ -217,11 +217,11 @@ func loadFilePV(keyFilePath, stateFilePath string, loadState bool) *FilePV {
if loadState { if loadState {
stateJSONBytes, err := ioutil.ReadFile(stateFilePath) stateJSONBytes, err := ioutil.ReadFile(stateFilePath)
if err != nil { if err != nil {
tmos.Exit(err.Error())
return nil, err
} }
err = tmjson.Unmarshal(stateJSONBytes, &pvState) err = tmjson.Unmarshal(stateJSONBytes, &pvState)
if err != nil { if err != nil {
tmos.Exit(fmt.Sprintf("Error reading PrivValidator state from %v: %v\n", stateFilePath, err))
return nil, fmt.Errorf("error reading PrivValidator state from %v: %w", stateFilePath, err)
} }
} }
@ -230,7 +230,7 @@ func loadFilePV(keyFilePath, stateFilePath string, loadState bool) *FilePV {
return &FilePV{ return &FilePV{
Key: pvKey, Key: pvKey,
LastSignState: pvState, LastSignState: pvState,
}
}, nil
} }
// LoadOrGenFilePV loads a FilePV from the given filePaths // LoadOrGenFilePV loads a FilePV from the given filePaths
@ -241,7 +241,7 @@ func LoadOrGenFilePV(keyFilePath, stateFilePath string) (*FilePV, error) {
err error err error
) )
if tmos.FileExists(keyFilePath) { if tmos.FileExists(keyFilePath) {
pv = LoadFilePV(keyFilePath, stateFilePath)
pv, err = LoadFilePV(keyFilePath, stateFilePath)
} else { } else {
pv, err = GenFilePV(keyFilePath, stateFilePath, "") pv, err = GenFilePV(keyFilePath, stateFilePath, "")
pv.Save() pv.Save()


+ 2
- 1
privval/file_test.go View File

@ -36,7 +36,8 @@ func TestGenLoadValidator(t *testing.T) {
privVal.Save() privVal.Save()
addr := privVal.GetAddress() addr := privVal.GetAddress()
privVal = LoadFilePV(tempKeyFile.Name(), tempStateFile.Name())
privVal, err = LoadFilePV(tempKeyFile.Name(), tempStateFile.Name())
assert.NoError(err)
assert.Equal(addr, privVal.GetAddress(), "expected privval addr to be the same") assert.Equal(addr, privVal.GetAddress(), "expected privval addr to be the same")
assert.Equal(height, privVal.LastSignState.Height, "expected privval.LastHeight to have been saved") assert.Equal(height, privVal.LastSignState.Height, "expected privval.LastHeight to have been saved")
} }


+ 5
- 2
test/e2e/app/main.go View File

@ -176,7 +176,10 @@ func startNode(cfg *Config) error {
// startSigner starts a signer server connecting to the given endpoint. // startSigner starts a signer server connecting to the given endpoint.
func startSigner(cfg *Config) error { func startSigner(cfg *Config) error {
filePV := privval.LoadFilePV(cfg.PrivValKey, cfg.PrivValState)
filePV, err := privval.LoadFilePV(cfg.PrivValKey, cfg.PrivValState)
if err != nil {
return err
}
protocol, address := tmnet.ProtocolAndAddress(cfg.PrivValServer) protocol, address := tmnet.ProtocolAndAddress(cfg.PrivValServer)
var dialFn privval.SocketDialer var dialFn privval.SocketDialer
@ -210,7 +213,7 @@ func startSigner(cfg *Config) error {
endpoint := privval.NewSignerDialerEndpoint(logger, dialFn, endpoint := privval.NewSignerDialerEndpoint(logger, dialFn,
privval.SignerDialerEndpointRetryWaitInterval(1*time.Second), privval.SignerDialerEndpointRetryWaitInterval(1*time.Second),
privval.SignerDialerEndpointConnRetries(100)) privval.SignerDialerEndpointConnRetries(100))
err := privval.NewSignerServer(endpoint, cfg.ChainID, filePV).Start()
err = privval.NewSignerServer(endpoint, cfg.ChainID, filePV).Start()
if err != nil { if err != nil {
return err return err
} }


+ 4
- 1
tools/tm-signer-harness/internal/test_harness.go View File

@ -94,7 +94,10 @@ func NewTestHarness(logger log.Logger, cfg TestHarnessConfig) (*TestHarness, err
logger.Info("Loading private validator configuration", "keyFile", keyFile, "stateFile", stateFile) logger.Info("Loading private validator configuration", "keyFile", keyFile, "stateFile", stateFile)
// NOTE: LoadFilePV ultimately calls os.Exit on failure. No error will be // NOTE: LoadFilePV ultimately calls os.Exit on failure. No error will be
// returned if this call fails. // returned if this call fails.
fpv := privval.LoadFilePV(keyFile, stateFile)
fpv, err := privval.LoadFilePV(keyFile, stateFile)
if err != nil {
return nil, err
}
genesisFile := ExpandPath(cfg.GenesisFile) genesisFile := ExpandPath(cfg.GenesisFile)
logger.Info("Loading chain ID from genesis file", "genesisFile", genesisFile) logger.Info("Loading chain ID from genesis file", "genesisFile", genesisFile)


+ 5
- 1
tools/tm-signer-harness/main.go View File

@ -134,7 +134,11 @@ func runTestHarness(acceptRetries int, bindAddr, tmhome string) {
func extractKey(tmhome, outputPath string) { func extractKey(tmhome, outputPath string) {
keyFile := filepath.Join(internal.ExpandPath(tmhome), "config", "priv_validator_key.json") keyFile := filepath.Join(internal.ExpandPath(tmhome), "config", "priv_validator_key.json")
stateFile := filepath.Join(internal.ExpandPath(tmhome), "data", "priv_validator_state.json") stateFile := filepath.Join(internal.ExpandPath(tmhome), "data", "priv_validator_state.json")
fpv := privval.LoadFilePV(keyFile, stateFile)
fpv, err := privval.LoadFilePV(keyFile, stateFile)
if err != nil {
logger.Error("Can't load file pv", "err", err)
os.Exit(1)
}
pkb := []byte(fpv.Key.PrivKey.(ed25519.PrivKey)) pkb := []byte(fpv.Key.PrivKey.(ed25519.PrivKey))
if err := ioutil.WriteFile(internal.ExpandPath(outputPath), pkb[:32], 0600); err != nil { if err := ioutil.WriteFile(internal.ExpandPath(outputPath), pkb[:32], 0600); err != nil {
logger.Info("Failed to write private key", "output", outputPath, "err", err) logger.Info("Failed to write private key", "output", outputPath, "err", err)


Loading…
Cancel
Save