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 }