2022-02-01 19:54:19 +00:00
|
|
|
package local
|
2021-11-19 04:11:54 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
2022-01-06 17:33:08 +00:00
|
|
|
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
2021-11-19 04:11:54 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
|
|
|
ethpbservice "github.com/prysmaticlabs/prysm/proto/eth/service"
|
|
|
|
"github.com/prysmaticlabs/prysm/testing/require"
|
|
|
|
mock "github.com/prysmaticlabs/prysm/validator/accounts/testing"
|
|
|
|
"github.com/prysmaticlabs/prysm/validator/keymanager"
|
|
|
|
logTest "github.com/sirupsen/logrus/hooks/test"
|
|
|
|
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
|
|
|
|
)
|
|
|
|
|
2022-02-01 19:54:19 +00:00
|
|
|
func TestLocalKeymanager_DeleteKeystores(t *testing.T) {
|
2021-11-19 04:11:54 +00:00
|
|
|
hook := logTest.NewGlobal()
|
|
|
|
wallet := &mock.Wallet{
|
|
|
|
Files: make(map[string]map[string][]byte),
|
|
|
|
WalletPassword: password,
|
|
|
|
}
|
|
|
|
dr := &Keymanager{
|
|
|
|
wallet: wallet,
|
|
|
|
accountsStore: &accountStore{},
|
|
|
|
}
|
|
|
|
numAccounts := 5
|
|
|
|
ctx := context.Background()
|
|
|
|
keystores := make([]*keymanager.Keystore, numAccounts)
|
2021-12-02 14:58:49 +00:00
|
|
|
passwords := make([]string, numAccounts)
|
2021-11-19 04:11:54 +00:00
|
|
|
for i := 0; i < numAccounts; i++ {
|
|
|
|
keystores[i] = createRandomKeystore(t, password)
|
2021-12-02 14:58:49 +00:00
|
|
|
passwords[i] = password
|
2021-11-19 04:11:54 +00:00
|
|
|
}
|
2021-12-02 14:58:49 +00:00
|
|
|
_, err := dr.ImportKeystores(ctx, keystores, passwords)
|
2021-11-24 15:40:49 +00:00
|
|
|
require.NoError(t, err)
|
2021-11-19 04:11:54 +00:00
|
|
|
accounts, err := dr.FetchValidatingPublicKeys(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, numAccounts, len(accounts))
|
|
|
|
|
|
|
|
t.Run("keys not found", func(t *testing.T) {
|
2022-01-06 17:33:08 +00:00
|
|
|
notFoundPubKey := [fieldparams.BLSPubkeyLength]byte{1, 2, 3}
|
|
|
|
notFoundPubKey2 := [fieldparams.BLSPubkeyLength]byte{4, 5, 6}
|
2021-11-19 04:11:54 +00:00
|
|
|
statuses, err := dr.DeleteKeystores(ctx, [][]byte{notFoundPubKey[:], notFoundPubKey2[:]})
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 2, len(statuses))
|
|
|
|
require.Equal(t, ethpbservice.DeletedKeystoreStatus_NOT_FOUND, statuses[0].Status)
|
|
|
|
require.Equal(t, ethpbservice.DeletedKeystoreStatus_NOT_FOUND, statuses[1].Status)
|
|
|
|
})
|
|
|
|
t.Run("deletes properly", func(t *testing.T) {
|
|
|
|
accountToRemove := uint64(2)
|
|
|
|
accountPubKey := accounts[accountToRemove]
|
|
|
|
statuses, err := dr.DeleteKeystores(ctx, [][]byte{accountPubKey[:]})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.Equal(t, 1, len(statuses))
|
|
|
|
require.Equal(t, ethpbservice.DeletedKeystoreStatus_DELETED, statuses[0].Status)
|
|
|
|
|
|
|
|
// Ensure the keystore file 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")
|
|
|
|
keystoreFile := &keymanager.Keystore{}
|
|
|
|
require.NoError(t, json.Unmarshal(encodedKeystore, keystoreFile))
|
|
|
|
|
|
|
|
// We extract the accounts from the 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))
|
|
|
|
|
|
|
|
require.Equal(t, numAccounts-1, len(store.PublicKeys))
|
|
|
|
require.Equal(t, numAccounts-1, len(store.PrivateKeys))
|
|
|
|
require.LogsContain(t, hook, fmt.Sprintf("%#x", bytesutil.Trunc(accountPubKey[:])))
|
|
|
|
require.LogsContain(t, hook, "Successfully deleted validator key(s)")
|
|
|
|
})
|
|
|
|
t.Run("returns NOT_ACTIVE status for duplicate public key in request", func(t *testing.T) {
|
|
|
|
accountToRemove := uint64(3)
|
|
|
|
accountPubKey := accounts[accountToRemove]
|
|
|
|
statuses, err := dr.DeleteKeystores(ctx, [][]byte{
|
|
|
|
accountPubKey[:],
|
|
|
|
accountPubKey[:], // Add in the same key a few more times.
|
|
|
|
accountPubKey[:],
|
|
|
|
accountPubKey[:],
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.Equal(t, 4, len(statuses))
|
|
|
|
for i, st := range statuses {
|
|
|
|
if i == 0 {
|
|
|
|
require.Equal(t, ethpbservice.DeletedKeystoreStatus_DELETED, st.Status)
|
|
|
|
} else {
|
|
|
|
require.Equal(t, ethpbservice.DeletedKeystoreStatus_NOT_ACTIVE, st.Status)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure the keystore file 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")
|
|
|
|
keystoreFile := &keymanager.Keystore{}
|
|
|
|
require.NoError(t, json.Unmarshal(encodedKeystore, keystoreFile))
|
|
|
|
|
|
|
|
// We extract the accounts from the 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))
|
|
|
|
|
|
|
|
require.Equal(t, numAccounts-2, len(store.PublicKeys))
|
|
|
|
require.Equal(t, numAccounts-2, len(store.PrivateKeys))
|
|
|
|
require.LogsContain(t, hook, fmt.Sprintf("%#x", bytesutil.Trunc(accountPubKey[:])))
|
|
|
|
require.LogsContain(t, hook, "Successfully deleted validator key(s)")
|
|
|
|
})
|
|
|
|
}
|