Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add EIP-3076 Interchange JSON CLI command to validator #7880

Merged
merged 47 commits into from Dec 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
18e1d16
Import JSON CLI
0xKiwi Nov 19, 2020
a4a3c50
CLI impotr
0xKiwi Nov 20, 2020
4c6a80a
f
0xKiwi Nov 20, 2020
2954ecd
Begin adding new commands in slashing protection
0xKiwi Nov 20, 2020
7fc99a2
Move testing helpers to separate packae
0xKiwi Nov 20, 2020
0efb884
Merge branch 'master' into sp-helpers
0xKiwi Nov 20, 2020
801ad1e
Merge branch 'sp-helpers' of github.com:prysmaticlabs/prysm into cli-…
0xKiwi Nov 20, 2020
7c0c4a8
Add command for importing slashing protection JSONs
0xKiwi Nov 21, 2020
ebe060b
fix import cycle
rauljordan Nov 21, 2020
3f20e0d
fix test
rauljordan Nov 21, 2020
c8094f0
Merge branch 'master' of github.com:prysmaticlabs/prysm into cli-import
0xKiwi Nov 21, 2020
8e0473b
Undo cleaning changes
0xKiwi Nov 21, 2020
7cce70a
Improvements
0xKiwi Nov 21, 2020
8073ecc
Add better prompts
0xKiwi Nov 21, 2020
1b2be36
Merge branch 'master' into cli-import
0xKiwi Nov 22, 2020
d722e52
Fix prompt
0xKiwi Nov 22, 2020
8d63ae9
Merge branch 'cli-import' of github.com:prysmaticlabs/prysm into cli-…
0xKiwi Nov 22, 2020
b17a7df
Merge branch 'master' of github.com:prysmaticlabs/prysm into cli-import
0xKiwi Nov 22, 2020
e5cf8bb
Merge branch 'master' of github.com:prysmaticlabs/prysm into cli-import
0xKiwi Nov 26, 2020
65ea684
Fix
0xKiwi Nov 26, 2020
fe1ee0c
Fix
0xKiwi Nov 26, 2020
e18b846
Fix
0xKiwi Nov 26, 2020
b67184b
Merge branch 'master' of github.com:prysmaticlabs/prysm into cli-import
0xKiwi Nov 27, 2020
c4eb6d3
Fix conflict
0xKiwi Nov 28, 2020
2697094
Fix
0xKiwi Nov 28, 2020
094f5c5
Merge branch 'master' of github.com:prysmaticlabs/prysm into cli-import
0xKiwi Nov 28, 2020
0350c09
Merge branch 'feature/slashing-interchange' into cli-import
rauljordan Dec 4, 2020
d1f97b1
Merge branch 'feature/slashing-interchange' of github.com:prysmaticla…
0xKiwi Dec 5, 2020
e361a14
Fixes
0xKiwi Dec 5, 2020
d676456
Fixes
0xKiwi Dec 5, 2020
c83d5d4
Merge branch 'feature/slashing-interchange' of github.com:prysmaticla…
0xKiwi Dec 5, 2020
13da441
Fix exported func
0xKiwi Dec 5, 2020
dc1b255
test func
0xKiwi Dec 5, 2020
5079d0f
Fixes
0xKiwi Dec 5, 2020
574754f
fix test
0xKiwi Dec 5, 2020
8156421
simplify import and standardize with export
rauljordan Dec 7, 2020
9af20d5
add round trip test
rauljordan Dec 7, 2020
3a1ed1d
true integration test works
rauljordan Dec 7, 2020
830db55
fix up comments
rauljordan Dec 7, 2020
917501f
logrus
rauljordan Dec 7, 2020
5ec6a78
better error
rauljordan Dec 7, 2020
51baff1
fix build
rauljordan Dec 7, 2020
9e84af8
build fix
rauljordan Dec 7, 2020
ed1fee8
Merge branch 'feature/slashing-interchange' into cli-import
rauljordan Dec 7, 2020
dbf796a
Update validator/slashing-protection/cli_export.go
rauljordan Dec 8, 2020
9d11dcd
Update validator/slashing-protection/cli_import.go
rauljordan Dec 8, 2020
23de559
fmt
prestonvanloon Dec 8, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion shared/promptutil/prompt.go
Expand Up @@ -55,7 +55,7 @@ func DefaultPrompt(promptText, defaultValue string) (string, error) {
if defaultValue != "" {
fmt.Printf("%s %s:\n", promptText, fmt.Sprintf("(%s: %s)", au.BrightGreen("default"), defaultValue))
} else {
fmt.Printf("%s\n", promptText)
fmt.Printf("%s:\n", promptText)
}
scanner := bufio.NewScanner(os.Stdin)
if ok := scanner.Scan(); ok {
Expand Down
4 changes: 4 additions & 0 deletions validator/accounts/prompt/prompt.go
Expand Up @@ -19,6 +19,10 @@ import (
const (
// ImportKeysDirPromptText for the import keys cli function.
ImportKeysDirPromptText = "Enter the directory or filepath where your keystores to import are located"
// DataDirDirPromptText for the validator database directory.
DataDirDirPromptText = "Enter the directory of the validator database you would like to use"
// SlashingProtectionJSONPromptText for the EIP-3076 slashing protection JSON prompt.
SlashingProtectionJSONPromptText = "Enter the the filepath of your EIP-3076 Slashing Protection JSON from your previously used validator client"
// WalletDirPromptText for the wallet.
WalletDirPromptText = "Enter a wallet directory"
// SelectAccountsDeletePromptText --
Expand Down
5 changes: 5 additions & 0 deletions validator/flags/flags.go
Expand Up @@ -226,6 +226,11 @@ var (
Usage: "Path to a directory where accounts will be backed up into a zip file",
Value: DefaultValidatorDir(),
}
// SlashingProtectionJSONFileFlag is used to enter the file path of the slashing protection JSON.
SlashingProtectionJSONFileFlag = &cli.StringFlag{
Name: "slashing-protection-json-file",
Usage: "Path to an EIP-3076 compliant JSON file containing a user's slashing protection history",
}
// KeysDirFlag defines the path for a directory where keystores to be imported at stored.
KeysDirFlag = &cli.StringFlag{
Name: "keys-dir",
Expand Down
2 changes: 1 addition & 1 deletion validator/keymanager/imported/import.go
Expand Up @@ -88,7 +88,7 @@ func (dr *Keymanager) attemptDecryptKeystore(
doesNotDecrypt := err != nil && strings.Contains(err.Error(), "invalid checksum")
for doesNotDecrypt {
password, err = promptutil.PasswordPrompt(
"Password incorrect for keystore, input correct password", promptutil.NotEmpty,
fmt.Sprintf("Password incorrect for key 0x%s, input correct password", keystore.Pubkey), promptutil.NotEmpty,
)
if err != nil {
return nil, nil, "", fmt.Errorf("could not read keystore password: %w", err)
Expand Down
4 changes: 3 additions & 1 deletion validator/slashing-protection/BUILD.bazel
Expand Up @@ -5,6 +5,7 @@ go_library(
name = "go_default_library",
srcs = [
"cli_export.go",
"cli_import.go",
"cmd.go",
"external.go",
"protector.go",
Expand All @@ -19,6 +20,7 @@ go_library(
"//shared/fileutil:go_default_library",
"//shared/grpcutils:go_default_library",
"//shared/tos:go_default_library",
"//validator/accounts/prompt:go_default_library",
"//validator/db/kv:go_default_library",
"//validator/flags:go_default_library",
"//validator/slashing-protection/local/standard-protection-format:go_default_library",
Expand All @@ -41,7 +43,7 @@ go_library(
go_test(
name = "go_default_test",
srcs = [
"cli_export_test.go",
"cli_import_export_test.go",
"external_test.go",
],
embed = [":go_default_library"],
Expand Down
33 changes: 28 additions & 5 deletions validator/slashing-protection/cli_export.go
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/shared/cmd"
"github.com/prysmaticlabs/prysm/shared/fileutil"
"github.com/prysmaticlabs/prysm/validator/accounts/prompt"
"github.com/prysmaticlabs/prysm/validator/db/kv"
"github.com/prysmaticlabs/prysm/validator/flags"
export "github.com/prysmaticlabs/prysm/validator/slashing-protection/local/standard-protection-format"
Expand All @@ -23,21 +24,43 @@ const (
//
// Steps:
// 1. Parse a path to the validator's datadir from the CLI context.
// 2. Open the validator database file.
// 2. Open the validator database.
// 3. Call the function which actually exports the data from
// from the validator's db into an EIP standard slashing protection format
// 4. Format and save the JSON file to a user's specified output directory.
func ExportSlashingProtectionJSONCli(cliCtx *cli.Context) error {
datadir := cliCtx.String(cmd.DataDirFlag.Name)
validatorDB, err := kv.NewKVStore(datadir, nil)
var err error
dataDir := cliCtx.String(cmd.DataDirFlag.Name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made export interactive to match the changes to import from this PR

if !cliCtx.IsSet(cmd.DataDirFlag.Name) {
dataDir, err = prompt.InputDirectory(cliCtx, prompt.DataDirDirPromptText, cmd.DataDirFlag)
if err != nil {
return err
}
}
validatorDB, err := kv.NewKVStore(dataDir, nil)
if err != nil {
return errors.Wrapf(err, "could not open database at %s", datadir)
return errors.Wrapf(err, "could not access validator database at path %s", dataDir)
}
defer func() {
if err := validatorDB.Close(); err != nil {
log.WithError(err).Errorf("Could not close validator DB")
}
}()
eipJSON, err := export.ExportStandardProtectionJSON(cliCtx.Context, validatorDB)
if err != nil {
return errors.Wrap(err, "could not export slashing protection history")
}
outputDir := cliCtx.String(flags.SlashingProtectionExportDirFlag.Name)
outputDir, err := prompt.InputDirectory(
cliCtx,
"Enter your desired output directory for your slashing protection history",
flags.SlashingProtectionExportDirFlag,
)
if err != nil {
return errors.Wrap(err, "could not get slashing protection json file")
}
if outputDir == "" {
return errors.New("output directory not specified")
}
exists, err := fileutil.HasDir(outputDir)
if err != nil {
return errors.Wrapf(err, "could not check if output directory %s already exists", outputDir)
Expand Down
67 changes: 67 additions & 0 deletions validator/slashing-protection/cli_import.go
@@ -0,0 +1,67 @@
package slashingprotection

import (
"bytes"
"fmt"

"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/shared/cmd"
"github.com/prysmaticlabs/prysm/shared/fileutil"
"github.com/prysmaticlabs/prysm/validator/accounts/prompt"
"github.com/prysmaticlabs/prysm/validator/db/kv"
"github.com/prysmaticlabs/prysm/validator/flags"
slashingProtectionFormat "github.com/prysmaticlabs/prysm/validator/slashing-protection/local/standard-protection-format"
"github.com/urfave/cli/v2"
)

// ImportSlashingProtectionCLI reads an input slashing protection EIP-3076
// standard JSON file and attempts to insert its data into our validator DB.
//
// Steps:
// 1. Parse a path to the validator's datadir from the CLI context.
// 2. Open the validator database.
// 3. Read the JSON file from user input.
// 4. Call the function which actually imports the data from
// from the standard slashing protection JSON file into our database.
func ImportSlashingProtectionCLI(cliCtx *cli.Context) error {
var err error
dataDir := cliCtx.String(cmd.DataDirFlag.Name)
if !cliCtx.IsSet(cmd.DataDirFlag.Name) {
dataDir, err = prompt.InputDirectory(cliCtx, prompt.DataDirDirPromptText, cmd.DataDirFlag)
if err != nil {
return err
}
}
valDB, err := kv.NewKVStore(dataDir, make([][48]byte, 0))
if err != nil {
return errors.Wrapf(err, "could not access validator database at path: %s", dataDir)
}
defer func() {
if err := valDB.Close(); err != nil {
log.WithError(err).Errorf("Could not close validator DB")
}
}()
protectionFilePath, err := prompt.InputDirectory(cliCtx, prompt.SlashingProtectionJSONPromptText, flags.SlashingProtectionJSONFileFlag)
rauljordan marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return errors.Wrap(err, "could not get slashing protection json file")
}
if protectionFilePath == "" {
return fmt.Errorf(
"No path to a slashing_protection.json file specified, please retry. "+
"You can also specify it with the %s flag",
flags.SlashingProtectionJSONFileFlag.Name,
)
}
enc, err := fileutil.ReadFileAsBytes(protectionFilePath)
if err != nil {
return err
}
buf := bytes.NewBuffer(enc)
if err := slashingProtectionFormat.ImportStandardProtectionJSON(
cliCtx.Context, valDB, buf,
); err != nil {
return err
}
log.Info("Slashing protection JSON successfully imported")
return nil
}
@@ -1,8 +1,6 @@
package slashingprotection

import (
"bytes"
"context"
"encoding/json"
"flag"
"os"
Expand All @@ -23,20 +21,26 @@ import (
func setupCliCtx(
tb testing.TB,
dbPath string,
protectionFilePath string,
outputDir string,
) *cli.Context {
app := cli.App{}
set := flag.NewFlagSet("test", 0)
set.String(cmd.DataDirFlag.Name, dbPath, "")
set.String(flags.SlashingProtectionJSONFileFlag.Name, protectionFilePath, "")
set.String(flags.SlashingProtectionExportDirFlag.Name, outputDir, "")
require.NoError(tb, set.Set(flags.SlashingProtectionJSONFileFlag.Name, protectionFilePath))
assert.NoError(tb, set.Set(cmd.DataDirFlag.Name, dbPath))
assert.NoError(tb, set.Set(flags.SlashingProtectionExportDirFlag.Name, outputDir))
return cli.NewContext(&app, set, nil)
}

func TestExportSlashingProtectionCli(t *testing.T) {
ctx := context.Background()
func TestImportExportSlashingProtectionCli_RoundTrip(t *testing.T) {
numValidators := 10
outputPath := filepath.Join(os.TempDir(), "slashing-exports")
err := fileutil.MkdirAll(outputPath)
require.NoError(t, err)
protectionFileName := "slashing_history_import.json"

// Create some mock slashing protection history. and JSON file
pubKeys, err := mocks.CreateRandomPubKeys(numValidators)
Expand All @@ -46,21 +50,25 @@ func TestExportSlashingProtectionCli(t *testing.T) {
mockJSON, err := mocks.MockSlashingProtectionJSON(pubKeys, attestingHistory, proposalHistory)
require.NoError(t, err)

// We JSON encode the protection file and import it into our database.
// We JSON encode the protection file and save it to disk as a JSON file.
encoded, err := json.Marshal(mockJSON)
require.NoError(t, err)
buf := bytes.NewBuffer(encoded)

validatorDB := dbTest.SetupDB(t, pubKeys)
err = protectionFormat.ImportStandardProtectionJSON(ctx, validatorDB, buf)
protectionFilePath := filepath.Join(outputPath, protectionFileName)
err = fileutil.WriteFile(protectionFilePath, encoded)
require.NoError(t, err)
require.NoError(t, validatorDB.Close())

// We export our slashing protection history by creating a CLI context
// with the required values, such as the database datadir and output directory.
// We create a CLI context with the required values, such as the database datadir and output directory.
validatorDB := dbTest.SetupDB(t, pubKeys)
dbPath := validatorDB.DatabasePath()
outputPath := filepath.Join(os.TempDir(), "slashing-exports")
cliCtx := setupCliCtx(t, dbPath, outputPath)
require.NoError(t, validatorDB.Close())
cliCtx := setupCliCtx(t, dbPath, protectionFilePath, outputPath)

// We import the slashing protection history file via CLI.
err = ImportSlashingProtectionCLI(cliCtx)
require.NoError(t, err)

// We export the slashing protection history file via CLI.
err = ExportSlashingProtectionJSONCli(cliCtx)
require.NoError(t, err)

Expand Down
25 changes: 25 additions & 0 deletions validator/slashing-protection/cmd.go
Expand Up @@ -5,9 +5,12 @@ import (
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/tos"
"github.com/prysmaticlabs/prysm/validator/flags"
"github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
)

var log = logrus.WithField("prefix", "slashing-protection")

// Commands for slashing protection.
var Commands = &cli.Command{
Name: "slashing-protection",
Expand All @@ -32,5 +35,27 @@ var Commands = &cli.Command{
return ExportSlashingProtectionJSONCli(cliCtx)
},
},
{
Name: "import",
Description: `imports a selected EIP-3076 compliant slashing protection JSON to the validator database`,
Flags: cmd.WrapFlags([]cli.Flag{
cmd.DataDirFlag,
flags.SlashingProtectionJSONFileFlag,
featureconfig.Mainnet,
featureconfig.PyrmontTestnet,
featureconfig.ToledoTestnet,
cmd.AcceptTosFlag,
}),
Before: func(cliCtx *cli.Context) error {
if err := cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags); err != nil {
return err
}
return tos.VerifyTosAcceptedOrPrompt(cliCtx)
},
Action: func(cliCtx *cli.Context) error {
featureconfig.ConfigureValidator(cliCtx)
return ImportSlashingProtectionCLI(cliCtx)
},
},
},
}
1 change: 0 additions & 1 deletion validator/slashing-protection/external.go
Expand Up @@ -4,7 +4,6 @@ import (
"context"

ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
log "github.com/sirupsen/logrus"
)

// CheckBlockSafety this function is part of slashing protection for block proposals it performs
Expand Down
1 change: 0 additions & 1 deletion validator/slashing-protection/slasher_client.go
Expand Up @@ -13,7 +13,6 @@ import (
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
ethsl "github.com/prysmaticlabs/prysm/proto/slashing"
"github.com/prysmaticlabs/prysm/shared/grpcutils"
log "github.com/sirupsen/logrus"
"go.opencensus.io/plugin/ocgrpc"
"google.golang.org/grpc"
"google.golang.org/grpc/connectivity"
Expand Down