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

     1  package imported
     2  
     3  import (
     4  	"context"
     5  	"encoding/hex"
     6  	"encoding/json"
     7  	"fmt"
     8  	"strings"
     9  
    10  	"github.com/k0kubun/go-ansi"
    11  	"github.com/pkg/errors"
    12  	"github.com/prysmaticlabs/prysm/shared/bls"
    13  	"github.com/prysmaticlabs/prysm/shared/promptutil"
    14  	"github.com/prysmaticlabs/prysm/validator/keymanager"
    15  	"github.com/schollz/progressbar/v3"
    16  	keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
    17  )
    18  
    19  // ImportKeystores into the imported keymanager from an external source.
    20  func (km *Keymanager) ImportKeystores(
    21  	ctx context.Context,
    22  	keystores []*keymanager.Keystore,
    23  	importsPassword string,
    24  ) error {
    25  	decryptor := keystorev4.New()
    26  	bar := initializeProgressBar(len(keystores), "Importing accounts...")
    27  	keys := map[string]string{}
    28  	var err error
    29  	for i := 0; i < len(keystores); i++ {
    30  		var privKeyBytes []byte
    31  		var pubKeyBytes []byte
    32  		privKeyBytes, pubKeyBytes, importsPassword, err = km.attemptDecryptKeystore(decryptor, keystores[i], importsPassword)
    33  		if err != nil {
    34  			return err
    35  		}
    36  		// if key exists prior to being added then output log that duplicate key was found
    37  		if _, ok := keys[string(pubKeyBytes)]; ok {
    38  			log.Warnf("Duplicate key in import folder will be ignored: %#x", pubKeyBytes)
    39  		}
    40  		keys[string(pubKeyBytes)] = string(privKeyBytes)
    41  		if err := bar.Add(1); err != nil {
    42  			return errors.Wrap(err, "could not add to progress bar")
    43  		}
    44  	}
    45  	privKeys := make([][]byte, 0)
    46  	pubKeys := make([][]byte, 0)
    47  	for pubKey, privKey := range keys {
    48  		pubKeys = append(pubKeys, []byte(pubKey))
    49  		privKeys = append(privKeys, []byte(privKey))
    50  	}
    51  
    52  	// Write the accounts to disk into a single keystore.
    53  	accountsKeystore, err := km.CreateAccountsKeystore(ctx, privKeys, pubKeys)
    54  	if err != nil {
    55  		return err
    56  	}
    57  	encodedAccounts, err := json.MarshalIndent(accountsKeystore, "", "\t")
    58  	if err != nil {
    59  		return err
    60  	}
    61  	return km.wallet.WriteFileAtPath(ctx, AccountsPath, AccountsKeystoreFileName, encodedAccounts)
    62  }
    63  
    64  // ImportKeypairs directly into the keymanager.
    65  func (km *Keymanager) ImportKeypairs(ctx context.Context, privKeys, pubKeys [][]byte) error {
    66  	// Write the accounts to disk into a single keystore.
    67  	accountsKeystore, err := km.CreateAccountsKeystore(ctx, privKeys, pubKeys)
    68  	if err != nil {
    69  		return errors.Wrap(err, "could not import account keypairs")
    70  	}
    71  	encodedAccounts, err := json.MarshalIndent(accountsKeystore, "", "\t")
    72  	if err != nil {
    73  		return errors.Wrap(err, "could not marshal accounts keystore into JSON")
    74  	}
    75  	return km.wallet.WriteFileAtPath(ctx, AccountsPath, AccountsKeystoreFileName, encodedAccounts)
    76  }
    77  
    78  // Retrieves the private key and public key from an EIP-2335 keystore file
    79  // by decrypting using a specified password. If the password fails,
    80  // it prompts the user for the correct password until it confirms.
    81  func (km *Keymanager) attemptDecryptKeystore(
    82  	enc *keystorev4.Encryptor, keystore *keymanager.Keystore, password string,
    83  ) ([]byte, []byte, string, error) {
    84  	// Attempt to decrypt the keystore with the specifies password.
    85  	var privKeyBytes []byte
    86  	var err error
    87  	privKeyBytes, err = enc.Decrypt(keystore.Crypto, password)
    88  	doesNotDecrypt := err != nil && strings.Contains(err.Error(), "invalid checksum")
    89  	for doesNotDecrypt {
    90  		password, err = promptutil.PasswordPrompt(
    91  			fmt.Sprintf("Password incorrect for key 0x%s, input correct password", keystore.Pubkey), promptutil.NotEmpty,
    92  		)
    93  		if err != nil {
    94  			return nil, nil, "", fmt.Errorf("could not read keystore password: %w", err)
    95  		}
    96  		privKeyBytes, err = enc.Decrypt(keystore.Crypto, password)
    97  		doesNotDecrypt = err != nil && strings.Contains(err.Error(), "invalid checksum")
    98  		if err != nil && !strings.Contains(err.Error(), "invalid checksum") {
    99  			return nil, nil, "", errors.Wrap(err, "could not decrypt keystore")
   100  		}
   101  	}
   102  	if err != nil && !strings.Contains(err.Error(), "invalid checksum") {
   103  		return nil, nil, "", errors.Wrap(err, "could not decrypt keystore")
   104  	}
   105  	var pubKeyBytes []byte
   106  	// Attempt to use the pubkey present in the keystore itself as a field. If unavailable,
   107  	// then utilize the public key directly from the private key.
   108  	if keystore.Pubkey != "" {
   109  		pubKeyBytes, err = hex.DecodeString(keystore.Pubkey)
   110  		if err != nil {
   111  			return nil, nil, "", errors.Wrap(err, "could not decode pubkey from keystore")
   112  		}
   113  	} else {
   114  		privKey, err := bls.SecretKeyFromBytes(privKeyBytes)
   115  		if err != nil {
   116  			return nil, nil, "", errors.Wrap(err, "could not initialize private key from bytes")
   117  		}
   118  		pubKeyBytes = privKey.PublicKey().Marshal()
   119  	}
   120  	return privKeyBytes, pubKeyBytes, password, nil
   121  }
   122  
   123  func initializeProgressBar(numItems int, msg string) *progressbar.ProgressBar {
   124  	return progressbar.NewOptions(
   125  		numItems,
   126  		progressbar.OptionFullWidth(),
   127  		progressbar.OptionSetWriter(ansi.NewAnsiStdout()),
   128  		progressbar.OptionEnableColorCodes(true),
   129  		progressbar.OptionSetTheme(progressbar.Theme{
   130  			Saucer:        "[green]=[reset]",
   131  			SaucerHead:    "[green]>[reset]",
   132  			SaucerPadding: " ",
   133  			BarStart:      "[",
   134  			BarEnd:        "]",
   135  		}),
   136  		progressbar.OptionOnCompletion(func() { fmt.Println() }),
   137  		progressbar.OptionSetDescription(msg),
   138  	)
   139  }