github.com/prysmaticlabs/prysm@v1.4.4/validator/keymanager/imported/import_test.go (about)

     1  package imported
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/google/uuid"
    11  	"github.com/prysmaticlabs/prysm/shared/bls"
    12  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    13  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    14  	mock "github.com/prysmaticlabs/prysm/validator/accounts/testing"
    15  	"github.com/prysmaticlabs/prysm/validator/keymanager"
    16  	logTest "github.com/sirupsen/logrus/hooks/test"
    17  	keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
    18  )
    19  
    20  const password = "secretPassw0rd$1999"
    21  
    22  func createRandomKeystore(t testing.TB, password string) *keymanager.Keystore {
    23  	encryptor := keystorev4.New()
    24  	id, err := uuid.NewRandom()
    25  	require.NoError(t, err)
    26  	validatingKey, err := bls.RandKey()
    27  	require.NoError(t, err)
    28  	pubKey := validatingKey.PublicKey().Marshal()
    29  	cryptoFields, err := encryptor.Encrypt(validatingKey.Marshal(), password)
    30  	require.NoError(t, err)
    31  	return &keymanager.Keystore{
    32  		Crypto:  cryptoFields,
    33  		Pubkey:  fmt.Sprintf("%x", pubKey),
    34  		ID:      id.String(),
    35  		Version: encryptor.Version(),
    36  		Name:    encryptor.Name(),
    37  	}
    38  }
    39  
    40  func TestImportedKeymanager_CreateAccountsKeystore_NoDuplicates(t *testing.T) {
    41  	numKeys := 50
    42  	pubKeys := make([][]byte, numKeys)
    43  	privKeys := make([][]byte, numKeys)
    44  	for i := 0; i < numKeys; i++ {
    45  		priv, err := bls.RandKey()
    46  		require.NoError(t, err)
    47  		privKeys[i] = priv.Marshal()
    48  		pubKeys[i] = priv.PublicKey().Marshal()
    49  	}
    50  	wallet := &mock.Wallet{
    51  		WalletPassword: "Passwordz0202$",
    52  	}
    53  	dr := &Keymanager{
    54  		wallet: wallet,
    55  	}
    56  	ctx := context.Background()
    57  	_, err := dr.CreateAccountsKeystore(ctx, privKeys, pubKeys)
    58  	require.NoError(t, err)
    59  
    60  	// We expect the 50 keys in the account store to match.
    61  	require.NotNil(t, dr.accountsStore)
    62  	require.Equal(t, len(dr.accountsStore.PublicKeys), len(dr.accountsStore.PrivateKeys))
    63  	require.Equal(t, len(dr.accountsStore.PublicKeys), numKeys)
    64  	for i := 0; i < len(dr.accountsStore.PrivateKeys); i++ {
    65  		assert.DeepEqual(t, dr.accountsStore.PrivateKeys[i], privKeys[i])
    66  		assert.DeepEqual(t, dr.accountsStore.PublicKeys[i], pubKeys[i])
    67  	}
    68  
    69  	// Re-run the create accounts keystore function with the same pubkeys.
    70  	_, err = dr.CreateAccountsKeystore(ctx, privKeys, pubKeys)
    71  	require.NoError(t, err)
    72  
    73  	// We expect nothing to change.
    74  	require.NotNil(t, dr.accountsStore)
    75  	require.Equal(t, len(dr.accountsStore.PublicKeys), len(dr.accountsStore.PrivateKeys))
    76  	require.Equal(t, len(dr.accountsStore.PublicKeys), numKeys)
    77  	for i := 0; i < len(dr.accountsStore.PrivateKeys); i++ {
    78  		assert.DeepEqual(t, dr.accountsStore.PrivateKeys[i], privKeys[i])
    79  		assert.DeepEqual(t, dr.accountsStore.PublicKeys[i], pubKeys[i])
    80  	}
    81  
    82  	// Now, we run the function again but with a new priv and pubkey and this
    83  	// time, we do expect a change.
    84  	privKey, err := bls.RandKey()
    85  	require.NoError(t, err)
    86  	privKeys = append(privKeys, privKey.Marshal())
    87  	pubKeys = append(pubKeys, privKey.PublicKey().Marshal())
    88  
    89  	_, err = dr.CreateAccountsKeystore(ctx, privKeys, pubKeys)
    90  	require.NoError(t, err)
    91  	require.Equal(t, len(dr.accountsStore.PublicKeys), len(dr.accountsStore.PrivateKeys))
    92  
    93  	// We should have 1 more new key in the store.
    94  	require.Equal(t, numKeys+1, len(dr.accountsStore.PrivateKeys))
    95  }
    96  
    97  func TestImportedKeymanager_ImportKeystores(t *testing.T) {
    98  	// Setup the keymanager.
    99  	wallet := &mock.Wallet{
   100  		Files:          make(map[string]map[string][]byte),
   101  		WalletPassword: password,
   102  	}
   103  	dr := &Keymanager{
   104  		wallet:        wallet,
   105  		accountsStore: &accountStore{},
   106  	}
   107  
   108  	// Create a duplicate keystore and attempt to import it. This should complete correctly though log specific output.
   109  	numAccounts := 5
   110  	keystores := make([]*keymanager.Keystore, numAccounts+1)
   111  	for i := 1; i < numAccounts+1; i++ {
   112  		keystores[i] = createRandomKeystore(t, password)
   113  	}
   114  	keystores[0] = keystores[1]
   115  	ctx := context.Background()
   116  	hook := logTest.NewGlobal()
   117  	require.NoError(t, dr.ImportKeystores(
   118  		ctx,
   119  		keystores,
   120  		password,
   121  	))
   122  	require.LogsContain(t, hook, "Duplicate key")
   123  	// Import them correctly even without the duplicate.
   124  	require.NoError(t, dr.ImportKeystores(
   125  		ctx,
   126  		keystores[1:],
   127  		password,
   128  	))
   129  
   130  	// Ensure the single, all-encompassing accounts keystore was written
   131  	// to the wallet and ensure we can decrypt it using the EIP-2335 standard.
   132  	var encodedKeystore []byte
   133  	for k, v := range wallet.Files[AccountsPath] {
   134  		if strings.Contains(k, "keystore") {
   135  			encodedKeystore = v
   136  		}
   137  	}
   138  	require.NotNil(t, encodedKeystore, "could not find keystore file")
   139  	keystoreFile := &keymanager.Keystore{}
   140  	require.NoError(t, json.Unmarshal(encodedKeystore, keystoreFile))
   141  
   142  	// We decrypt the crypto fields of the accounts keystore.
   143  	decryptor := keystorev4.New()
   144  	encodedAccounts, err := decryptor.Decrypt(keystoreFile.Crypto, password)
   145  	require.NoError(t, err, "Could not decrypt validator accounts")
   146  	store := &accountStore{}
   147  	require.NoError(t, json.Unmarshal(encodedAccounts, store))
   148  
   149  	// We should have successfully imported all accounts
   150  	// from external sources into a single AccountsStore
   151  	// struct preserved within a single keystore file.
   152  	assert.Equal(t, numAccounts, len(store.PublicKeys))
   153  	assert.Equal(t, numAccounts, len(store.PrivateKeys))
   154  }