Skip to content

Commit

Permalink
Use validator protection datadir (#7355)
Browse files Browse the repository at this point in the history
* Add validator protection db flag

* fix nil handling

* reuse datadir

* add datadir default config

* Add handling for moving account dir datafile to new set dir

* naming conditionals

* add tests

* fix test

* fix logic to default to wallet dir

* raul feedback

* nishant feedback

* gaz

* revert site_data changes

* fix formatting

* fix formatting

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
Co-authored-by: Nishant Das <nishdas93@gmail.com>
Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
  • Loading branch information
4 people authored Oct 22, 2020
1 parent e7723c4 commit ab76bda
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 23 deletions.
13 changes: 13 additions & 0 deletions validator/accounts/prompt/prompt.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,19 @@ func InputDirectory(cliCtx *cli.Context, promptText string, flag *cli.StringFlag
return fileutil.ExpandPath(inputtedDir)
}

// InputDir from the cli without exception.
func InputDir(cliCtx *cli.Context, promptText string, dirFlag *cli.StringFlag) (string, error) {
directory := cliCtx.String(dirFlag.Name)
inputtedDir, err := promptutil.DefaultPrompt(au.Bold(promptText).String(), directory)
if err != nil {
return "", err
}
if inputtedDir == directory {
return directory, nil
}
return fileutil.ExpandPath(inputtedDir)
}

// InputRemoteKeymanagerConfig via the cli.
func InputRemoteKeymanagerConfig(cliCtx *cli.Context) (*remote.KeymanagerOpts, error) {
addr := cliCtx.String(flags.GrpcRemoteAddressFlag.Name)
Expand Down
5 changes: 5 additions & 0 deletions validator/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,11 @@ var (
Usage: "Enables the web portal for the validator client (work in progress)",
Value: false,
}
// AllowEmptyProtectionDB allow new protection db to be created without prompting the user.
AllowEmptyProtectionDB = &cli.BoolFlag{
Name: "allow-new-protection-db",
Usage: "Use this flag allow new protection db to be created non-interactively",
}
)

// DefaultValidatorDir returns OS-specific default validator directory.
Expand Down
1 change: 1 addition & 0 deletions validator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ var appFlags = []cli.Flag{
flags.WalletPasswordFileFlag,
flags.WalletDirFlag,
flags.EnableWebFlag,
flags.AllowEmptyProtectionDB,
cmd.MinimalConfigFlag,
cmd.E2EConfigFlag,
cmd.VerbosityFlag,
Expand Down
4 changes: 4 additions & 0 deletions validator/node/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ go_test(
srcs = ["node_test.go"],
embed = [":go_default_library"],
deps = [
"//shared/params:go_default_library",
"//shared/testutil:go_default_library",
"//shared/testutil/assert:go_default_library",
"//shared/testutil/require:go_default_library",
"//validator/accounts:go_default_library",
"//validator/accounts/wallet:go_default_library",
"//validator/db/kv:go_default_library",
"//validator/flags:go_default_library",
"//validator/keymanager:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
Expand All @@ -36,6 +38,7 @@ go_library(
"//shared/prometheus:go_default_library",
"//shared/tracing:go_default_library",
"//shared/version:go_default_library",
"//validator/accounts/prompt:go_default_library",
"//validator/accounts/wallet:go_default_library",
"//validator/client:go_default_library",
"//validator/db/kv:go_default_library",
Expand All @@ -45,6 +48,7 @@ go_library(
"//validator/rpc:go_default_library",
"//validator/rpc/gateway:go_default_library",
"//validator/slashing-protection:go_default_library",
"@com_github_logrusorgru_aurora//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_urfave_cli_v2//:go_default_library",
Expand Down
76 changes: 53 additions & 23 deletions validator/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"sync"
"syscall"

"github.com/logrusorgru/aurora"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/shared"
"github.com/prysmaticlabs/prysm/shared/cmd"
Expand All @@ -24,6 +25,7 @@ import (
"github.com/prysmaticlabs/prysm/shared/prometheus"
"github.com/prysmaticlabs/prysm/shared/tracing"
"github.com/prysmaticlabs/prysm/shared/version"
"github.com/prysmaticlabs/prysm/validator/accounts/prompt"
"github.com/prysmaticlabs/prysm/validator/accounts/wallet"
"github.com/prysmaticlabs/prysm/validator/client"
"github.com/prysmaticlabs/prysm/validator/db/kv"
Expand All @@ -38,6 +40,17 @@ import (
)

var log = logrus.WithField("prefix", "node")
var au = aurora.NewAurora(true)
var calmFirstTimeUsers = "If this is the first time you are using these keys " +
"disregard this warning and hit the Enter key.\n"
var warning = "Warning!!! protection db is the main method to prevent slashing. " +
"If it is not the first time you are running the validator with the current " +
"keys please locate the db file!!!\n"
var defaultWarning = "hitting return will start an empty db file"
var specifyProtectionDBPath = fmt.Sprintf(
"\n\n%s%sdb file name is %s please locate the latest version of it "+
"and paste the path here (%s)", au.BrightCyan(calmFirstTimeUsers), au.BrightMagenta(warning),
au.BrightMagenta(kv.ProtectionDbFileName), au.Red(defaultWarning))

// ValidatorClient defines an instance of an eth2 validator that manages
// the entire lifecycle of services attached to it participating in eth2.
Expand Down Expand Up @@ -159,7 +172,6 @@ func (s *ValidatorClient) Close() {
func (s *ValidatorClient) initializeFromCLI(cliCtx *cli.Context) error {
var keyManager keymanager.IKeymanager
var err error
var accountsDir string
if cliCtx.IsSet(flags.InteropNumValidators.Name) {
numValidatorKeys := cliCtx.Uint64(flags.InteropNumValidators.Name)
offset := cliCtx.Uint64(flags.InteropStartIndex.Name)
Expand Down Expand Up @@ -189,15 +201,19 @@ func (s *ValidatorClient) initializeFromCLI(cliCtx *cli.Context) error {
if err := w.LockWalletConfigFile(cliCtx.Context); err != nil {
log.Fatalf("Could not get a lock on wallet file. Please check if you have another validator instance running and using the same wallet: %v", err)
}
accountsDir = s.wallet.AccountsDir()
}

dataDir := moveDb(cliCtx, accountsDir)
dataFlag := flags.WalletDirFlag
if cliCtx.String(cmd.DataDirFlag.Name) != cmd.DefaultDataDir() {
dataFlag = cmd.DataDirFlag
}
dataDir := cliCtx.String(dataFlag.Name)
moveSlashingProtectionDatabase(cliCtx, dataFlag)
clearFlag := cliCtx.Bool(cmd.ClearDB.Name)
forceClearFlag := cliCtx.Bool(cmd.ForceClearDB.Name)
if clearFlag || forceClearFlag {
if dataDir == "" {
dataDir = cmd.DefaultDataDir()
if dataDir == "" && s.wallet != nil {
dataDir = s.wallet.AccountsDir()
if dataDir == "" {
log.Fatal(
"Could not determine your system's HOME path, please specify a --datadir you wish " +
Expand Down Expand Up @@ -241,24 +257,33 @@ func (s *ValidatorClient) initializeFromCLI(cliCtx *cli.Context) error {
return nil
}

func moveDb(cliCtx *cli.Context, accountsDir string) string {
dataDir := cliCtx.String(cmd.DataDirFlag.Name)
if accountsDir != "" {
dataFile := filepath.Join(dataDir, kv.ProtectionDbFileName)
newDataFile := filepath.Join(accountsDir, kv.ProtectionDbFileName)
if fileutil.FileExists(dataFile) && !fileutil.FileExists(newDataFile) {
log.WithFields(logrus.Fields{
"oldDbPath": dataDir,
"walletDir": accountsDir,
}).Info("Moving validator protection db to wallet dir")
err := fileutil.CopyFile(dataFile, newDataFile)
if err != nil {
log.Fatal(err)
}
func moveSlashingProtectionDatabase(cliCtx *cli.Context, defaultDir *cli.StringFlag) {
dataDir := cliCtx.String(defaultDir.Name)
dataFile := filepath.Join(dataDir, kv.ProtectionDbFileName)
clearFlag := cliCtx.Bool(cmd.ClearDB.Name)
forceClearFlag := cliCtx.Bool(cmd.ForceClearDB.Name)
if clearFlag || forceClearFlag || cliCtx.Bool(flags.AllowEmptyProtectionDB.Name) {
return
}
if !fileutil.FileExists(dataFile) {
// Input the directory where the old protection db resides.
protectionDbPath, err := prompt.InputDir(cliCtx, specifyProtectionDBPath, defaultDir)
if err != nil {
log.WithError(err).Fatal("could not parse protection db directory")
}
if protectionDbPath == dataDir {
return
}
oldDataFile := filepath.Join(protectionDbPath, kv.ProtectionDbFileName)
log.WithFields(logrus.Fields{
"oldDbPath": oldDataFile,
"validatorDbDir": dataFile,
}).Info("Moving validator protection db")
err = fileutil.CopyFile(oldDataFile, dataFile)
if err != nil {
log.WithError(err).Fatal("could not copy old db file")
}
dataDir = accountsDir
}
return dataDir
}

func (s *ValidatorClient) initializeForWeb(cliCtx *cli.Context) error {
Expand Down Expand Up @@ -287,10 +312,15 @@ func (s *ValidatorClient) initializeForWeb(cliCtx *cli.Context) error {
log.Fatalf("Could not get a lock on wallet file. Please check if you have another validator instance running and using the same wallet: %v", err)
}
}

dataFlag := flags.WalletDirFlag
if cliCtx.String(cmd.DataDirFlag.Name) != cmd.DefaultDataDir() {
dataFlag = cmd.DataDirFlag
}
dataDir := cliCtx.String(dataFlag.Name)
moveSlashingProtectionDatabase(cliCtx, dataFlag)
clearFlag := cliCtx.Bool(cmd.ClearDB.Name)
forceClearFlag := cliCtx.Bool(cmd.ForceClearDB.Name)
dataDir := cliCtx.String(cmd.DataDirFlag.Name)

if clearFlag || forceClearFlag {
if dataDir == "" {
dataDir = cmd.DefaultDataDir()
Expand Down
80 changes: 80 additions & 0 deletions validator/node/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import (
"path/filepath"
"testing"

"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/testutil"
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
"github.com/prysmaticlabs/prysm/shared/testutil/require"
"github.com/prysmaticlabs/prysm/validator/accounts"
"github.com/prysmaticlabs/prysm/validator/accounts/wallet"
"github.com/prysmaticlabs/prysm/validator/db/kv"
"github.com/prysmaticlabs/prysm/validator/flags"
"github.com/prysmaticlabs/prysm/validator/keymanager"
logTest "github.com/sirupsen/logrus/hooks/test"
Expand All @@ -26,6 +28,7 @@ func TestNode_Builds(t *testing.T) {
app := cli.App{}
set := flag.NewFlagSet("test", 0)
set.String("datadir", testutil.TempDir()+"/datadir", "the node data directory")
set.Bool("allow-new-protection-db", true, "dont prompt")
dir := testutil.TempDir() + "/walletpath"
passwordDir := testutil.TempDir() + "/password"
require.NoError(t, os.MkdirAll(passwordDir, os.ModePerm))
Expand Down Expand Up @@ -73,3 +76,80 @@ func TestClearDB(t *testing.T) {
require.NoError(t, err)
require.LogsContain(t, hook, "Removing database")
}

func Test_moveSlashingProtectionDatabase_doesntPromptWithFlag(t *testing.T) {
hook := logTest.NewGlobal()
app := cli.App{}
set := flag.NewFlagSet("test", 0)
dataDir := testutil.TempDir() + "/datadir"
set.String("datadir", dataDir, "the node data directory")
set.Bool("allow-new-protection-db", true, "dont prompt")
context := cli.NewContext(&app, set, nil)
// dont prompt when non interactive flag is on.
moveSlashingProtectionDatabase(context, flags.WalletDirFlag)
require.LogsDoNotContain(t, hook, "protection db is empty.")
require.LogsDoNotContain(t, hook, "Moving validator protection db")
}

func Test_moveSlashingProtectionDatabaseDefaultValue(t *testing.T) {
tmpfile, err := ioutil.TempFile("", "content")
require.NoError(t, err)
defer func() {
err := os.Remove(tmpfile.Name())
require.NoError(t, err)
}()

_, err = tmpfile.Write([]byte("\n"))
require.NoError(t, err)

_, err = tmpfile.Seek(0, 0)
require.NoError(t, err)
oldStdin := os.Stdin
defer func() { os.Stdin = oldStdin }() // Restore original Stdin
os.Stdin = tmpfile

hook := logTest.NewGlobal()
app := cli.App{}
set := flag.NewFlagSet("test", 0)

// prompt when flag is not present and db is new.
context := cli.NewContext(&app, set, nil)
moveSlashingProtectionDatabase(context, flags.WalletDirFlag)
require.LogsDoNotContain(t, hook, "Moving validator protection db")
}

func Test_moveSlashingProtectionDatabaseToNewLocation(t *testing.T) {
tmpDBDir, err := ioutil.TempDir("", "dbdir")
require.NoError(t, err)
tmpfile, err := ioutil.TempFile("", "content")
require.NoError(t, err)
tmpDbFile := filepath.Join(tmpDBDir, kv.ProtectionDbFileName)
err = ioutil.WriteFile(tmpDbFile, []byte("test data"), params.BeaconIoConfig().ReadWritePermissions)
require.NoError(t, err)
defer func() {
err := os.Remove(tmpfile.Name())
require.NoError(t, err)
err = os.Remove(tmpDbFile)
require.NoError(t, err)
err = os.Remove(tmpDBDir)
require.NoError(t, err)
}()
_, err = tmpfile.Write([]byte(tmpDBDir))
require.NoError(t, err)

_, err = tmpfile.Seek(0, 0)
require.NoError(t, err)
oldStdin := os.Stdin
defer func() { os.Stdin = oldStdin }() // Restore original Stdin
os.Stdin = tmpfile

hook := logTest.NewGlobal()
app := cli.App{}
set := flag.NewFlagSet("test", 0)
set.String("datadir", testutil.TempDir(), "the node data directory")

// prompt when flag is not present and db is new.
context := cli.NewContext(&app, set, nil)
moveSlashingProtectionDatabase(context, flags.WalletDirFlag)
require.LogsContain(t, hook, "Moving validator protection db")
}
1 change: 1 addition & 0 deletions validator/usage.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ var appHelpFlagGroups = []flagGroup{
flags.BeaconRPCGatewayProviderFlag,
flags.CertFlag,
flags.EnableWebFlag,
flags.AllowEmptyProtectionDB,
flags.DisablePenaltyRewardLogFlag,
flags.GraffitiFlag,
flags.EnableRPCFlag,
Expand Down

0 comments on commit ab76bda

Please sign in to comment.