mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 07:28:06 -05:00
* 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>
180 lines
6.9 KiB
Go
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)
|
|
}
|
|
}
|