Files
prysm/validator/slashing-protection/cli_import_export_test.go
Nishant Das 91bd477f4f Add Metadata V2 Object and Interface (#8962)
* checkpoint changes

* gaz

* add error check

* gaz

* fix tests

* fix tests

* terence's review

* terence's review

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
2021-06-02 13:44:34 +08:00

180 lines
6.9 KiB
Go

package slashingprotection
import (
"encoding/json"
"flag"
"os"
"path/filepath"
"testing"
"github.com/prysmaticlabs/prysm/cmd/validator/flags"
"github.com/prysmaticlabs/prysm/shared/cmd"
"github.com/prysmaticlabs/prysm/shared/fileutil"
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
"github.com/prysmaticlabs/prysm/shared/testutil/require"
"github.com/prysmaticlabs/prysm/validator/db/kv"
dbTest "github.com/prysmaticlabs/prysm/validator/db/testing"
"github.com/prysmaticlabs/prysm/validator/slashing-protection/local/standard-protection-format/format"
mocks "github.com/prysmaticlabs/prysm/validator/testing"
"github.com/urfave/cli/v2"
)
func setupCliCtx(
tb testing.TB,
dbPath,
protectionFilePath,
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 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)
require.NoError(t, err)
attestingHistory, proposalHistory := mocks.MockAttestingAndProposalHistories(numValidators)
require.NoError(t, err)
mockJSON, err := mocks.MockSlashingProtectionJSON(pubKeys, attestingHistory, proposalHistory)
require.NoError(t, err)
// We JSON encode the protection file and save it to disk as a JSON file.
encoded, err := json.Marshal(mockJSON)
require.NoError(t, err)
protectionFilePath := filepath.Join(outputPath, protectionFileName)
err = fileutil.WriteFile(protectionFilePath, encoded)
require.NoError(t, err)
// 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()
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)
// Attempt to read the exported file from the output directory.
enc, err := fileutil.ReadFileAsBytes(filepath.Join(outputPath, jsonExportFileName))
require.NoError(t, err)
receivedJSON := &format.EIPSlashingProtectionFormat{}
err = json.Unmarshal(enc, receivedJSON)
require.NoError(t, err)
// We verify the parsed JSON file matches. Given there is no guarantee of order,
// we will have to carefully compare and sort values as needed.
//
// First, we compare basic data such as the MetadataV0 value in the JSON file.
require.DeepEqual(t, mockJSON.Metadata, receivedJSON.Metadata)
wantedHistoryByPublicKey := make(map[string]*format.ProtectionData)
for _, item := range mockJSON.Data {
wantedHistoryByPublicKey[item.Pubkey] = item
}
// Next, we compare all the data for each validator public key.
for _, item := range receivedJSON.Data {
wanted, ok := wantedHistoryByPublicKey[item.Pubkey]
require.Equal(t, true, ok)
wantedAttsByRoot := make(map[string]*format.SignedAttestation)
for _, att := range wanted.SignedAttestations {
wantedAttsByRoot[att.SigningRoot] = att
}
for _, att := range item.SignedAttestations {
wantedAtt, ok := wantedAttsByRoot[att.SigningRoot]
require.Equal(t, true, ok)
require.DeepEqual(t, wantedAtt, att)
}
require.Equal(t, len(wanted.SignedBlocks), len(item.SignedBlocks))
require.DeepEqual(t, wanted.SignedBlocks, item.SignedBlocks)
}
}
func TestImportExportSlashingProtectionCli_EmptyData(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)
require.NoError(t, err)
attestingHistory := make([][]*kv.AttestationRecord, 0)
proposalHistory := make([]kv.ProposalHistoryForPubkey, len(pubKeys))
for i := 0; i < len(pubKeys); i++ {
proposalHistory[i].Proposals = make([]kv.Proposal, 0)
}
mockJSON, err := mocks.MockSlashingProtectionJSON(pubKeys, attestingHistory, proposalHistory)
require.NoError(t, err)
// We JSON encode the protection file and save it to disk as a JSON file.
encoded, err := json.Marshal(mockJSON)
require.NoError(t, err)
protectionFilePath := filepath.Join(outputPath, protectionFileName)
err = fileutil.WriteFile(protectionFilePath, encoded)
require.NoError(t, err)
// 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()
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)
// Attempt to read the exported file from the output directory.
enc, err := fileutil.ReadFileAsBytes(filepath.Join(outputPath, jsonExportFileName))
require.NoError(t, err)
receivedJSON := &format.EIPSlashingProtectionFormat{}
err = json.Unmarshal(enc, receivedJSON)
require.NoError(t, err)
// We verify the parsed JSON file matches. Given there is no guarantee of order,
// we will have to carefully compare and sort values as needed.
//
// First, we compare basic data such as the MetadataV0 value in the JSON file.
require.DeepEqual(t, mockJSON.Metadata, receivedJSON.Metadata)
wantedHistoryByPublicKey := make(map[string]*format.ProtectionData)
for _, item := range mockJSON.Data {
wantedHistoryByPublicKey[item.Pubkey] = item
}
// Next, we compare all the data for each validator public key.
for _, item := range receivedJSON.Data {
wanted, ok := wantedHistoryByPublicKey[item.Pubkey]
require.Equal(t, true, ok)
require.Equal(t, len(wanted.SignedBlocks), len(item.SignedBlocks))
require.Equal(t, len(wanted.SignedAttestations), len(item.SignedAttestations))
require.DeepEqual(t, make([]*format.SignedBlock, 0), item.SignedBlocks)
require.DeepEqual(t, make([]*format.SignedAttestation, 0), item.SignedAttestations)
}
}