github.com/prysmaticlabs/prysm@v1.4.4/validator/slashing-protection/cli_import_export_test.go (about)

     1  package slashingprotection
     2  
     3  import (
     4  	"encoding/json"
     5  	"flag"
     6  	"os"
     7  	"path/filepath"
     8  	"testing"
     9  
    10  	"github.com/prysmaticlabs/prysm/cmd/validator/flags"
    11  	"github.com/prysmaticlabs/prysm/shared/cmd"
    12  	"github.com/prysmaticlabs/prysm/shared/fileutil"
    13  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    14  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    15  	"github.com/prysmaticlabs/prysm/validator/db/kv"
    16  	dbTest "github.com/prysmaticlabs/prysm/validator/db/testing"
    17  	"github.com/prysmaticlabs/prysm/validator/slashing-protection/local/standard-protection-format/format"
    18  	mocks "github.com/prysmaticlabs/prysm/validator/testing"
    19  	"github.com/urfave/cli/v2"
    20  )
    21  
    22  func setupCliCtx(
    23  	tb testing.TB,
    24  	dbPath,
    25  	protectionFilePath,
    26  	outputDir string,
    27  ) *cli.Context {
    28  	app := cli.App{}
    29  	set := flag.NewFlagSet("test", 0)
    30  	set.String(cmd.DataDirFlag.Name, dbPath, "")
    31  	set.String(flags.SlashingProtectionJSONFileFlag.Name, protectionFilePath, "")
    32  	set.String(flags.SlashingProtectionExportDirFlag.Name, outputDir, "")
    33  	require.NoError(tb, set.Set(flags.SlashingProtectionJSONFileFlag.Name, protectionFilePath))
    34  	assert.NoError(tb, set.Set(cmd.DataDirFlag.Name, dbPath))
    35  	assert.NoError(tb, set.Set(flags.SlashingProtectionExportDirFlag.Name, outputDir))
    36  	return cli.NewContext(&app, set, nil)
    37  }
    38  
    39  func TestImportExportSlashingProtectionCli_RoundTrip(t *testing.T) {
    40  	numValidators := 10
    41  	outputPath := filepath.Join(os.TempDir(), "slashing-exports")
    42  	err := fileutil.MkdirAll(outputPath)
    43  	require.NoError(t, err)
    44  	protectionFileName := "slashing_history_import.json"
    45  
    46  	// Create some mock slashing protection history. and JSON file
    47  	pubKeys, err := mocks.CreateRandomPubKeys(numValidators)
    48  	require.NoError(t, err)
    49  	attestingHistory, proposalHistory := mocks.MockAttestingAndProposalHistories(pubKeys)
    50  	require.NoError(t, err)
    51  	mockJSON, err := mocks.MockSlashingProtectionJSON(pubKeys, attestingHistory, proposalHistory)
    52  	require.NoError(t, err)
    53  
    54  	// We JSON encode the protection file and save it to disk as a JSON file.
    55  	encoded, err := json.Marshal(mockJSON)
    56  	require.NoError(t, err)
    57  
    58  	protectionFilePath := filepath.Join(outputPath, protectionFileName)
    59  	err = fileutil.WriteFile(protectionFilePath, encoded)
    60  	require.NoError(t, err)
    61  
    62  	// We create a CLI context with the required values, such as the database datadir and output directory.
    63  	validatorDB := dbTest.SetupDB(t, pubKeys)
    64  	dbPath := validatorDB.DatabasePath()
    65  	require.NoError(t, validatorDB.Close())
    66  	cliCtx := setupCliCtx(t, dbPath, protectionFilePath, outputPath)
    67  
    68  	// We import the slashing protection history file via CLI.
    69  	err = ImportSlashingProtectionCLI(cliCtx)
    70  	require.NoError(t, err)
    71  
    72  	// We export the slashing protection history file via CLI.
    73  	err = ExportSlashingProtectionJSONCli(cliCtx)
    74  	require.NoError(t, err)
    75  
    76  	// Attempt to read the exported file from the output directory.
    77  	enc, err := fileutil.ReadFileAsBytes(filepath.Join(outputPath, jsonExportFileName))
    78  	require.NoError(t, err)
    79  
    80  	receivedJSON := &format.EIPSlashingProtectionFormat{}
    81  	err = json.Unmarshal(enc, receivedJSON)
    82  	require.NoError(t, err)
    83  
    84  	// We verify the parsed JSON file matches. Given there is no guarantee of order,
    85  	// we will have to carefully compare and sort values as needed.
    86  	//
    87  	// First, we compare basic data such as the MetadataV0 value in the JSON file.
    88  	require.DeepEqual(t, mockJSON.Metadata, receivedJSON.Metadata)
    89  	wantedHistoryByPublicKey := make(map[string]*format.ProtectionData)
    90  	for _, item := range mockJSON.Data {
    91  		wantedHistoryByPublicKey[item.Pubkey] = item
    92  	}
    93  
    94  	// Next, we compare all the data for each validator public key.
    95  	for _, item := range receivedJSON.Data {
    96  		wanted, ok := wantedHistoryByPublicKey[item.Pubkey]
    97  		require.Equal(t, true, ok)
    98  		wantedAttsByRoot := make(map[string]*format.SignedAttestation)
    99  		for _, att := range wanted.SignedAttestations {
   100  			wantedAttsByRoot[att.SigningRoot] = att
   101  		}
   102  		for _, att := range item.SignedAttestations {
   103  			wantedAtt, ok := wantedAttsByRoot[att.SigningRoot]
   104  			require.Equal(t, true, ok)
   105  			require.DeepEqual(t, wantedAtt, att)
   106  		}
   107  		require.Equal(t, len(wanted.SignedBlocks), len(item.SignedBlocks))
   108  		require.DeepEqual(t, wanted.SignedBlocks, item.SignedBlocks)
   109  	}
   110  }
   111  
   112  func TestImportExportSlashingProtectionCli_EmptyData(t *testing.T) {
   113  	numValidators := 10
   114  	outputPath := filepath.Join(os.TempDir(), "slashing-exports")
   115  	err := fileutil.MkdirAll(outputPath)
   116  	require.NoError(t, err)
   117  	protectionFileName := "slashing_history_import.json"
   118  
   119  	// Create some mock slashing protection history. and JSON file
   120  	pubKeys, err := mocks.CreateRandomPubKeys(numValidators)
   121  	require.NoError(t, err)
   122  	attestingHistory := make([][]*kv.AttestationRecord, 0)
   123  	proposalHistory := make([]kv.ProposalHistoryForPubkey, len(pubKeys))
   124  	for i := 0; i < len(pubKeys); i++ {
   125  		proposalHistory[i].Proposals = make([]kv.Proposal, 0)
   126  	}
   127  	mockJSON, err := mocks.MockSlashingProtectionJSON(pubKeys, attestingHistory, proposalHistory)
   128  	require.NoError(t, err)
   129  
   130  	// We JSON encode the protection file and save it to disk as a JSON file.
   131  	encoded, err := json.Marshal(mockJSON)
   132  	require.NoError(t, err)
   133  
   134  	protectionFilePath := filepath.Join(outputPath, protectionFileName)
   135  	err = fileutil.WriteFile(protectionFilePath, encoded)
   136  	require.NoError(t, err)
   137  
   138  	// We create a CLI context with the required values, such as the database datadir and output directory.
   139  	validatorDB := dbTest.SetupDB(t, pubKeys)
   140  	dbPath := validatorDB.DatabasePath()
   141  	require.NoError(t, validatorDB.Close())
   142  	cliCtx := setupCliCtx(t, dbPath, protectionFilePath, outputPath)
   143  
   144  	// We import the slashing protection history file via CLI.
   145  	err = ImportSlashingProtectionCLI(cliCtx)
   146  	require.NoError(t, err)
   147  
   148  	// We export the slashing protection history file via CLI.
   149  	err = ExportSlashingProtectionJSONCli(cliCtx)
   150  	require.NoError(t, err)
   151  
   152  	// Attempt to read the exported file from the output directory.
   153  	enc, err := fileutil.ReadFileAsBytes(filepath.Join(outputPath, jsonExportFileName))
   154  	require.NoError(t, err)
   155  
   156  	receivedJSON := &format.EIPSlashingProtectionFormat{}
   157  	err = json.Unmarshal(enc, receivedJSON)
   158  	require.NoError(t, err)
   159  
   160  	// We verify the parsed JSON file matches. Given there is no guarantee of order,
   161  	// we will have to carefully compare and sort values as needed.
   162  	//
   163  	// First, we compare basic data such as the MetadataV0 value in the JSON file.
   164  	require.DeepEqual(t, mockJSON.Metadata, receivedJSON.Metadata)
   165  	wantedHistoryByPublicKey := make(map[string]*format.ProtectionData)
   166  	for _, item := range mockJSON.Data {
   167  		wantedHistoryByPublicKey[item.Pubkey] = item
   168  	}
   169  
   170  	// Next, we compare all the data for each validator public key.
   171  	for _, item := range receivedJSON.Data {
   172  		wanted, ok := wantedHistoryByPublicKey[item.Pubkey]
   173  		require.Equal(t, true, ok)
   174  		require.Equal(t, len(wanted.SignedBlocks), len(item.SignedBlocks))
   175  		require.Equal(t, len(wanted.SignedAttestations), len(item.SignedAttestations))
   176  		require.DeepEqual(t, make([]*format.SignedBlock, 0), item.SignedBlocks)
   177  		require.DeepEqual(t, make([]*format.SignedAttestation, 0), item.SignedAttestations)
   178  	}
   179  }