From 3c84cc8a350231a26a915472530c9b9bbcc1a464 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Fri, 14 Apr 2023 11:57:34 -0500 Subject: [PATCH 01/22] WIP changes for keymanager --- validator/keymanager/local/delete.go | 48 ++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/validator/keymanager/local/delete.go b/validator/keymanager/local/delete.go index 3a6f33ffabc7..f552f64730c6 100644 --- a/validator/keymanager/local/delete.go +++ b/validator/keymanager/local/delete.go @@ -16,6 +16,12 @@ import ( // DeleteKeystores takes in public keys and removes the accounts from the wallet. // This includes their disk keystore and cached keystore, but maintains the slashing // protection history in the database. +// 1) Copy the in memory keystore +// 2) Delete the keys from copied in memory keystore +// 3) Save the copy to disk +// 4) Reinitialize account store from disk +// 5) Verify keys are indeed deleted +// 6) Return API response func (km *Keymanager) DeleteKeystores( ctx context.Context, publicKeys [][]byte, ) ([]*ethpbservice.DeletedKeystoreStatus, error) { @@ -25,8 +31,15 @@ func (km *Keymanager) DeleteKeystores( var store *AccountsKeystoreRepresentation var err error deletedKeys := make([][]byte, 0, len(publicKeys)) + // 1) Copy the in memory keystore + storeCopy := km.accountsStore + storeCopy.PrivateKeys = make([][]byte, len(km.accountsStore.PrivateKeys)) + copy(storeCopy.PrivateKeys, km.accountsStore.PrivateKeys) + storeCopy.PublicKeys = make([][]byte, len(km.accountsStore.PublicKeys)) + copy(storeCopy.PublicKeys, km.accountsStore.PublicKeys) + // for _, publicKey := range publicKeys { - // Check if the key in the request is a duplicate. + // Check if the key in the request is a duplicate or not found if _, ok := trackedPublicKeys[bytesutil.ToBytes48(publicKey)]; ok { statuses = append(statuses, ðpbservice.DeletedKeystoreStatus{ Status: ethpbservice.DeletedKeystoreStatus_NOT_ACTIVE, @@ -35,7 +48,7 @@ func (km *Keymanager) DeleteKeystores( } var index int var found bool - for j, pubKey := range km.accountsStore.PublicKeys { + for j, pubKey := range storeCopy.PublicKeys { if bytes.Equal(pubKey, publicKey) { index = j found = true @@ -48,14 +61,18 @@ func (km *Keymanager) DeleteKeystores( }) continue } - deletedPublicKey := km.accountsStore.PublicKeys[index] + // + // 2) Delete the keys from copied in memory keystore + deletedPublicKey := storeCopy.PublicKeys[index] deletedKeys = append(deletedKeys, deletedPublicKey) - km.accountsStore.PrivateKeys = append(km.accountsStore.PrivateKeys[:index], km.accountsStore.PrivateKeys[index+1:]...) - km.accountsStore.PublicKeys = append(km.accountsStore.PublicKeys[:index], km.accountsStore.PublicKeys[index+1:]...) - store, err = km.CreateAccountsKeystore(ctx, km.accountsStore.PrivateKeys, km.accountsStore.PublicKeys) + + storeCopy.PrivateKeys = append(storeCopy.PrivateKeys[:index], storeCopy.PrivateKeys[index+1:]...) + storeCopy.PublicKeys = append(storeCopy.PublicKeys[:index], storeCopy.PublicKeys[index+1:]...) + store, err = km.CreateAccountsKeystore(ctx, storeCopy.PrivateKeys, storeCopy.PublicKeys) if err != nil { return nil, errors.Wrap(err, "could not rewrite accounts keystore") } + // statuses = append(statuses, ðpbservice.DeletedKeystoreStatus{ Status: ethpbservice.DeletedKeystoreStatus_DELETED, }) @@ -75,10 +92,7 @@ func (km *Keymanager) DeleteKeystores( } } - log.WithFields(logrus.Fields{ - "publicKeys": deletedKeysStr, - }).Info("Successfully deleted validator key(s)") - + // 3) Save the copy to disk // Write the encoded keystore. encoded, err := json.MarshalIndent(store, "", "\t") if err != nil { @@ -87,12 +101,18 @@ func (km *Keymanager) DeleteKeystores( if err := km.wallet.WriteFileAtPath(ctx, AccountsPath, AccountsKeystoreFileName, encoded); err != nil { return nil, errors.Wrap(err, "could not write keystore file for accounts") } - err = km.initializeKeysCachesFromKeystore() - if err != nil { - return nil, errors.Wrap(err, "failed to initialize key caches") - } + // + // 4) Reinitialize account store from disk + + //// ) Reload keystore Cache + //err = km.initializeKeysCachesFromKeystore() + //if err != nil { + // return nil, errors.Wrap(err, "failed to initialize key caches") + //} + //// log.WithFields(logrus.Fields{ "publicKeys": deletedKeysStr, }).Info("Successfully deleted validator key(s)") + // 6) Return API response return statuses, nil } From c36cb62729f7c3c612bfc6585262c7863e34afde Mon Sep 17 00:00:00 2001 From: james-prysm Date: Fri, 14 Apr 2023 12:29:19 -0500 Subject: [PATCH 02/22] WIP fix --- validator/keymanager/local/delete.go | 37 ++++++++++++++-------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/validator/keymanager/local/delete.go b/validator/keymanager/local/delete.go index f552f64730c6..b4dddff8cfe9 100644 --- a/validator/keymanager/local/delete.go +++ b/validator/keymanager/local/delete.go @@ -31,6 +31,7 @@ func (km *Keymanager) DeleteKeystores( var store *AccountsKeystoreRepresentation var err error deletedKeys := make([][]byte, 0, len(publicKeys)) + originalKeyLen := len(km.accountsStore.PublicKeys) // 1) Copy the in memory keystore storeCopy := km.accountsStore storeCopy.PrivateKeys = make([][]byte, len(km.accountsStore.PrivateKeys)) @@ -81,17 +82,6 @@ func (km *Keymanager) DeleteKeystores( if len(deletedKeys) == 0 { return statuses, nil } - var deletedKeysStr string - for i, k := range deletedKeys { - if i == 0 { - deletedKeysStr += fmt.Sprintf("%#x", bytesutil.Trunc(k)) - } else if i == len(deletedKeys)-1 { - deletedKeysStr += fmt.Sprintf("%#x", bytesutil.Trunc(k)) - } else { - deletedKeysStr += fmt.Sprintf(",%#x", bytesutil.Trunc(k)) - } - } - // 3) Save the copy to disk // Write the encoded keystore. encoded, err := json.MarshalIndent(store, "", "\t") @@ -103,13 +93,24 @@ func (km *Keymanager) DeleteKeystores( } // // 4) Reinitialize account store from disk - - //// ) Reload keystore Cache - //err = km.initializeKeysCachesFromKeystore() - //if err != nil { - // return nil, errors.Wrap(err, "failed to initialize key caches") - //} - //// + if err := km.initializeAccountKeystore(ctx); err != nil { + return nil, errors.New("was not able to re-initialize account keystore from disk.") + } + // 5) Verify keys are indeed deleted + if len(km.accountsStore.PublicKeys) == originalKeyLen || len(km.accountsStore.PublicKeys) != len(storeCopy.PublicKeys) { + return nil, errors.New("keys were not successfully deleted in file.") + } + // + var deletedKeysStr string + for i, k := range deletedKeys { + if i == 0 { + deletedKeysStr += fmt.Sprintf("%#x", bytesutil.Trunc(k)) + } else if i == len(deletedKeys)-1 { + deletedKeysStr += fmt.Sprintf("%#x", bytesutil.Trunc(k)) + } else { + deletedKeysStr += fmt.Sprintf(",%#x", bytesutil.Trunc(k)) + } + } log.WithFields(logrus.Fields{ "publicKeys": deletedKeysStr, }).Info("Successfully deleted validator key(s)") From 071e5334407fe81b45c3e4df8414a18b4286b704 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Fri, 14 Apr 2023 15:36:18 -0500 Subject: [PATCH 03/22] WIP needs unit tests --- validator/keymanager/local/delete.go | 12 +++--- validator/keymanager/local/keymanager.go | 53 +++++++++++++++--------- 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/validator/keymanager/local/delete.go b/validator/keymanager/local/delete.go index b4dddff8cfe9..5ca001ff5e19 100644 --- a/validator/keymanager/local/delete.go +++ b/validator/keymanager/local/delete.go @@ -33,11 +33,9 @@ func (km *Keymanager) DeleteKeystores( deletedKeys := make([][]byte, 0, len(publicKeys)) originalKeyLen := len(km.accountsStore.PublicKeys) // 1) Copy the in memory keystore - storeCopy := km.accountsStore - storeCopy.PrivateKeys = make([][]byte, len(km.accountsStore.PrivateKeys)) - copy(storeCopy.PrivateKeys, km.accountsStore.PrivateKeys) - storeCopy.PublicKeys = make([][]byte, len(km.accountsStore.PublicKeys)) - copy(storeCopy.PublicKeys, km.accountsStore.PublicKeys) + storeCopy := &accountStore{} + storeCopy.PrivateKeys = bytesutil.SafeCopy2dBytes(km.accountsStore.PrivateKeys) + storeCopy.PublicKeys = bytesutil.SafeCopy2dBytes(km.accountsStore.PublicKeys) // for _, publicKey := range publicKeys { // Check if the key in the request is a duplicate or not found @@ -69,7 +67,7 @@ func (km *Keymanager) DeleteKeystores( storeCopy.PrivateKeys = append(storeCopy.PrivateKeys[:index], storeCopy.PrivateKeys[index+1:]...) storeCopy.PublicKeys = append(storeCopy.PublicKeys[:index], storeCopy.PublicKeys[index+1:]...) - store, err = km.CreateAccountsKeystore(ctx, storeCopy.PrivateKeys, storeCopy.PublicKeys) + store, err = CreateAccountsKeystoreRepresentation(ctx, storeCopy, km.wallet.Password()) if err != nil { return nil, errors.Wrap(err, "could not rewrite accounts keystore") } @@ -92,7 +90,7 @@ func (km *Keymanager) DeleteKeystores( return nil, errors.Wrap(err, "could not write keystore file for accounts") } // - // 4) Reinitialize account store from disk + // 4) Reinitialize account store from disk, updating the local store and cache if err := km.initializeAccountKeystore(ctx); err != nil { return nil, errors.New("was not able to re-initialize account keystore from disk.") } diff --git a/validator/keymanager/local/keymanager.go b/validator/keymanager/local/keymanager.go index 5c971c477d3a..b15b187aee37 100644 --- a/validator/keymanager/local/keymanager.go +++ b/validator/keymanager/local/keymanager.go @@ -256,17 +256,45 @@ func (km *Keymanager) initializeAccountKeystore(ctx context.Context) error { } // CreateAccountsKeystore creates a new keystore holding the provided keys. -func (km *Keymanager) CreateAccountsKeystore( +func (km *Keymanager) CreateAccountsKeystore(ctx context.Context, publicKeys [][]byte, privateKeys [][]byte) (*AccountsKeystoreRepresentation, error) { + if err := km.CreateOrUpdateInMemoryAccountsStore(ctx, publicKeys, privateKeys); err != nil { + return nil, err + } + return CreateAccountsKeystoreRepresentation(ctx, km.accountsStore, km.wallet.Password()) +} + +// CreateAccountsKeystoreRepresentation is a pure function that takes an accountStore and wallet password and returns the encrypted formatted json version for local writing. +func CreateAccountsKeystoreRepresentation( _ context.Context, - privateKeys, publicKeys [][]byte, + store *accountStore, + walletPW string, ) (*AccountsKeystoreRepresentation, error) { encryptor := keystorev4.New() id, err := uuid.NewRandom() if err != nil { return nil, err } + encodedStore, err := json.MarshalIndent(store, "", "\t") + if err != nil { + return nil, err + } + cryptoFields, err := encryptor.Encrypt(encodedStore, walletPW) + if err != nil { + return nil, errors.Wrap(err, "could not encrypt accounts") + } + return &AccountsKeystoreRepresentation{ + Crypto: cryptoFields, + ID: id.String(), + Version: encryptor.Version(), + Name: encryptor.Name(), + }, nil +} + +// CreateOrUpdateInMemoryAccountsStore will set or update the local accounts store and update the local cache. +// This function DOES NOT save the accounts store to disk. +func (km *Keymanager) CreateOrUpdateInMemoryAccountsStore(_ context.Context, publicKeys [][]byte, privateKeys [][]byte) error { if len(privateKeys) != len(publicKeys) { - return nil, fmt.Errorf( + return fmt.Errorf( "number of private keys and public keys is not equal: %d != %d", len(privateKeys), len(publicKeys), ) } @@ -296,24 +324,11 @@ func (km *Keymanager) CreateAccountsKeystore( km.accountsStore.PrivateKeys = append(km.accountsStore.PrivateKeys, sk) } } - err = km.initializeKeysCachesFromKeystore() - if err != nil { - return nil, errors.Wrap(err, "failed to initialize keys caches") - } - encodedStore, err := json.MarshalIndent(km.accountsStore, "", "\t") + err := km.initializeKeysCachesFromKeystore() if err != nil { - return nil, err - } - cryptoFields, err := encryptor.Encrypt(encodedStore, km.wallet.Password()) - if err != nil { - return nil, errors.Wrap(err, "could not encrypt accounts") + return errors.Wrap(err, "failed to initialize keys caches") } - return &AccountsKeystoreRepresentation{ - Crypto: cryptoFields, - ID: id.String(), - Version: encryptor.Version(), - Name: encryptor.Name(), - }, nil + return nil } func (km *Keymanager) ListKeymanagerAccounts(ctx context.Context, cfg keymanager.ListKeymanagerAccountConfig) error { From 95c90f878af099beccdbdb5dd1e4a216c29b1c47 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Fri, 14 Apr 2023 16:06:03 -0500 Subject: [PATCH 04/22] fixing order --- validator/keymanager/local/delete.go | 2 +- validator/keymanager/local/keymanager.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/validator/keymanager/local/delete.go b/validator/keymanager/local/delete.go index 5ca001ff5e19..47c2b656bdf6 100644 --- a/validator/keymanager/local/delete.go +++ b/validator/keymanager/local/delete.go @@ -69,7 +69,7 @@ func (km *Keymanager) DeleteKeystores( storeCopy.PublicKeys = append(storeCopy.PublicKeys[:index], storeCopy.PublicKeys[index+1:]...) store, err = CreateAccountsKeystoreRepresentation(ctx, storeCopy, km.wallet.Password()) if err != nil { - return nil, errors.Wrap(err, "could not rewrite accounts keystore") + return nil, errors.Wrap(err, "could not create accounts keystore representation") } // statuses = append(statuses, ðpbservice.DeletedKeystoreStatus{ diff --git a/validator/keymanager/local/keymanager.go b/validator/keymanager/local/keymanager.go index b15b187aee37..a6b5ecd0b51d 100644 --- a/validator/keymanager/local/keymanager.go +++ b/validator/keymanager/local/keymanager.go @@ -256,8 +256,8 @@ func (km *Keymanager) initializeAccountKeystore(ctx context.Context) error { } // CreateAccountsKeystore creates a new keystore holding the provided keys. -func (km *Keymanager) CreateAccountsKeystore(ctx context.Context, publicKeys [][]byte, privateKeys [][]byte) (*AccountsKeystoreRepresentation, error) { - if err := km.CreateOrUpdateInMemoryAccountsStore(ctx, publicKeys, privateKeys); err != nil { +func (km *Keymanager) CreateAccountsKeystore(ctx context.Context, privateKeys [][]byte, publicKeys [][]byte) (*AccountsKeystoreRepresentation, error) { + if err := km.CreateOrUpdateInMemoryAccountsStore(ctx, privateKeys, publicKeys); err != nil { return nil, err } return CreateAccountsKeystoreRepresentation(ctx, km.accountsStore, km.wallet.Password()) @@ -292,7 +292,7 @@ func CreateAccountsKeystoreRepresentation( // CreateOrUpdateInMemoryAccountsStore will set or update the local accounts store and update the local cache. // This function DOES NOT save the accounts store to disk. -func (km *Keymanager) CreateOrUpdateInMemoryAccountsStore(_ context.Context, publicKeys [][]byte, privateKeys [][]byte) error { +func (km *Keymanager) CreateOrUpdateInMemoryAccountsStore(_ context.Context, privateKeys [][]byte, publicKeys [][]byte) error { if len(privateKeys) != len(publicKeys) { return fmt.Errorf( "number of private keys and public keys is not equal: %d != %d", len(privateKeys), len(publicKeys), From 9956a19148ebe67618997b0e78f6b1664b74ad64 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Fri, 14 Apr 2023 17:55:03 -0500 Subject: [PATCH 05/22] adding unit test --- validator/accounts/testing/mock.go | 6 ++++++ validator/keymanager/local/delete.go | 4 ++-- validator/keymanager/local/delete_test.go | 16 ++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/validator/accounts/testing/mock.go b/validator/accounts/testing/mock.go index f4d8379e86be..2fc52606682c 100644 --- a/validator/accounts/testing/mock.go +++ b/validator/accounts/testing/mock.go @@ -25,6 +25,7 @@ type Wallet struct { WalletPassword string UnlockAccounts bool lock sync.RWMutex + HasWriteFileError bool } // AccountNames -- @@ -57,6 +58,11 @@ func (w *Wallet) Password() string { func (w *Wallet) WriteFileAtPath(_ context.Context, pathName, fileName string, data []byte) error { w.lock.Lock() defer w.lock.Unlock() + if w.HasWriteFileError { + // reset the flag to not contaminate other tests + w.HasWriteFileError = false + return errors.New("could not write keystore file for accounts") + } if w.Files[pathName] == nil { w.Files[pathName] = make(map[string][]byte) } diff --git a/validator/keymanager/local/delete.go b/validator/keymanager/local/delete.go index 47c2b656bdf6..e5dd5457560e 100644 --- a/validator/keymanager/local/delete.go +++ b/validator/keymanager/local/delete.go @@ -92,11 +92,11 @@ func (km *Keymanager) DeleteKeystores( // // 4) Reinitialize account store from disk, updating the local store and cache if err := km.initializeAccountKeystore(ctx); err != nil { - return nil, errors.New("was not able to re-initialize account keystore from disk.") + return nil, errors.New("was not able to re-initialize account keystore from disk") } // 5) Verify keys are indeed deleted if len(km.accountsStore.PublicKeys) == originalKeyLen || len(km.accountsStore.PublicKeys) != len(storeCopy.PublicKeys) { - return nil, errors.New("keys were not successfully deleted in file.") + return nil, errors.New("keys were not successfully deleted in file") } // var deletedKeysStr string diff --git a/validator/keymanager/local/delete_test.go b/validator/keymanager/local/delete_test.go index 8b20cf70c0a0..d130b3c5362c 100644 --- a/validator/keymanager/local/delete_test.go +++ b/validator/keymanager/local/delete_test.go @@ -7,6 +7,7 @@ import ( "strings" "testing" + "github.com/mohae/deepcopy" fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams" "github.com/prysmaticlabs/prysm/v4/encoding/bytesutil" ethpbservice "github.com/prysmaticlabs/prysm/v4/proto/eth/service" @@ -50,6 +51,18 @@ func TestLocalKeymanager_DeleteKeystores(t *testing.T) { require.Equal(t, ethpbservice.DeletedKeystoreStatus_NOT_FOUND, statuses[0].Status) require.Equal(t, ethpbservice.DeletedKeystoreStatus_NOT_FOUND, statuses[1].Status) }) + t.Run("file write errors should not lead to updated local keystore or cache", func(t *testing.T) { + wallet.HasWriteFileError = true + accountToRemove := uint64(2) + accountPubKey := accounts[accountToRemove] + require.NotEqual(t, len(dr.accountsStore.PublicKeys), 0) + copyStore, ok := deepcopy.Copy(dr.accountsStore).(*accountStore) + require.Equal(t, true, ok) + statuses, err := dr.DeleteKeystores(ctx, [][]byte{accountPubKey[:]}) + require.ErrorContains(t, "could not write keystore file for accounts", err) + require.Equal(t, len(statuses), 0) + require.DeepEqual(t, dr.accountsStore, copyStore) + }) t.Run("deletes properly", func(t *testing.T) { accountToRemove := uint64(2) accountPubKey := accounts[accountToRemove] @@ -83,7 +96,9 @@ func TestLocalKeymanager_DeleteKeystores(t *testing.T) { 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) { + fmt.Println(wallet.HasWriteFileError) accountToRemove := uint64(3) accountPubKey := accounts[accountToRemove] statuses, err := dr.DeleteKeystores(ctx, [][]byte{ @@ -127,4 +142,5 @@ func TestLocalKeymanager_DeleteKeystores(t *testing.T) { require.LogsContain(t, hook, fmt.Sprintf("%#x", bytesutil.Trunc(accountPubKey[:]))) require.LogsContain(t, hook, "Successfully deleted validator key(s)") }) + } From 5f489fea6f1080e36bd7757da09df767f526ab32 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Fri, 14 Apr 2023 18:11:59 -0500 Subject: [PATCH 06/22] fixing linter --- validator/keymanager/local/BUILD.bazel | 1 + 1 file changed, 1 insertion(+) diff --git a/validator/keymanager/local/BUILD.bazel b/validator/keymanager/local/BUILD.bazel index 779dcc5a5f92..e2ad4b832ec5 100644 --- a/validator/keymanager/local/BUILD.bazel +++ b/validator/keymanager/local/BUILD.bazel @@ -67,6 +67,7 @@ go_test( "//validator/accounts/testing:go_default_library", "//validator/keymanager:go_default_library", "@com_github_google_uuid//:go_default_library", + "@com_github_mohae_deepcopy//:go_default_library", "@com_github_sirupsen_logrus//hooks/test:go_default_library", "@com_github_wealdtech_go_eth2_wallet_encryptor_keystorev4//:go_default_library", ], From 49dff21ffba3503f21665b25fa5669e3101f004a Mon Sep 17 00:00:00 2001 From: james-prysm Date: Fri, 14 Apr 2023 21:43:33 -0500 Subject: [PATCH 07/22] updating unit tests and creating more reusable functions --- validator/accounts/wallet_create.go | 1 + validator/keymanager/local/delete.go | 23 +------ validator/keymanager/local/import.go | 83 ++++++++++++++++------- validator/keymanager/local/import_test.go | 62 +++++++++++++++++ validator/keymanager/local/keymanager.go | 64 +++++++++++------ 5 files changed, 168 insertions(+), 65 deletions(-) diff --git a/validator/accounts/wallet_create.go b/validator/accounts/wallet_create.go index 703f4364d61d..c53e7cf3c37b 100644 --- a/validator/accounts/wallet_create.go +++ b/validator/accounts/wallet_create.go @@ -34,6 +34,7 @@ func (acm *AccountsCLIManager) WalletCreate(ctx context.Context) (*wallet.Wallet if !ok { return nil, errors.Wrap(err, ErrCouldNotInitializeKeymanager) } + accountsKeystore, err := localKm.CreateAccountsKeystore(ctx, make([][]byte, 0), make([][]byte, 0)) if err != nil { return nil, err diff --git a/validator/keymanager/local/delete.go b/validator/keymanager/local/delete.go index e5dd5457560e..2860f015e9d3 100644 --- a/validator/keymanager/local/delete.go +++ b/validator/keymanager/local/delete.go @@ -3,7 +3,6 @@ package local import ( "bytes" "context" - "encoding/json" "fmt" "github.com/pkg/errors" @@ -28,8 +27,6 @@ func (km *Keymanager) DeleteKeystores( // Check for duplicate keys and filter them out. trackedPublicKeys := make(map[[fieldparams.BLSPubkeyLength]byte]bool) statuses := make([]*ethpbservice.DeletedKeystoreStatus, 0, len(publicKeys)) - var store *AccountsKeystoreRepresentation - var err error deletedKeys := make([][]byte, 0, len(publicKeys)) originalKeyLen := len(km.accountsStore.PublicKeys) // 1) Copy the in memory keystore @@ -64,36 +61,22 @@ func (km *Keymanager) DeleteKeystores( // 2) Delete the keys from copied in memory keystore deletedPublicKey := storeCopy.PublicKeys[index] deletedKeys = append(deletedKeys, deletedPublicKey) - storeCopy.PrivateKeys = append(storeCopy.PrivateKeys[:index], storeCopy.PrivateKeys[index+1:]...) storeCopy.PublicKeys = append(storeCopy.PublicKeys[:index], storeCopy.PublicKeys[index+1:]...) - store, err = CreateAccountsKeystoreRepresentation(ctx, storeCopy, km.wallet.Password()) - if err != nil { - return nil, errors.Wrap(err, "could not create accounts keystore representation") - } - // statuses = append(statuses, ðpbservice.DeletedKeystoreStatus{ Status: ethpbservice.DeletedKeystoreStatus_DELETED, }) trackedPublicKeys[bytesutil.ToBytes48(publicKey)] = true + // } if len(deletedKeys) == 0 { return statuses, nil } - // 3) Save the copy to disk - // Write the encoded keystore. - encoded, err := json.MarshalIndent(store, "", "\t") - if err != nil { + //3 & 4) save to disk and re-initializes keystore + if err := km.SaveStoreAndReInitialize(ctx, storeCopy); err != nil { return nil, err } - if err := km.wallet.WriteFileAtPath(ctx, AccountsPath, AccountsKeystoreFileName, encoded); err != nil { - return nil, errors.Wrap(err, "could not write keystore file for accounts") - } // - // 4) Reinitialize account store from disk, updating the local store and cache - if err := km.initializeAccountKeystore(ctx); err != nil { - return nil, errors.New("was not able to re-initialize account keystore from disk") - } // 5) Verify keys are indeed deleted if len(km.accountsStore.PublicKeys) == originalKeyLen || len(km.accountsStore.PublicKeys) != len(storeCopy.PublicKeys) { return nil, errors.New("keys were not successfully deleted in file") diff --git a/validator/keymanager/local/import.go b/validator/keymanager/local/import.go index 0a41d54ee37f..9d1d27165207 100644 --- a/validator/keymanager/local/import.go +++ b/validator/keymanager/local/import.go @@ -3,13 +3,13 @@ package local import ( "context" "encoding/hex" - "encoding/json" "fmt" "strings" "github.com/k0kubun/go-ansi" "github.com/pkg/errors" "github.com/prysmaticlabs/prysm/v4/crypto/bls" + "github.com/prysmaticlabs/prysm/v4/encoding/bytesutil" ethpbservice "github.com/prysmaticlabs/prysm/v4/proto/eth/service" "github.com/prysmaticlabs/prysm/v4/validator/keymanager" "github.com/schollz/progressbar/v3" @@ -17,6 +17,13 @@ import ( ) // ImportKeystores into the local keymanager from an external source. +// protection history in the database. +// 1) Copy the in memory keystore +// 2) Import the keys into copied in memory keystore +// 3) Save the copy to disk +// 4) Reinitialize account store from disk +// 5) Verify keys are indeed Imported +// 6) Return Statuses func (km *Keymanager) ImportKeystores( ctx context.Context, keystores []*keymanager.Keystore, @@ -33,7 +40,16 @@ func (km *Keymanager) ImportKeystores( keys := map[string]string{} statuses := make([]*ethpbservice.ImportedKeystoreStatus, len(keystores)) var err error - + // 1) Copy the in memory keystore + storeCopy := &accountStore{} + storeCopy.PrivateKeys = bytesutil.SafeCopy2dBytes(km.accountsStore.PrivateKeys) + storeCopy.PublicKeys = bytesutil.SafeCopy2dBytes(km.accountsStore.PublicKeys) + // + totalImported := 0 + existingPubKeys := make(map[string]bool) + for i := 0; i < len(storeCopy.PrivateKeys); i++ { + existingPubKeys[string(storeCopy.PublicKeys[i])] = true + } for i := 0; i < len(keystores); i++ { var privKeyBytes []byte var pubKeyBytes []byte @@ -49,52 +65,69 @@ func (km *Keymanager) ImportKeystores( log.Error(err) } // if key exists prior to being added then output log that duplicate key was found - if _, ok := keys[string(pubKeyBytes)]; ok { + _, isDuplicateInArray := keys[string(pubKeyBytes)] + _, isDuplicateInExisting := existingPubKeys[string(pubKeyBytes)] + if isDuplicateInArray || isDuplicateInExisting { log.Warnf("Duplicate key in import will be ignored: %#x", pubKeyBytes) statuses[i] = ðpbservice.ImportedKeystoreStatus{ Status: ethpbservice.ImportedKeystoreStatus_DUPLICATE, } continue } + keys[string(pubKeyBytes)] = string(privKeyBytes) statuses[i] = ðpbservice.ImportedKeystoreStatus{ Status: ethpbservice.ImportedKeystoreStatus_IMPORTED, } + totalImported++ } - privKeys := make([][]byte, 0) - pubKeys := make([][]byte, 0) - for pubKey, privKey := range keys { - pubKeys = append(pubKeys, []byte(pubKey)) - privKeys = append(privKeys, []byte(privKey)) + if totalImported == 0 { + log.Warn("no keys were imported") + return statuses, nil } - - // Write the accounts to disk into a single keystore. - accountsKeystore, err := km.CreateAccountsKeystore(ctx, privKeys, pubKeys) - if err != nil { - return nil, err + // 2) Import the keys into copied in memory keystore,clear duplicates in existing set + // duplicates,errored ones are already skipped + for pubKey, privKey := range keys { + storeCopy.PublicKeys = append(storeCopy.PublicKeys, []byte(pubKey)) + storeCopy.PrivateKeys = append(storeCopy.PrivateKeys, []byte(privKey)) } - encodedAccounts, err := json.MarshalIndent(accountsKeystore, "", "\t") - if err != nil { + //3 & 4) save to disk and re-initializes keystore + if err := km.SaveStoreAndReInitialize(ctx, storeCopy); err != nil { return nil, err } - if err := km.wallet.WriteFileAtPath(ctx, AccountsPath, AccountsKeystoreFileName, encodedAccounts); err != nil { - return nil, err + // 5) Verify keys are indeed Imported + if len(km.accountsStore.PublicKeys) < len(storeCopy.PublicKeys) { + return nil, fmt.Errorf("keys were not imported successfully, expected %d got %d", len(storeCopy.PublicKeys), len(km.accountsStore.PublicKeys)) } + // + // 6) Return Statuses return statuses, nil } // ImportKeypairs directly into the keymanager. func (km *Keymanager) ImportKeypairs(ctx context.Context, privKeys, pubKeys [][]byte) error { - // Write the accounts to disk into a single keystore. - accountsKeystore, err := km.CreateAccountsKeystore(ctx, privKeys, pubKeys) - if err != nil { - return errors.Wrap(err, "could not import account keypairs") + if len(privKeys) != len(pubKeys) { + return fmt.Errorf( + "number of private keys and public keys is not equal: %d != %d", len(privKeys), len(pubKeys), + ) + } + // 1) Copy the in memory keystore + storeCopy := &accountStore{} + storeCopy.PrivateKeys = bytesutil.SafeCopy2dBytes(km.accountsStore.PrivateKeys) + storeCopy.PublicKeys = bytesutil.SafeCopy2dBytes(km.accountsStore.PublicKeys) + // + // 2) Update store and remove duplicates + updateAccountsStoreInMemory(storeCopy, privKeys, pubKeys) + // + //3 & 4) save to disk and re-initializes keystore + if err := km.SaveStoreAndReInitialize(ctx, storeCopy); err != nil { + return err } - encodedAccounts, err := json.MarshalIndent(accountsKeystore, "", "\t") - if err != nil { - return errors.Wrap(err, "could not marshal accounts keystore into JSON") + // 5) verify if store was not updated + if len(km.accountsStore.PublicKeys) < len(storeCopy.PublicKeys) { + return fmt.Errorf("keys were not imported successfully, expected %d got %d", len(storeCopy.PublicKeys), len(km.accountsStore.PublicKeys)) } - return km.wallet.WriteFileAtPath(ctx, AccountsPath, AccountsKeystoreFileName, encodedAccounts) + return nil } // Retrieves the private key and public key from an EIP-2335 keystore file diff --git a/validator/keymanager/local/import_test.go b/validator/keymanager/local/import_test.go index 18553f9956e7..18b1202e5f6a 100644 --- a/validator/keymanager/local/import_test.go +++ b/validator/keymanager/local/import_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/google/uuid" + "github.com/mohae/deepcopy" "github.com/prysmaticlabs/prysm/v4/crypto/bls" ethpbservice "github.com/prysmaticlabs/prysm/v4/proto/eth/service" "github.com/prysmaticlabs/prysm/v4/testing/assert" @@ -190,4 +191,65 @@ func TestLocalKeymanager_ImportKeystores(t *testing.T) { statuses[2].Message, ) }) + t.Run("All fail or duplicated", func(t *testing.T) { + // First keystore is normal. + keystore1 := createRandomKeystore(t, password) + // First Import successfully + statuses, err := dr.ImportKeystores( + ctx, + []*keymanager.Keystore{keystore1}, + []string{password}, + ) + require.NoError(t, err) + require.Equal(t, len(statuses), 1) + + keystores := make([]*keymanager.Keystore, 0) + passwords := make([]string, 0) + // Second keystore is a duplicate of the first. + keystores = append(keystores, keystore1) + passwords = append(passwords, password) + + // Third keystore has a wrong password. + keystore3 := createRandomKeystore(t, password) + keystores = append(keystores, keystore3) + passwords = append(passwords, "foobar") + + statuses, err = dr.ImportKeystores( + ctx, + keystores, + passwords, + ) + require.NoError(t, err) + require.Equal(t, len(keystores), len(statuses)) + require.Equal( + t, + ethpbservice.ImportedKeystoreStatus_DUPLICATE, + statuses[0].Status, + ) + require.Equal( + t, + ethpbservice.ImportedKeystoreStatus_ERROR, + statuses[1].Status, + ) + require.Equal( + t, + fmt.Sprintf("incorrect password for key 0x%s", keystores[1].Pubkey), + statuses[1].Message, + ) + }) + t.Run("file write fails during import", func(t *testing.T) { + wallet.HasWriteFileError = true + copyStore, ok := deepcopy.Copy(dr.accountsStore).(*accountStore) + require.Equal(t, true, ok) + keystore1 := createRandomKeystore(t, password) + statuses, err := dr.ImportKeystores( + ctx, + []*keymanager.Keystore{keystore1}, + []string{password}, + ) + require.ErrorContains(t, "could not write keystore file for accounts", err) + require.Equal(t, len(statuses), 0) + // local copy did not update due to bad file write + require.DeepEqual(t, dr.accountsStore, copyStore) + }) } diff --git a/validator/keymanager/local/keymanager.go b/validator/keymanager/local/keymanager.go index a6b5ecd0b51d..d538c5caccc0 100644 --- a/validator/keymanager/local/keymanager.go +++ b/validator/keymanager/local/keymanager.go @@ -263,6 +263,26 @@ func (km *Keymanager) CreateAccountsKeystore(ctx context.Context, privateKeys [] return CreateAccountsKeystoreRepresentation(ctx, km.accountsStore, km.wallet.Password()) } +// SaveStoreAndReInitialize saves the store to disk and re-initializes the account keystore from file +func (km *Keymanager) SaveStoreAndReInitialize(ctx context.Context, store *accountStore) error { + // Save the copy to disk + accountsKeystore, err := CreateAccountsKeystoreRepresentation(ctx, store, km.wallet.Password()) + if err != nil { + return err + + } + encodedAccounts, err := json.MarshalIndent(accountsKeystore, "", "\t") + if err != nil { + return err + } + if err := km.wallet.WriteFileAtPath(ctx, AccountsPath, AccountsKeystoreFileName, encodedAccounts); err != nil { + return err + } + // + // Reinitialize account store from disk, updating the local store and cache + return km.initializeAccountKeystore(ctx) +} + // CreateAccountsKeystoreRepresentation is a pure function that takes an accountStore and wallet password and returns the encrypted formatted json version for local writing. func CreateAccountsKeystoreRepresentation( _ context.Context, @@ -292,7 +312,7 @@ func CreateAccountsKeystoreRepresentation( // CreateOrUpdateInMemoryAccountsStore will set or update the local accounts store and update the local cache. // This function DOES NOT save the accounts store to disk. -func (km *Keymanager) CreateOrUpdateInMemoryAccountsStore(_ context.Context, privateKeys [][]byte, publicKeys [][]byte) error { +func (km *Keymanager) CreateOrUpdateInMemoryAccountsStore(_ context.Context, privateKeys, publicKeys [][]byte) error { if len(privateKeys) != len(publicKeys) { return fmt.Errorf( "number of private keys and public keys is not equal: %d != %d", len(privateKeys), len(publicKeys), @@ -304,25 +324,7 @@ func (km *Keymanager) CreateOrUpdateInMemoryAccountsStore(_ context.Context, pri PublicKeys: publicKeys, } } else { - existingPubKeys := make(map[string]bool) - existingPrivKeys := make(map[string]bool) - for i := 0; i < len(km.accountsStore.PrivateKeys); i++ { - existingPrivKeys[string(km.accountsStore.PrivateKeys[i])] = true - existingPubKeys[string(km.accountsStore.PublicKeys[i])] = true - } - // We append to the accounts store keys only - // if the private/secret key do not already exist, to prevent duplicates. - for i := 0; i < len(privateKeys); i++ { - sk := privateKeys[i] - pk := publicKeys[i] - _, privKeyExists := existingPrivKeys[string(sk)] - _, pubKeyExists := existingPubKeys[string(pk)] - if privKeyExists || pubKeyExists { - continue - } - km.accountsStore.PublicKeys = append(km.accountsStore.PublicKeys, pk) - km.accountsStore.PrivateKeys = append(km.accountsStore.PrivateKeys, sk) - } + updateAccountsStoreInMemory(km.accountsStore, privateKeys, publicKeys) } err := km.initializeKeysCachesFromKeystore() if err != nil { @@ -331,6 +333,28 @@ func (km *Keymanager) CreateOrUpdateInMemoryAccountsStore(_ context.Context, pri return nil } +func updateAccountsStoreInMemory(store *accountStore, privateKeys, publicKeys [][]byte) { + existingPubKeys := make(map[string]bool) + existingPrivKeys := make(map[string]bool) + for i := 0; i < len(store.PrivateKeys); i++ { + existingPrivKeys[string(store.PrivateKeys[i])] = true + existingPubKeys[string(store.PublicKeys[i])] = true + } + // We append to the accounts store keys only + // if the private/secret key do not already exist, to prevent duplicates. + for i := 0; i < len(privateKeys); i++ { + sk := privateKeys[i] + pk := publicKeys[i] + _, privKeyExists := existingPrivKeys[string(sk)] + _, pubKeyExists := existingPubKeys[string(pk)] + if privKeyExists || pubKeyExists { + continue + } + store.PublicKeys = append(store.PublicKeys, pk) + store.PrivateKeys = append(store.PrivateKeys, sk) + } +} + func (km *Keymanager) ListKeymanagerAccounts(ctx context.Context, cfg keymanager.ListKeymanagerAccountConfig) error { au := aurora.NewAurora(true) // We initialize the wallet's keymanager. From 62bc302bc5f2774f4c7aa95fabe8cbf428404730 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Fri, 14 Apr 2023 21:55:20 -0500 Subject: [PATCH 08/22] making accountStore copy method part of struct --- validator/keymanager/local/BUILD.bazel | 1 - validator/keymanager/local/delete.go | 4 +--- validator/keymanager/local/delete_test.go | 4 +--- validator/keymanager/local/import.go | 9 ++------- validator/keymanager/local/import_test.go | 4 +--- validator/keymanager/local/keymanager.go | 8 ++++++++ 6 files changed, 13 insertions(+), 17 deletions(-) diff --git a/validator/keymanager/local/BUILD.bazel b/validator/keymanager/local/BUILD.bazel index e2ad4b832ec5..779dcc5a5f92 100644 --- a/validator/keymanager/local/BUILD.bazel +++ b/validator/keymanager/local/BUILD.bazel @@ -67,7 +67,6 @@ go_test( "//validator/accounts/testing:go_default_library", "//validator/keymanager:go_default_library", "@com_github_google_uuid//:go_default_library", - "@com_github_mohae_deepcopy//:go_default_library", "@com_github_sirupsen_logrus//hooks/test:go_default_library", "@com_github_wealdtech_go_eth2_wallet_encryptor_keystorev4//:go_default_library", ], diff --git a/validator/keymanager/local/delete.go b/validator/keymanager/local/delete.go index 2860f015e9d3..243919e7ad6e 100644 --- a/validator/keymanager/local/delete.go +++ b/validator/keymanager/local/delete.go @@ -30,9 +30,7 @@ func (km *Keymanager) DeleteKeystores( deletedKeys := make([][]byte, 0, len(publicKeys)) originalKeyLen := len(km.accountsStore.PublicKeys) // 1) Copy the in memory keystore - storeCopy := &accountStore{} - storeCopy.PrivateKeys = bytesutil.SafeCopy2dBytes(km.accountsStore.PrivateKeys) - storeCopy.PublicKeys = bytesutil.SafeCopy2dBytes(km.accountsStore.PublicKeys) + storeCopy := km.accountsStore.Copy() // for _, publicKey := range publicKeys { // Check if the key in the request is a duplicate or not found diff --git a/validator/keymanager/local/delete_test.go b/validator/keymanager/local/delete_test.go index d130b3c5362c..978a0aa8b4c7 100644 --- a/validator/keymanager/local/delete_test.go +++ b/validator/keymanager/local/delete_test.go @@ -7,7 +7,6 @@ import ( "strings" "testing" - "github.com/mohae/deepcopy" fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams" "github.com/prysmaticlabs/prysm/v4/encoding/bytesutil" ethpbservice "github.com/prysmaticlabs/prysm/v4/proto/eth/service" @@ -56,8 +55,7 @@ func TestLocalKeymanager_DeleteKeystores(t *testing.T) { accountToRemove := uint64(2) accountPubKey := accounts[accountToRemove] require.NotEqual(t, len(dr.accountsStore.PublicKeys), 0) - copyStore, ok := deepcopy.Copy(dr.accountsStore).(*accountStore) - require.Equal(t, true, ok) + copyStore := dr.accountsStore.Copy() statuses, err := dr.DeleteKeystores(ctx, [][]byte{accountPubKey[:]}) require.ErrorContains(t, "could not write keystore file for accounts", err) require.Equal(t, len(statuses), 0) diff --git a/validator/keymanager/local/import.go b/validator/keymanager/local/import.go index 9d1d27165207..2fbcfaf46a85 100644 --- a/validator/keymanager/local/import.go +++ b/validator/keymanager/local/import.go @@ -9,7 +9,6 @@ import ( "github.com/k0kubun/go-ansi" "github.com/pkg/errors" "github.com/prysmaticlabs/prysm/v4/crypto/bls" - "github.com/prysmaticlabs/prysm/v4/encoding/bytesutil" ethpbservice "github.com/prysmaticlabs/prysm/v4/proto/eth/service" "github.com/prysmaticlabs/prysm/v4/validator/keymanager" "github.com/schollz/progressbar/v3" @@ -41,9 +40,7 @@ func (km *Keymanager) ImportKeystores( statuses := make([]*ethpbservice.ImportedKeystoreStatus, len(keystores)) var err error // 1) Copy the in memory keystore - storeCopy := &accountStore{} - storeCopy.PrivateKeys = bytesutil.SafeCopy2dBytes(km.accountsStore.PrivateKeys) - storeCopy.PublicKeys = bytesutil.SafeCopy2dBytes(km.accountsStore.PublicKeys) + storeCopy := km.accountsStore.Copy() // totalImported := 0 existingPubKeys := make(map[string]bool) @@ -112,9 +109,7 @@ func (km *Keymanager) ImportKeypairs(ctx context.Context, privKeys, pubKeys [][] ) } // 1) Copy the in memory keystore - storeCopy := &accountStore{} - storeCopy.PrivateKeys = bytesutil.SafeCopy2dBytes(km.accountsStore.PrivateKeys) - storeCopy.PublicKeys = bytesutil.SafeCopy2dBytes(km.accountsStore.PublicKeys) + storeCopy := km.accountsStore.Copy() // // 2) Update store and remove duplicates updateAccountsStoreInMemory(storeCopy, privKeys, pubKeys) diff --git a/validator/keymanager/local/import_test.go b/validator/keymanager/local/import_test.go index 18b1202e5f6a..d01e78948826 100644 --- a/validator/keymanager/local/import_test.go +++ b/validator/keymanager/local/import_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/google/uuid" - "github.com/mohae/deepcopy" "github.com/prysmaticlabs/prysm/v4/crypto/bls" ethpbservice "github.com/prysmaticlabs/prysm/v4/proto/eth/service" "github.com/prysmaticlabs/prysm/v4/testing/assert" @@ -239,8 +238,7 @@ func TestLocalKeymanager_ImportKeystores(t *testing.T) { }) t.Run("file write fails during import", func(t *testing.T) { wallet.HasWriteFileError = true - copyStore, ok := deepcopy.Copy(dr.accountsStore).(*accountStore) - require.Equal(t, true, ok) + copyStore := dr.accountsStore.Copy() keystore1 := createRandomKeystore(t, password) statuses, err := dr.ImportKeystores( ctx, diff --git a/validator/keymanager/local/keymanager.go b/validator/keymanager/local/keymanager.go index d538c5caccc0..59e7c65d3bd7 100644 --- a/validator/keymanager/local/keymanager.go +++ b/validator/keymanager/local/keymanager.go @@ -59,6 +59,14 @@ type accountStore struct { PublicKeys [][]byte `json:"public_keys"` } +// Copy creates a deep copy of accountStore +func (a *accountStore) Copy() *accountStore { + storeCopy := &accountStore{} + storeCopy.PrivateKeys = bytesutil.SafeCopy2dBytes(a.PrivateKeys) + storeCopy.PublicKeys = bytesutil.SafeCopy2dBytes(a.PublicKeys) + return storeCopy +} + // AccountsKeystoreRepresentation defines an internal Prysm representation // of validator accounts, encrypted according to the EIP-2334 standard. type AccountsKeystoreRepresentation struct { From 50e618569418a9c43cc8cc0c4c3c20a503a86999 Mon Sep 17 00:00:00 2001 From: Raul Jordan Date: Sat, 15 Apr 2023 21:47:51 -0400 Subject: [PATCH 09/22] Update validator/keymanager/local/delete_test.go --- validator/keymanager/local/delete_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/validator/keymanager/local/delete_test.go b/validator/keymanager/local/delete_test.go index 978a0aa8b4c7..d4bf16703ba8 100644 --- a/validator/keymanager/local/delete_test.go +++ b/validator/keymanager/local/delete_test.go @@ -96,7 +96,6 @@ func TestLocalKeymanager_DeleteKeystores(t *testing.T) { }) t.Run("returns NOT_ACTIVE status for duplicate public key in request", func(t *testing.T) { - fmt.Println(wallet.HasWriteFileError) accountToRemove := uint64(3) accountPubKey := accounts[accountToRemove] statuses, err := dr.DeleteKeystores(ctx, [][]byte{ From eb1d5d2283845232f5bfbfde108d691fee067fac Mon Sep 17 00:00:00 2001 From: Raul Jordan Date: Sat, 15 Apr 2023 21:47:57 -0400 Subject: [PATCH 10/22] Update validator/keymanager/local/delete.go --- validator/keymanager/local/delete.go | 1 - 1 file changed, 1 deletion(-) diff --git a/validator/keymanager/local/delete.go b/validator/keymanager/local/delete.go index 243919e7ad6e..a32bfc28fec5 100644 --- a/validator/keymanager/local/delete.go +++ b/validator/keymanager/local/delete.go @@ -31,7 +31,6 @@ func (km *Keymanager) DeleteKeystores( originalKeyLen := len(km.accountsStore.PublicKeys) // 1) Copy the in memory keystore storeCopy := km.accountsStore.Copy() - // for _, publicKey := range publicKeys { // Check if the key in the request is a duplicate or not found if _, ok := trackedPublicKeys[bytesutil.ToBytes48(publicKey)]; ok { From f8fedf8947aca01c9e9a5fe258c8f045b947fd47 Mon Sep 17 00:00:00 2001 From: james-prysm <90280386+james-prysm@users.noreply.github.com> Date: Sun, 16 Apr 2023 20:31:18 -0500 Subject: [PATCH 11/22] Update validator/keymanager/local/delete.go Co-authored-by: Preston Van Loon --- validator/keymanager/local/delete.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validator/keymanager/local/delete.go b/validator/keymanager/local/delete.go index a32bfc28fec5..ed86d0b27cf7 100644 --- a/validator/keymanager/local/delete.go +++ b/validator/keymanager/local/delete.go @@ -73,12 +73,12 @@ func (km *Keymanager) DeleteKeystores( if err := km.SaveStoreAndReInitialize(ctx, storeCopy); err != nil { return nil, err } - // + // 5) Verify keys are indeed deleted if len(km.accountsStore.PublicKeys) == originalKeyLen || len(km.accountsStore.PublicKeys) != len(storeCopy.PublicKeys) { return nil, errors.New("keys were not successfully deleted in file") } - // + var deletedKeysStr string for i, k := range deletedKeys { if i == 0 { From c901df6294c4ea874addf60fcbb29204f6ffc72f Mon Sep 17 00:00:00 2001 From: james-prysm <90280386+james-prysm@users.noreply.github.com> Date: Sun, 16 Apr 2023 20:31:24 -0500 Subject: [PATCH 12/22] Update validator/keymanager/local/import.go Co-authored-by: Preston Van Loon --- validator/keymanager/local/import.go | 1 - 1 file changed, 1 deletion(-) diff --git a/validator/keymanager/local/import.go b/validator/keymanager/local/import.go index 2fbcfaf46a85..641f47fdfea2 100644 --- a/validator/keymanager/local/import.go +++ b/validator/keymanager/local/import.go @@ -41,7 +41,6 @@ func (km *Keymanager) ImportKeystores( var err error // 1) Copy the in memory keystore storeCopy := km.accountsStore.Copy() - // totalImported := 0 existingPubKeys := make(map[string]bool) for i := 0; i < len(storeCopy.PrivateKeys); i++ { From 1fc1f209731f733b790ee62694ab92de52596ea7 Mon Sep 17 00:00:00 2001 From: james-prysm <90280386+james-prysm@users.noreply.github.com> Date: Sun, 16 Apr 2023 20:31:31 -0500 Subject: [PATCH 13/22] Update validator/keymanager/local/delete.go Co-authored-by: Preston Van Loon --- validator/keymanager/local/delete.go | 1 - 1 file changed, 1 deletion(-) diff --git a/validator/keymanager/local/delete.go b/validator/keymanager/local/delete.go index ed86d0b27cf7..556a2295b3d2 100644 --- a/validator/keymanager/local/delete.go +++ b/validator/keymanager/local/delete.go @@ -64,7 +64,6 @@ func (km *Keymanager) DeleteKeystores( Status: ethpbservice.DeletedKeystoreStatus_DELETED, }) trackedPublicKeys[bytesutil.ToBytes48(publicKey)] = true - // } if len(deletedKeys) == 0 { return statuses, nil From fd31c6ffec00c6e7f987c926626180052e8cacb3 Mon Sep 17 00:00:00 2001 From: james-prysm <90280386+james-prysm@users.noreply.github.com> Date: Sun, 16 Apr 2023 20:31:39 -0500 Subject: [PATCH 14/22] Update validator/keymanager/local/delete.go Co-authored-by: Preston Van Loon --- validator/keymanager/local/delete.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validator/keymanager/local/delete.go b/validator/keymanager/local/delete.go index 556a2295b3d2..993d335e25cb 100644 --- a/validator/keymanager/local/delete.go +++ b/validator/keymanager/local/delete.go @@ -68,7 +68,7 @@ func (km *Keymanager) DeleteKeystores( if len(deletedKeys) == 0 { return statuses, nil } - //3 & 4) save to disk and re-initializes keystore + // 3 & 4) save to disk and re-initializes keystore if err := km.SaveStoreAndReInitialize(ctx, storeCopy); err != nil { return nil, err } From 480759522e5c00649836e141cd0f11f6ccd214df Mon Sep 17 00:00:00 2001 From: james-prysm <90280386+james-prysm@users.noreply.github.com> Date: Sun, 16 Apr 2023 20:31:47 -0500 Subject: [PATCH 15/22] Update validator/keymanager/local/import.go Co-authored-by: Preston Van Loon --- validator/keymanager/local/import.go | 1 - 1 file changed, 1 deletion(-) diff --git a/validator/keymanager/local/import.go b/validator/keymanager/local/import.go index 641f47fdfea2..12b8a56b92fe 100644 --- a/validator/keymanager/local/import.go +++ b/validator/keymanager/local/import.go @@ -95,7 +95,6 @@ func (km *Keymanager) ImportKeystores( if len(km.accountsStore.PublicKeys) < len(storeCopy.PublicKeys) { return nil, fmt.Errorf("keys were not imported successfully, expected %d got %d", len(storeCopy.PublicKeys), len(km.accountsStore.PublicKeys)) } - // // 6) Return Statuses return statuses, nil } From 5e52c8c443cd72b36ff4c439c86768806031f321 Mon Sep 17 00:00:00 2001 From: james-prysm <90280386+james-prysm@users.noreply.github.com> Date: Sun, 16 Apr 2023 20:31:52 -0500 Subject: [PATCH 16/22] Update validator/keymanager/local/import.go Co-authored-by: Preston Van Loon --- validator/keymanager/local/import.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validator/keymanager/local/import.go b/validator/keymanager/local/import.go index 12b8a56b92fe..05d2268e8bb2 100644 --- a/validator/keymanager/local/import.go +++ b/validator/keymanager/local/import.go @@ -108,11 +108,11 @@ func (km *Keymanager) ImportKeypairs(ctx context.Context, privKeys, pubKeys [][] } // 1) Copy the in memory keystore storeCopy := km.accountsStore.Copy() - // + // 2) Update store and remove duplicates updateAccountsStoreInMemory(storeCopy, privKeys, pubKeys) - // - //3 & 4) save to disk and re-initializes keystore + + // 3 & 4) save to disk and re-initializes keystore if err := km.SaveStoreAndReInitialize(ctx, storeCopy); err != nil { return err } From fde491ccacf8842ea725037af2d799cacaa0e924 Mon Sep 17 00:00:00 2001 From: james-prysm <90280386+james-prysm@users.noreply.github.com> Date: Sun, 16 Apr 2023 20:31:59 -0500 Subject: [PATCH 17/22] Update validator/keymanager/local/delete.go Co-authored-by: Preston Van Loon --- validator/keymanager/local/delete.go | 1 - 1 file changed, 1 deletion(-) diff --git a/validator/keymanager/local/delete.go b/validator/keymanager/local/delete.go index 993d335e25cb..6237b150ceca 100644 --- a/validator/keymanager/local/delete.go +++ b/validator/keymanager/local/delete.go @@ -54,7 +54,6 @@ func (km *Keymanager) DeleteKeystores( }) continue } - // // 2) Delete the keys from copied in memory keystore deletedPublicKey := storeCopy.PublicKeys[index] deletedKeys = append(deletedKeys, deletedPublicKey) From 11977374b74e592802c4ee44195576f544574e37 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Sun, 16 Apr 2023 20:44:25 -0500 Subject: [PATCH 18/22] addressing suggestion of not reinitializing from reading the file but instead update the information based on memory on hand --- validator/keymanager/local/delete.go | 2 +- validator/keymanager/local/import.go | 3 +-- validator/keymanager/local/keymanager.go | 9 +++++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/validator/keymanager/local/delete.go b/validator/keymanager/local/delete.go index 6237b150ceca..108fb3e8226e 100644 --- a/validator/keymanager/local/delete.go +++ b/validator/keymanager/local/delete.go @@ -18,7 +18,7 @@ import ( // 1) Copy the in memory keystore // 2) Delete the keys from copied in memory keystore // 3) Save the copy to disk -// 4) Reinitialize account store from disk +// 4) Reinitialize account store // 5) Verify keys are indeed deleted // 6) Return API response func (km *Keymanager) DeleteKeystores( diff --git a/validator/keymanager/local/import.go b/validator/keymanager/local/import.go index 05d2268e8bb2..41fcea03d3a5 100644 --- a/validator/keymanager/local/import.go +++ b/validator/keymanager/local/import.go @@ -16,11 +16,10 @@ import ( ) // ImportKeystores into the local keymanager from an external source. -// protection history in the database. // 1) Copy the in memory keystore // 2) Import the keys into copied in memory keystore // 3) Save the copy to disk -// 4) Reinitialize account store from disk +// 4) Reinitialize account store // 5) Verify keys are indeed Imported // 6) Return Statuses func (km *Keymanager) ImportKeystores( diff --git a/validator/keymanager/local/keymanager.go b/validator/keymanager/local/keymanager.go index 59e7c65d3bd7..c172167c655e 100644 --- a/validator/keymanager/local/keymanager.go +++ b/validator/keymanager/local/keymanager.go @@ -287,8 +287,13 @@ func (km *Keymanager) SaveStoreAndReInitialize(ctx context.Context, store *accou return err } // - // Reinitialize account store from disk, updating the local store and cache - return km.initializeAccountKeystore(ctx) + // Reinitialize account store and cache + km.accountsStore = store + err = km.initializeKeysCachesFromKeystore() + if err != nil { + return errors.Wrap(err, "failed to initialize keys caches") + } + return err } // CreateAccountsKeystoreRepresentation is a pure function that takes an accountStore and wallet password and returns the encrypted formatted json version for local writing. From 5bafd3688fb81ef9891661eb561bf947d00cc944 Mon Sep 17 00:00:00 2001 From: james-prysm <90280386+james-prysm@users.noreply.github.com> Date: Sun, 16 Apr 2023 20:55:12 -0500 Subject: [PATCH 19/22] Update validator/accounts/wallet_create.go Co-authored-by: Preston Van Loon --- validator/accounts/wallet_create.go | 1 - 1 file changed, 1 deletion(-) diff --git a/validator/accounts/wallet_create.go b/validator/accounts/wallet_create.go index c53e7cf3c37b..703f4364d61d 100644 --- a/validator/accounts/wallet_create.go +++ b/validator/accounts/wallet_create.go @@ -34,7 +34,6 @@ func (acm *AccountsCLIManager) WalletCreate(ctx context.Context) (*wallet.Wallet if !ok { return nil, errors.Wrap(err, ErrCouldNotInitializeKeymanager) } - accountsKeystore, err := localKm.CreateAccountsKeystore(ctx, make([][]byte, 0), make([][]byte, 0)) if err != nil { return nil, err From 4eab5329e0827649425eb8b5b7fd12c5b9507ee9 Mon Sep 17 00:00:00 2001 From: james-prysm Date: Mon, 17 Apr 2023 09:43:31 -0500 Subject: [PATCH 20/22] adding changes based on suggestions --- validator/keymanager/local/delete.go | 12 ++---------- validator/keymanager/local/import.go | 11 +++-------- validator/keymanager/local/keymanager.go | 7 ++++--- 3 files changed, 9 insertions(+), 21 deletions(-) diff --git a/validator/keymanager/local/delete.go b/validator/keymanager/local/delete.go index 108fb3e8226e..6c047c2faef1 100644 --- a/validator/keymanager/local/delete.go +++ b/validator/keymanager/local/delete.go @@ -5,7 +5,6 @@ import ( "context" "fmt" - "github.com/pkg/errors" fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams" "github.com/prysmaticlabs/prysm/v4/encoding/bytesutil" ethpbservice "github.com/prysmaticlabs/prysm/v4/proto/eth/service" @@ -19,8 +18,7 @@ import ( // 2) Delete the keys from copied in memory keystore // 3) Save the copy to disk // 4) Reinitialize account store -// 5) Verify keys are indeed deleted -// 6) Return API response +// 5) Return API response func (km *Keymanager) DeleteKeystores( ctx context.Context, publicKeys [][]byte, ) ([]*ethpbservice.DeletedKeystoreStatus, error) { @@ -28,7 +26,6 @@ func (km *Keymanager) DeleteKeystores( trackedPublicKeys := make(map[[fieldparams.BLSPubkeyLength]byte]bool) statuses := make([]*ethpbservice.DeletedKeystoreStatus, 0, len(publicKeys)) deletedKeys := make([][]byte, 0, len(publicKeys)) - originalKeyLen := len(km.accountsStore.PublicKeys) // 1) Copy the in memory keystore storeCopy := km.accountsStore.Copy() for _, publicKey := range publicKeys { @@ -72,11 +69,6 @@ func (km *Keymanager) DeleteKeystores( return nil, err } - // 5) Verify keys are indeed deleted - if len(km.accountsStore.PublicKeys) == originalKeyLen || len(km.accountsStore.PublicKeys) != len(storeCopy.PublicKeys) { - return nil, errors.New("keys were not successfully deleted in file") - } - var deletedKeysStr string for i, k := range deletedKeys { if i == 0 { @@ -90,6 +82,6 @@ func (km *Keymanager) DeleteKeystores( log.WithFields(logrus.Fields{ "publicKeys": deletedKeysStr, }).Info("Successfully deleted validator key(s)") - // 6) Return API response + // 5) Return API response return statuses, nil } diff --git a/validator/keymanager/local/import.go b/validator/keymanager/local/import.go index 41fcea03d3a5..74897ad03bf7 100644 --- a/validator/keymanager/local/import.go +++ b/validator/keymanager/local/import.go @@ -20,8 +20,7 @@ import ( // 2) Import the keys into copied in memory keystore // 3) Save the copy to disk // 4) Reinitialize account store -// 5) Verify keys are indeed Imported -// 6) Return Statuses +// 5) Return Statuses func (km *Keymanager) ImportKeystores( ctx context.Context, keystores []*keymanager.Keystore, @@ -90,11 +89,7 @@ func (km *Keymanager) ImportKeystores( if err := km.SaveStoreAndReInitialize(ctx, storeCopy); err != nil { return nil, err } - // 5) Verify keys are indeed Imported - if len(km.accountsStore.PublicKeys) < len(storeCopy.PublicKeys) { - return nil, fmt.Errorf("keys were not imported successfully, expected %d got %d", len(storeCopy.PublicKeys), len(km.accountsStore.PublicKeys)) - } - // 6) Return Statuses + // 5) Return Statuses return statuses, nil } @@ -109,7 +104,7 @@ func (km *Keymanager) ImportKeypairs(ctx context.Context, privKeys, pubKeys [][] storeCopy := km.accountsStore.Copy() // 2) Update store and remove duplicates - updateAccountsStoreInMemory(storeCopy, privKeys, pubKeys) + updateAccountsStoreKeys(storeCopy, privKeys, pubKeys) // 3 & 4) save to disk and re-initializes keystore if err := km.SaveStoreAndReInitialize(ctx, storeCopy); err != nil { diff --git a/validator/keymanager/local/keymanager.go b/validator/keymanager/local/keymanager.go index c172167c655e..3773bb55a933 100644 --- a/validator/keymanager/local/keymanager.go +++ b/validator/keymanager/local/keymanager.go @@ -286,8 +286,9 @@ func (km *Keymanager) SaveStoreAndReInitialize(ctx context.Context, store *accou if err := km.wallet.WriteFileAtPath(ctx, AccountsPath, AccountsKeystoreFileName, encodedAccounts); err != nil { return err } - // + // Reinitialize account store and cache + // This will update the in-memory information instead of reading from the file itself for safety concerns km.accountsStore = store err = km.initializeKeysCachesFromKeystore() if err != nil { @@ -337,7 +338,7 @@ func (km *Keymanager) CreateOrUpdateInMemoryAccountsStore(_ context.Context, pri PublicKeys: publicKeys, } } else { - updateAccountsStoreInMemory(km.accountsStore, privateKeys, publicKeys) + updateAccountsStoreKeys(km.accountsStore, privateKeys, publicKeys) } err := km.initializeKeysCachesFromKeystore() if err != nil { @@ -346,7 +347,7 @@ func (km *Keymanager) CreateOrUpdateInMemoryAccountsStore(_ context.Context, pri return nil } -func updateAccountsStoreInMemory(store *accountStore, privateKeys, publicKeys [][]byte) { +func updateAccountsStoreKeys(store *accountStore, privateKeys, publicKeys [][]byte) { existingPubKeys := make(map[string]bool) existingPrivKeys := make(map[string]bool) for i := 0; i < len(store.PrivateKeys); i++ { From 701805fe67b18bbb54fd7ffc84a50e24d8bed86a Mon Sep 17 00:00:00 2001 From: james-prysm Date: Mon, 17 Apr 2023 10:36:21 -0500 Subject: [PATCH 21/22] making logs more consistent --- validator/keymanager/local/delete.go | 15 ++------------- validator/keymanager/local/import.go | 18 ++++++++++++------ validator/keymanager/local/import_test.go | 11 +++++++++++ validator/keymanager/local/keymanager.go | 14 ++++++++++++++ 4 files changed, 39 insertions(+), 19 deletions(-) diff --git a/validator/keymanager/local/delete.go b/validator/keymanager/local/delete.go index 6c047c2faef1..028961e985b8 100644 --- a/validator/keymanager/local/delete.go +++ b/validator/keymanager/local/delete.go @@ -3,7 +3,6 @@ package local import ( "bytes" "context" - "fmt" fieldparams "github.com/prysmaticlabs/prysm/v4/config/fieldparams" "github.com/prysmaticlabs/prysm/v4/encoding/bytesutil" @@ -17,7 +16,7 @@ import ( // 1) Copy the in memory keystore // 2) Delete the keys from copied in memory keystore // 3) Save the copy to disk -// 4) Reinitialize account store +// 4) Reinitialize account store and updating the keymanager // 5) Return API response func (km *Keymanager) DeleteKeystores( ctx context.Context, publicKeys [][]byte, @@ -69,18 +68,8 @@ func (km *Keymanager) DeleteKeystores( return nil, err } - var deletedKeysStr string - for i, k := range deletedKeys { - if i == 0 { - deletedKeysStr += fmt.Sprintf("%#x", bytesutil.Trunc(k)) - } else if i == len(deletedKeys)-1 { - deletedKeysStr += fmt.Sprintf("%#x", bytesutil.Trunc(k)) - } else { - deletedKeysStr += fmt.Sprintf(",%#x", bytesutil.Trunc(k)) - } - } log.WithFields(logrus.Fields{ - "publicKeys": deletedKeysStr, + "publicKeys": CreatePrintoutOfKeys(deletedKeys), }).Info("Successfully deleted validator key(s)") // 5) Return API response return statuses, nil diff --git a/validator/keymanager/local/import.go b/validator/keymanager/local/import.go index 74897ad03bf7..e68c2d90d599 100644 --- a/validator/keymanager/local/import.go +++ b/validator/keymanager/local/import.go @@ -12,14 +12,15 @@ import ( ethpbservice "github.com/prysmaticlabs/prysm/v4/proto/eth/service" "github.com/prysmaticlabs/prysm/v4/validator/keymanager" "github.com/schollz/progressbar/v3" + "github.com/sirupsen/logrus" keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4" ) // ImportKeystores into the local keymanager from an external source. // 1) Copy the in memory keystore -// 2) Import the keys into copied in memory keystore +// 2) Update copied keystore with new keys // 3) Save the copy to disk -// 4) Reinitialize account store +// 4) Reinitialize account store and updating the keymanager // 5) Return Statuses func (km *Keymanager) ImportKeystores( ctx context.Context, @@ -39,7 +40,7 @@ func (km *Keymanager) ImportKeystores( var err error // 1) Copy the in memory keystore storeCopy := km.accountsStore.Copy() - totalImported := 0 + importedKeys := make([][]byte, 0) existingPubKeys := make(map[string]bool) for i := 0; i < len(storeCopy.PrivateKeys); i++ { existingPubKeys[string(storeCopy.PublicKeys[i])] = true @@ -70,16 +71,16 @@ func (km *Keymanager) ImportKeystores( } keys[string(pubKeyBytes)] = string(privKeyBytes) + importedKeys = append(importedKeys, pubKeyBytes) statuses[i] = ðpbservice.ImportedKeystoreStatus{ Status: ethpbservice.ImportedKeystoreStatus_IMPORTED, } - totalImported++ } - if totalImported == 0 { + if len(importedKeys) == 0 { log.Warn("no keys were imported") return statuses, nil } - // 2) Import the keys into copied in memory keystore,clear duplicates in existing set + // 2) Update copied keystore with new keys,clear duplicates in existing set // duplicates,errored ones are already skipped for pubKey, privKey := range keys { storeCopy.PublicKeys = append(storeCopy.PublicKeys, []byte(pubKey)) @@ -89,6 +90,11 @@ func (km *Keymanager) ImportKeystores( if err := km.SaveStoreAndReInitialize(ctx, storeCopy); err != nil { return nil, err } + + log.WithFields(logrus.Fields{ + "publicKeys": CreatePrintoutOfKeys(importedKeys), + }).Info("Successfully imported validator key(s)") + // 5) Return Statuses return statuses, nil } diff --git a/validator/keymanager/local/import_test.go b/validator/keymanager/local/import_test.go index d01e78948826..89c938fbdba4 100644 --- a/validator/keymanager/local/import_test.go +++ b/validator/keymanager/local/import_test.go @@ -6,13 +6,16 @@ import ( "strconv" "testing" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/google/uuid" "github.com/prysmaticlabs/prysm/v4/crypto/bls" + "github.com/prysmaticlabs/prysm/v4/encoding/bytesutil" ethpbservice "github.com/prysmaticlabs/prysm/v4/proto/eth/service" "github.com/prysmaticlabs/prysm/v4/testing/assert" "github.com/prysmaticlabs/prysm/v4/testing/require" mock "github.com/prysmaticlabs/prysm/v4/validator/accounts/testing" "github.com/prysmaticlabs/prysm/v4/validator/keymanager" + logTest "github.com/sirupsen/logrus/hooks/test" keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4" ) @@ -94,6 +97,7 @@ func TestLocalKeymanager_NoDuplicates(t *testing.T) { } func TestLocalKeymanager_ImportKeystores(t *testing.T) { + hook := logTest.NewGlobal() ctx := context.Background() // Setup the keymanager. wallet := &mock.Wallet{ @@ -123,6 +127,7 @@ func TestLocalKeymanager_ImportKeystores(t *testing.T) { for _, status := range statuses { require.Equal(t, ethpbservice.ImportedKeystoreStatus_IMPORTED, status.Status) } + require.LogsContain(t, hook, "Successfully imported validator key(s)") }) t.Run("each imported keystore with a different password succeeds", func(t *testing.T) { numKeystores := 5 @@ -143,6 +148,7 @@ func TestLocalKeymanager_ImportKeystores(t *testing.T) { for _, status := range statuses { require.Equal(t, ethpbservice.ImportedKeystoreStatus_IMPORTED, status.Status) } + require.LogsContain(t, hook, "Successfully imported validator key(s)") }) t.Run("some succeed, some fail to decrypt, some duplicated", func(t *testing.T) { keystores := make([]*keymanager.Keystore, 0) @@ -189,6 +195,10 @@ func TestLocalKeymanager_ImportKeystores(t *testing.T) { fmt.Sprintf("incorrect password for key 0x%s", keystores[2].Pubkey), statuses[2].Message, ) + b, err := hexutil.Decode("0x" + keystore1.Pubkey) + require.NoError(t, err) + require.LogsContain(t, hook, fmt.Sprintf("%#x", bytesutil.Trunc(b))) + require.LogsContain(t, hook, "Successfully imported validator key(s)") }) t.Run("All fail or duplicated", func(t *testing.T) { // First keystore is normal. @@ -235,6 +245,7 @@ func TestLocalKeymanager_ImportKeystores(t *testing.T) { fmt.Sprintf("incorrect password for key 0x%s", keystores[1].Pubkey), statuses[1].Message, ) + require.LogsContain(t, hook, "no keys were imported") }) t.Run("file write fails during import", func(t *testing.T) { wallet.HasWriteFileError = true diff --git a/validator/keymanager/local/keymanager.go b/validator/keymanager/local/keymanager.go index 3773bb55a933..5f870003f66b 100644 --- a/validator/keymanager/local/keymanager.go +++ b/validator/keymanager/local/keymanager.go @@ -422,3 +422,17 @@ func (km *Keymanager) ListKeymanagerAccounts(ctx context.Context, cfg keymanager fmt.Println("") return nil } + +func CreatePrintoutOfKeys(keys [][]byte) string { + var keysStr string + for i, k := range keys { + if i == 0 { + keysStr += fmt.Sprintf("%#x", bytesutil.Trunc(k)) + } else if i == len(keys)-1 { + keysStr += fmt.Sprintf("%#x", bytesutil.Trunc(k)) + } else { + keysStr += fmt.Sprintf(",%#x", bytesutil.Trunc(k)) + } + } + return keysStr +} From 7cc67f99f0f0a429451539fde5ddc0d9283e34aa Mon Sep 17 00:00:00 2001 From: james-prysm Date: Mon, 17 Apr 2023 10:48:34 -0500 Subject: [PATCH 22/22] fixing linting --- validator/keymanager/local/BUILD.bazel | 1 + 1 file changed, 1 insertion(+) diff --git a/validator/keymanager/local/BUILD.bazel b/validator/keymanager/local/BUILD.bazel index 779dcc5a5f92..d06b41cac2c8 100644 --- a/validator/keymanager/local/BUILD.bazel +++ b/validator/keymanager/local/BUILD.bazel @@ -66,6 +66,7 @@ go_test( "//testing/require:go_default_library", "//validator/accounts/testing:go_default_library", "//validator/keymanager:go_default_library", + "@com_github_ethereum_go_ethereum//common/hexutil:go_default_library", "@com_github_google_uuid//:go_default_library", "@com_github_sirupsen_logrus//hooks/test:go_default_library", "@com_github_wealdtech_go_eth2_wallet_encryptor_keystorev4//:go_default_library",