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

     1  package imported
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  	"strings"
     9  	"sync"
    10  
    11  	"github.com/google/uuid"
    12  	"github.com/pkg/errors"
    13  	validatorpb "github.com/prysmaticlabs/prysm/proto/validator/accounts/v2"
    14  	"github.com/prysmaticlabs/prysm/shared/bls"
    15  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    16  	"github.com/prysmaticlabs/prysm/shared/event"
    17  	"github.com/prysmaticlabs/prysm/shared/interop"
    18  	"github.com/prysmaticlabs/prysm/shared/petnames"
    19  	"github.com/prysmaticlabs/prysm/validator/accounts/iface"
    20  	"github.com/sirupsen/logrus"
    21  	keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
    22  	"go.opencensus.io/trace"
    23  )
    24  
    25  var (
    26  	lock              sync.RWMutex
    27  	orderedPublicKeys = make([][48]byte, 0)
    28  	secretKeysCache   = make(map[[48]byte]bls.SecretKey)
    29  )
    30  
    31  const (
    32  	// KeystoreFileNameFormat exposes the filename the keystore should be formatted in.
    33  	KeystoreFileNameFormat = "keystore-%d.json"
    34  	// AccountsPath where all imported keymanager keystores are kept.
    35  	AccountsPath = "accounts"
    36  	// AccountsKeystoreFileName exposes the name of the keystore file.
    37  	AccountsKeystoreFileName = "all-accounts.keystore.json"
    38  )
    39  
    40  // Keymanager implementation for imported keystores utilizing EIP-2335.
    41  type Keymanager struct {
    42  	wallet              iface.Wallet
    43  	accountsStore       *accountStore
    44  	accountsChangedFeed *event.Feed
    45  }
    46  
    47  // SetupConfig includes configuration values for initializing
    48  // a keymanager, such as passwords, the wallet, and more.
    49  type SetupConfig struct {
    50  	Wallet           iface.Wallet
    51  	ListenForChanges bool
    52  }
    53  
    54  // Defines a struct containing 1-to-1 corresponding
    55  // private keys and public keys for Ethereum validators.
    56  type accountStore struct {
    57  	PrivateKeys [][]byte `json:"private_keys"`
    58  	PublicKeys  [][]byte `json:"public_keys"`
    59  }
    60  
    61  // AccountsKeystoreRepresentation defines an internal Prysm representation
    62  // of validator accounts, encrypted according to the EIP-2334 standard.
    63  type AccountsKeystoreRepresentation struct {
    64  	Crypto  map[string]interface{} `json:"crypto"`
    65  	ID      string                 `json:"uuid"`
    66  	Version uint                   `json:"version"`
    67  	Name    string                 `json:"name"`
    68  }
    69  
    70  // ResetCaches for the keymanager.
    71  func ResetCaches() {
    72  	lock.Lock()
    73  	orderedPublicKeys = make([][48]byte, 0)
    74  	secretKeysCache = make(map[[48]byte]bls.SecretKey)
    75  	lock.Unlock()
    76  }
    77  
    78  // NewKeymanager instantiates a new imported keymanager from configuration options.
    79  func NewKeymanager(ctx context.Context, cfg *SetupConfig) (*Keymanager, error) {
    80  	k := &Keymanager{
    81  		wallet:              cfg.Wallet,
    82  		accountsStore:       &accountStore{},
    83  		accountsChangedFeed: new(event.Feed),
    84  	}
    85  
    86  	if err := k.initializeAccountKeystore(ctx); err != nil {
    87  		return nil, errors.Wrap(err, "failed to initialize account store")
    88  	}
    89  
    90  	if cfg.ListenForChanges {
    91  		// We begin a goroutine to listen for file changes to our
    92  		// all-accounts.keystore.json file in the wallet directory.
    93  		go k.listenForAccountChanges(ctx)
    94  	}
    95  	return k, nil
    96  }
    97  
    98  // NewInteropKeymanager instantiates a new imported keymanager with the deterministically generated interop keys.
    99  func NewInteropKeymanager(_ context.Context, offset, numValidatorKeys uint64) (*Keymanager, error) {
   100  	k := &Keymanager{
   101  		accountsChangedFeed: new(event.Feed),
   102  	}
   103  	if numValidatorKeys == 0 {
   104  		return k, nil
   105  	}
   106  	secretKeys, publicKeys, err := interop.DeterministicallyGenerateKeys(offset, numValidatorKeys)
   107  	if err != nil {
   108  		return nil, errors.Wrap(err, "could not generate interop keys")
   109  	}
   110  	lock.Lock()
   111  	pubKeys := make([][48]byte, numValidatorKeys)
   112  	for i := uint64(0); i < numValidatorKeys; i++ {
   113  		publicKey := bytesutil.ToBytes48(publicKeys[i].Marshal())
   114  		pubKeys[i] = publicKey
   115  		secretKeysCache[publicKey] = secretKeys[i]
   116  	}
   117  	orderedPublicKeys = pubKeys
   118  	lock.Unlock()
   119  	return k, nil
   120  }
   121  
   122  // SubscribeAccountChanges creates an event subscription for a channel
   123  // to listen for public key changes at runtime, such as when new validator accounts
   124  // are imported into the keymanager while the validator process is running.
   125  func (km *Keymanager) SubscribeAccountChanges(pubKeysChan chan [][48]byte) event.Subscription {
   126  	return km.accountsChangedFeed.Subscribe(pubKeysChan)
   127  }
   128  
   129  // ValidatingAccountNames for a imported keymanager.
   130  func (km *Keymanager) ValidatingAccountNames() ([]string, error) {
   131  	lock.RLock()
   132  	names := make([]string, len(orderedPublicKeys))
   133  	for i, pubKey := range orderedPublicKeys {
   134  		names[i] = petnames.DeterministicName(bytesutil.FromBytes48(pubKey), "-")
   135  	}
   136  	lock.RUnlock()
   137  	return names, nil
   138  }
   139  
   140  // Initialize public and secret key caches that are used to speed up the functions
   141  // FetchValidatingPublicKeys and Sign
   142  func (km *Keymanager) initializeKeysCachesFromKeystore() error {
   143  	lock.Lock()
   144  	defer lock.Unlock()
   145  	count := len(km.accountsStore.PrivateKeys)
   146  	orderedPublicKeys = make([][48]byte, count)
   147  	secretKeysCache = make(map[[48]byte]bls.SecretKey, count)
   148  	for i, publicKey := range km.accountsStore.PublicKeys {
   149  		publicKey48 := bytesutil.ToBytes48(publicKey)
   150  		orderedPublicKeys[i] = publicKey48
   151  		secretKey, err := bls.SecretKeyFromBytes(km.accountsStore.PrivateKeys[i])
   152  		if err != nil {
   153  			return errors.Wrap(err, "failed to initialize keys caches from account keystore")
   154  		}
   155  		secretKeysCache[publicKey48] = secretKey
   156  	}
   157  	return nil
   158  }
   159  
   160  // DeleteAccounts takes in public keys and removes the accounts entirely. This includes their disk keystore and cached keystore.
   161  func (km *Keymanager) DeleteAccounts(ctx context.Context, publicKeys [][]byte) error {
   162  	for _, publicKey := range publicKeys {
   163  		var index int
   164  		var found bool
   165  		for i, pubKey := range km.accountsStore.PublicKeys {
   166  			if bytes.Equal(pubKey, publicKey) {
   167  				index = i
   168  				found = true
   169  				break
   170  			}
   171  		}
   172  		if !found {
   173  			return fmt.Errorf("could not find public key %#x", publicKey)
   174  		}
   175  		deletedPublicKey := km.accountsStore.PublicKeys[index]
   176  		accountName := petnames.DeterministicName(deletedPublicKey, "-")
   177  		km.accountsStore.PrivateKeys = append(km.accountsStore.PrivateKeys[:index], km.accountsStore.PrivateKeys[index+1:]...)
   178  		km.accountsStore.PublicKeys = append(km.accountsStore.PublicKeys[:index], km.accountsStore.PublicKeys[index+1:]...)
   179  
   180  		newStore, err := km.CreateAccountsKeystore(ctx, km.accountsStore.PrivateKeys, km.accountsStore.PublicKeys)
   181  		if err != nil {
   182  			return errors.Wrap(err, "could not rewrite accounts keystore")
   183  		}
   184  
   185  		// Write the encoded keystore.
   186  		encoded, err := json.MarshalIndent(newStore, "", "\t")
   187  		if err != nil {
   188  			return err
   189  		}
   190  		if err := km.wallet.WriteFileAtPath(ctx, AccountsPath, AccountsKeystoreFileName, encoded); err != nil {
   191  			return errors.Wrap(err, "could not write keystore file for accounts")
   192  		}
   193  
   194  		log.WithFields(logrus.Fields{
   195  			"name":      accountName,
   196  			"publicKey": fmt.Sprintf("%#x", bytesutil.Trunc(deletedPublicKey)),
   197  		}).Info("Successfully deleted validator account")
   198  		err = km.initializeKeysCachesFromKeystore()
   199  		if err != nil {
   200  			return errors.Wrap(err, "failed to initialize keys caches")
   201  		}
   202  	}
   203  	return nil
   204  }
   205  
   206  // FetchValidatingPublicKeys fetches the list of active public keys from the imported account keystores.
   207  func (km *Keymanager) FetchValidatingPublicKeys(ctx context.Context) ([][48]byte, error) {
   208  	ctx, span := trace.StartSpan(ctx, "keymanager.FetchValidatingPublicKeys")
   209  	defer span.End()
   210  
   211  	lock.RLock()
   212  	keys := orderedPublicKeys
   213  	result := make([][48]byte, len(keys))
   214  	copy(result, keys)
   215  	lock.RUnlock()
   216  	return result, nil
   217  }
   218  
   219  // FetchValidatingPrivateKeys fetches the list of private keys from the secret keys cache
   220  func (km *Keymanager) FetchValidatingPrivateKeys(ctx context.Context) ([][32]byte, error) {
   221  	lock.RLock()
   222  	defer lock.RUnlock()
   223  	privKeys := make([][32]byte, len(secretKeysCache))
   224  	pubKeys, err := km.FetchValidatingPublicKeys(ctx)
   225  	if err != nil {
   226  		return nil, errors.Wrap(err, "could not retrieve public keys")
   227  	}
   228  	for i, pk := range pubKeys {
   229  		seckey, ok := secretKeysCache[pk]
   230  		if !ok {
   231  			return nil, errors.New("Could not fetch private key")
   232  		}
   233  		privKeys[i] = bytesutil.ToBytes32(seckey.Marshal())
   234  	}
   235  	return privKeys, nil
   236  }
   237  
   238  // Sign signs a message using a validator key.
   239  func (km *Keymanager) Sign(ctx context.Context, req *validatorpb.SignRequest) (bls.Signature, error) {
   240  	ctx, span := trace.StartSpan(ctx, "keymanager.Sign")
   241  	defer span.End()
   242  
   243  	publicKey := req.PublicKey
   244  	if publicKey == nil {
   245  		return nil, errors.New("nil public key in request")
   246  	}
   247  	lock.RLock()
   248  	secretKey, ok := secretKeysCache[bytesutil.ToBytes48(publicKey)]
   249  	lock.RUnlock()
   250  	if !ok {
   251  		return nil, errors.New("no signing key found in keys cache")
   252  	}
   253  	return secretKey.Sign(req.SigningRoot), nil
   254  }
   255  
   256  func (km *Keymanager) initializeAccountKeystore(ctx context.Context) error {
   257  	encoded, err := km.wallet.ReadFileAtPath(ctx, AccountsPath, AccountsKeystoreFileName)
   258  	if err != nil && strings.Contains(err.Error(), "no files found") {
   259  		// If there are no keys to initialize at all, just exit.
   260  		return nil
   261  	} else if err != nil {
   262  		return errors.Wrapf(err, "could not read keystore file for accounts %s", AccountsKeystoreFileName)
   263  	}
   264  	keystoreFile := &AccountsKeystoreRepresentation{}
   265  	if err := json.Unmarshal(encoded, keystoreFile); err != nil {
   266  		return errors.Wrapf(err, "could not decode keystore file for accounts %s", AccountsKeystoreFileName)
   267  	}
   268  	// We extract the validator signing private key from the keystore
   269  	// by utilizing the password and initialize a new BLS secret key from
   270  	// its raw bytes.
   271  	password := km.wallet.Password()
   272  	decryptor := keystorev4.New()
   273  	enc, err := decryptor.Decrypt(keystoreFile.Crypto, password)
   274  	if err != nil && strings.Contains(err.Error(), "invalid checksum") {
   275  		return errors.Wrap(err, "wrong password for wallet entered")
   276  	} else if err != nil {
   277  		return errors.Wrap(err, "could not decrypt keystore")
   278  	}
   279  
   280  	store := &accountStore{}
   281  	if err := json.Unmarshal(enc, store); err != nil {
   282  		return err
   283  	}
   284  	if len(store.PublicKeys) != len(store.PrivateKeys) {
   285  		return errors.New("unequal number of public keys and private keys")
   286  	}
   287  	if len(store.PublicKeys) == 0 {
   288  		return nil
   289  	}
   290  	km.accountsStore = store
   291  	err = km.initializeKeysCachesFromKeystore()
   292  	if err != nil {
   293  		return errors.Wrap(err, "failed to initialize keys caches")
   294  	}
   295  	return err
   296  }
   297  
   298  // CreateAccountsKeystore creates a new keystore holding the provided keys.
   299  func (km *Keymanager) CreateAccountsKeystore(
   300  	_ context.Context,
   301  	privateKeys, publicKeys [][]byte,
   302  ) (*AccountsKeystoreRepresentation, error) {
   303  	encryptor := keystorev4.New()
   304  	id, err := uuid.NewRandom()
   305  	if err != nil {
   306  		return nil, err
   307  	}
   308  	if len(privateKeys) != len(publicKeys) {
   309  		return nil, fmt.Errorf(
   310  			"number of private keys and public keys is not equal: %d != %d", len(privateKeys), len(publicKeys),
   311  		)
   312  	}
   313  	if km.accountsStore == nil {
   314  		km.accountsStore = &accountStore{
   315  			PrivateKeys: privateKeys,
   316  			PublicKeys:  publicKeys,
   317  		}
   318  	} else {
   319  		existingPubKeys := make(map[string]bool)
   320  		existingPrivKeys := make(map[string]bool)
   321  		for i := 0; i < len(km.accountsStore.PrivateKeys); i++ {
   322  			existingPrivKeys[string(km.accountsStore.PrivateKeys[i])] = true
   323  			existingPubKeys[string(km.accountsStore.PublicKeys[i])] = true
   324  		}
   325  		// We append to the accounts store keys only
   326  		// if the private/secret key do not already exist, to prevent duplicates.
   327  		for i := 0; i < len(privateKeys); i++ {
   328  			sk := privateKeys[i]
   329  			pk := publicKeys[i]
   330  			_, privKeyExists := existingPrivKeys[string(sk)]
   331  			_, pubKeyExists := existingPubKeys[string(pk)]
   332  			if privKeyExists || pubKeyExists {
   333  				continue
   334  			}
   335  			km.accountsStore.PublicKeys = append(km.accountsStore.PublicKeys, pk)
   336  			km.accountsStore.PrivateKeys = append(km.accountsStore.PrivateKeys, sk)
   337  		}
   338  	}
   339  	err = km.initializeKeysCachesFromKeystore()
   340  	if err != nil {
   341  		return nil, errors.Wrap(err, "failed to initialize keys caches")
   342  	}
   343  	encodedStore, err := json.MarshalIndent(km.accountsStore, "", "\t")
   344  	if err != nil {
   345  		return nil, err
   346  	}
   347  	cryptoFields, err := encryptor.Encrypt(encodedStore, km.wallet.Password())
   348  	if err != nil {
   349  		return nil, errors.Wrap(err, "could not encrypt accounts")
   350  	}
   351  	return &AccountsKeystoreRepresentation{
   352  		Crypto:  cryptoFields,
   353  		ID:      id.String(),
   354  		Version: encryptor.Version(),
   355  		Name:    encryptor.Name(),
   356  	}, nil
   357  }