2020-10-16 18:45:14 +00:00
|
|
|
package imported
|
2020-08-02 20:02:04 +00:00
|
|
|
|
|
|
|
import (
|
2020-08-03 18:58:04 +00:00
|
|
|
"context"
|
2020-08-02 20:02:04 +00:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/prysmaticlabs/prysm/shared/bls"
|
|
|
|
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
|
|
|
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
2020-10-15 22:31:52 +00:00
|
|
|
mock "github.com/prysmaticlabs/prysm/validator/accounts/testing"
|
|
|
|
"github.com/prysmaticlabs/prysm/validator/keymanager"
|
2020-08-02 20:02:04 +00:00
|
|
|
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
|
|
|
|
)
|
|
|
|
|
2020-10-15 22:31:52 +00:00
|
|
|
func createRandomKeystore(t testing.TB, password string) *keymanager.Keystore {
|
2020-08-02 20:02:04 +00:00
|
|
|
encryptor := keystorev4.New()
|
|
|
|
id, err := uuid.NewRandom()
|
|
|
|
require.NoError(t, err)
|
|
|
|
validatingKey := bls.RandKey()
|
|
|
|
pubKey := validatingKey.PublicKey().Marshal()
|
|
|
|
cryptoFields, err := encryptor.Encrypt(validatingKey.Marshal(), password)
|
|
|
|
require.NoError(t, err)
|
2020-10-15 22:31:52 +00:00
|
|
|
return &keymanager.Keystore{
|
2020-08-02 20:02:04 +00:00
|
|
|
Crypto: cryptoFields,
|
|
|
|
Pubkey: fmt.Sprintf("%x", pubKey),
|
|
|
|
ID: id.String(),
|
|
|
|
Version: encryptor.Version(),
|
|
|
|
Name: encryptor.Name(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-16 18:45:14 +00:00
|
|
|
func TestImportedKeymanager_CreateAccountsKeystore_NoDuplicates(t *testing.T) {
|
2020-08-03 18:58:04 +00:00
|
|
|
numKeys := 50
|
|
|
|
pubKeys := make([][]byte, numKeys)
|
|
|
|
privKeys := make([][]byte, numKeys)
|
|
|
|
for i := 0; i < numKeys; i++ {
|
|
|
|
priv := bls.RandKey()
|
|
|
|
privKeys[i] = priv.Marshal()
|
|
|
|
pubKeys[i] = priv.PublicKey().Marshal()
|
|
|
|
}
|
2020-08-31 19:46:45 +00:00
|
|
|
wallet := &mock.Wallet{
|
|
|
|
WalletPassword: "Passwordz0202$",
|
|
|
|
}
|
2020-08-03 18:58:04 +00:00
|
|
|
dr := &Keymanager{
|
2020-08-31 19:46:45 +00:00
|
|
|
wallet: wallet,
|
2020-08-03 18:58:04 +00:00
|
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
_, err := dr.createAccountsKeystore(ctx, privKeys, pubKeys)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// We expect the 50 keys in the account store to match.
|
|
|
|
require.NotNil(t, dr.accountsStore)
|
|
|
|
require.Equal(t, len(dr.accountsStore.PublicKeys), len(dr.accountsStore.PrivateKeys))
|
|
|
|
require.Equal(t, len(dr.accountsStore.PublicKeys), numKeys)
|
|
|
|
for i := 0; i < len(dr.accountsStore.PrivateKeys); i++ {
|
|
|
|
assert.DeepEqual(t, dr.accountsStore.PrivateKeys[i], privKeys[i])
|
|
|
|
assert.DeepEqual(t, dr.accountsStore.PublicKeys[i], pubKeys[i])
|
|
|
|
}
|
|
|
|
|
|
|
|
// Re-run the create accounts keystore function with the same pubkeys.
|
|
|
|
_, err = dr.createAccountsKeystore(ctx, privKeys, pubKeys)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// We expect nothing to change.
|
|
|
|
require.NotNil(t, dr.accountsStore)
|
|
|
|
require.Equal(t, len(dr.accountsStore.PublicKeys), len(dr.accountsStore.PrivateKeys))
|
|
|
|
require.Equal(t, len(dr.accountsStore.PublicKeys), numKeys)
|
|
|
|
for i := 0; i < len(dr.accountsStore.PrivateKeys); i++ {
|
|
|
|
assert.DeepEqual(t, dr.accountsStore.PrivateKeys[i], privKeys[i])
|
|
|
|
assert.DeepEqual(t, dr.accountsStore.PublicKeys[i], pubKeys[i])
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now, we run the function again but with a new priv and pubkey and this
|
|
|
|
// time, we do expect a change.
|
|
|
|
privKey := bls.RandKey()
|
|
|
|
privKeys = append(privKeys, privKey.Marshal())
|
|
|
|
pubKeys = append(pubKeys, privKey.PublicKey().Marshal())
|
|
|
|
|
|
|
|
_, err = dr.createAccountsKeystore(ctx, privKeys, pubKeys)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, len(dr.accountsStore.PublicKeys), len(dr.accountsStore.PrivateKeys))
|
|
|
|
|
|
|
|
// We should have 1 more new key in the store.
|
|
|
|
require.Equal(t, numKeys+1, len(dr.accountsStore.PrivateKeys))
|
|
|
|
}
|
|
|
|
|
2020-10-16 18:45:14 +00:00
|
|
|
func TestImportedKeymanager_ImportKeystores(t *testing.T) {
|
2020-08-02 20:02:04 +00:00
|
|
|
password := "secretPassw0rd$1999"
|
|
|
|
// Setup the keymanager.
|
|
|
|
wallet := &mock.Wallet{
|
2020-08-31 19:46:45 +00:00
|
|
|
Files: make(map[string]map[string][]byte),
|
|
|
|
WalletPassword: password,
|
2020-08-02 20:02:04 +00:00
|
|
|
}
|
|
|
|
dr := &Keymanager{
|
2020-08-31 19:46:45 +00:00
|
|
|
wallet: wallet,
|
|
|
|
accountsStore: &AccountStore{},
|
2020-08-02 20:02:04 +00:00
|
|
|
}
|
|
|
|
|
2020-10-10 01:45:26 +00:00
|
|
|
// Create a duplicate keystore and attempt to import it.
|
2020-08-02 20:02:04 +00:00
|
|
|
numAccounts := 5
|
2020-10-15 22:31:52 +00:00
|
|
|
keystores := make([]*keymanager.Keystore, numAccounts+1)
|
2020-10-10 01:45:26 +00:00
|
|
|
for i := 1; i < numAccounts+1; i++ {
|
2020-08-02 20:02:04 +00:00
|
|
|
keystores[i] = createRandomKeystore(t, password)
|
|
|
|
}
|
2020-10-10 01:45:26 +00:00
|
|
|
keystores[0] = keystores[1]
|
2020-08-31 19:46:45 +00:00
|
|
|
ctx := context.Background()
|
2020-10-10 01:45:26 +00:00
|
|
|
require.ErrorContains(t, "duplicated key found:", dr.ImportKeystores(
|
2020-08-31 19:46:45 +00:00
|
|
|
ctx,
|
|
|
|
keystores,
|
|
|
|
password,
|
|
|
|
))
|
2020-10-10 01:45:26 +00:00
|
|
|
// Import them correctly without the duplicate.
|
|
|
|
require.NoError(t, dr.ImportKeystores(
|
|
|
|
ctx,
|
|
|
|
keystores[1:],
|
|
|
|
password,
|
|
|
|
))
|
2020-08-02 20:02:04 +00:00
|
|
|
|
|
|
|
// Ensure the single, all-encompassing accounts keystore was written
|
|
|
|
// to the wallet and ensure we can decrypt it using the EIP-2335 standard.
|
|
|
|
var encodedKeystore []byte
|
|
|
|
for k, v := range wallet.Files[AccountsPath] {
|
|
|
|
if strings.Contains(k, "keystore") {
|
|
|
|
encodedKeystore = v
|
|
|
|
}
|
|
|
|
}
|
|
|
|
require.NotNil(t, encodedKeystore, "could not find keystore file")
|
2020-10-15 22:31:52 +00:00
|
|
|
keystoreFile := &keymanager.Keystore{}
|
2020-08-02 20:02:04 +00:00
|
|
|
require.NoError(t, json.Unmarshal(encodedKeystore, keystoreFile))
|
|
|
|
|
|
|
|
// We decrypt the crypto fields of the accounts keystore.
|
|
|
|
decryptor := keystorev4.New()
|
|
|
|
encodedAccounts, err := decryptor.Decrypt(keystoreFile.Crypto, password)
|
|
|
|
require.NoError(t, err, "Could not decrypt validator accounts")
|
|
|
|
store := &AccountStore{}
|
|
|
|
require.NoError(t, json.Unmarshal(encodedAccounts, store))
|
|
|
|
|
|
|
|
// We should have successfully imported all accounts
|
|
|
|
// from external sources into a single AccountsStore
|
|
|
|
// struct preserved within a single keystore file.
|
|
|
|
assert.Equal(t, numAccounts, len(store.PublicKeys))
|
|
|
|
assert.Equal(t, numAccounts, len(store.PrivateKeys))
|
|
|
|
}
|