github.com/prysmaticlabs/prysm@v1.4.4/validator/accounts/accounts_backup_test.go (about)

     1  package accounts
     2  
     3  import (
     4  	"archive/zip"
     5  	"encoding/hex"
     6  	"encoding/json"
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  	"sort"
    11  	"strings"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/prysmaticlabs/prysm/shared/fileutil"
    16  	"github.com/prysmaticlabs/prysm/shared/params"
    17  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    18  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    19  	"github.com/prysmaticlabs/prysm/validator/accounts/iface"
    20  	"github.com/prysmaticlabs/prysm/validator/accounts/wallet"
    21  	"github.com/prysmaticlabs/prysm/validator/keymanager"
    22  	"github.com/prysmaticlabs/prysm/validator/keymanager/derived"
    23  	constant "github.com/prysmaticlabs/prysm/validator/testing"
    24  )
    25  
    26  func TestBackupAccounts_Noninteractive_Derived(t *testing.T) {
    27  	walletDir, _, passwordFilePath := setupWalletAndPasswordsDir(t)
    28  	// Specify the password locally to this file for convenience.
    29  	password := "Pa$sW0rD0__Fo0xPr"
    30  	require.NoError(t, ioutil.WriteFile(passwordFilePath, []byte(password), os.ModePerm))
    31  
    32  	// Write a directory where we will backup accounts to.
    33  	backupDir := filepath.Join(t.TempDir(), "backupDir")
    34  	require.NoError(t, os.MkdirAll(backupDir, params.BeaconIoConfig().ReadWriteExecutePermissions))
    35  
    36  	// Write a password for the accounts we wish to backup to a file.
    37  	backupPasswordFile := filepath.Join(backupDir, "backuppass.txt")
    38  	err := ioutil.WriteFile(
    39  		backupPasswordFile,
    40  		[]byte("Passw0rdz4938%%"),
    41  		params.BeaconIoConfig().ReadWritePermissions,
    42  	)
    43  	require.NoError(t, err)
    44  
    45  	// We initialize a wallet with a derived keymanager.
    46  	cliCtx := setupWalletCtx(t, &testWalletConfig{
    47  		// Wallet configuration flags.
    48  		walletDir:          walletDir,
    49  		keymanagerKind:     keymanager.Derived,
    50  		walletPasswordFile: passwordFilePath,
    51  		// Flags required for BackupAccounts to work.
    52  		backupPasswordFile: backupPasswordFile,
    53  		backupDir:          backupDir,
    54  	})
    55  	w, err := CreateWalletWithKeymanager(cliCtx.Context, &CreateWalletConfig{
    56  		WalletCfg: &wallet.Config{
    57  			WalletDir:      walletDir,
    58  			KeymanagerKind: keymanager.Derived,
    59  			WalletPassword: password,
    60  		},
    61  	})
    62  	require.NoError(t, err)
    63  
    64  	km, err := w.InitializeKeymanager(cliCtx.Context, iface.InitKeymanagerConfig{ListenForChanges: false})
    65  	require.NoError(t, err)
    66  	// Create 2 accounts
    67  	derivedKM, ok := km.(*derived.Keymanager)
    68  	require.Equal(t, true, ok)
    69  	err = derivedKM.RecoverAccountsFromMnemonic(cliCtx.Context, constant.TestMnemonic, "", 2)
    70  	require.NoError(t, err)
    71  
    72  	// Obtain the public keys of the accounts we created
    73  	pubkeys, err := km.FetchValidatingPublicKeys(cliCtx.Context)
    74  	require.NoError(t, err)
    75  	var generatedPubKeys []string
    76  	for _, pubkey := range pubkeys {
    77  		encoded := make([]byte, hex.EncodedLen(len(pubkey)))
    78  		hex.Encode(encoded, pubkey[:])
    79  		generatedPubKeys = append(generatedPubKeys, string(encoded))
    80  	}
    81  	backupPublicKeys := strings.Join(generatedPubKeys, ",")
    82  
    83  	// Recreate a cliCtx with the addition of these backup keys to be later used by the backup process
    84  	cliCtx = setupWalletCtx(t, &testWalletConfig{
    85  		// Wallet configuration flags.
    86  		walletDir:          walletDir,
    87  		keymanagerKind:     keymanager.Derived,
    88  		walletPasswordFile: passwordFilePath,
    89  		// Flags required for BackupAccounts to work.
    90  		backupPublicKeys:   backupPublicKeys,
    91  		backupPasswordFile: backupPasswordFile,
    92  		backupDir:          backupDir,
    93  	})
    94  
    95  	// Next, we attempt to backup the accounts.
    96  	require.NoError(t, BackupAccountsCli(cliCtx))
    97  
    98  	// We check a backup.zip file was created at the output path.
    99  	zipFilePath := filepath.Join(backupDir, archiveFilename)
   100  	assert.DeepEqual(t, true, fileutil.FileExists(zipFilePath))
   101  
   102  	// We attempt to unzip the file and verify the keystores do match our accounts.
   103  	f, err := os.Open(zipFilePath)
   104  	require.NoError(t, err)
   105  	defer func() {
   106  		require.NoError(t, f.Close())
   107  	}()
   108  	fi, err := f.Stat()
   109  	require.NoError(t, err)
   110  	r, err := zip.NewReader(f, fi.Size())
   111  	require.NoError(t, err)
   112  
   113  	// We check we have 2 keystore files in the unzipped results.
   114  	require.DeepEqual(t, 2, len(r.File))
   115  	unzippedPublicKeys := make([]string, 2)
   116  	for i, unzipped := range r.File {
   117  		ff, err := unzipped.Open()
   118  		require.NoError(t, err)
   119  		encodedBytes, err := ioutil.ReadAll(ff)
   120  		require.NoError(t, err)
   121  		keystoreFile := &keymanager.Keystore{}
   122  		require.NoError(t, json.Unmarshal(encodedBytes, keystoreFile))
   123  		require.NoError(t, ff.Close())
   124  		unzippedPublicKeys[i] = keystoreFile.Pubkey
   125  	}
   126  	sort.Strings(unzippedPublicKeys)
   127  	sort.Strings(generatedPubKeys)
   128  	assert.DeepEqual(t, unzippedPublicKeys, generatedPubKeys)
   129  }
   130  
   131  func TestBackupAccounts_Noninteractive_Imported(t *testing.T) {
   132  	walletDir, _, passwordFilePath := setupWalletAndPasswordsDir(t)
   133  	// Write a directory where we will import keys from.
   134  	keysDir := filepath.Join(t.TempDir(), "keysDir")
   135  	require.NoError(t, os.MkdirAll(keysDir, params.BeaconIoConfig().ReadWriteExecutePermissions))
   136  
   137  	// Write a directory where we will backup accounts to.
   138  	backupDir := filepath.Join(t.TempDir(), "backupDir")
   139  	require.NoError(t, os.MkdirAll(backupDir, params.BeaconIoConfig().ReadWriteExecutePermissions))
   140  
   141  	// Create 2 keystore files in the keys directory we can then
   142  	// import from in our wallet.
   143  	k1, _ := createKeystore(t, keysDir)
   144  	time.Sleep(time.Second)
   145  	k2, _ := createKeystore(t, keysDir)
   146  	generatedPubKeys := []string{k1.Pubkey, k2.Pubkey}
   147  	backupPublicKeys := strings.Join(generatedPubKeys, ",")
   148  
   149  	// Write a password for the accounts we wish to backup to a file.
   150  	backupPasswordFile := filepath.Join(backupDir, "backuppass.txt")
   151  	err := ioutil.WriteFile(
   152  		backupPasswordFile,
   153  		[]byte("Passw0rdz4938%%"),
   154  		params.BeaconIoConfig().ReadWritePermissions,
   155  	)
   156  	require.NoError(t, err)
   157  
   158  	// We initialize a wallet with a imported keymanager.
   159  	cliCtx := setupWalletCtx(t, &testWalletConfig{
   160  		// Wallet configuration flags.
   161  		walletDir:           walletDir,
   162  		keymanagerKind:      keymanager.Imported,
   163  		walletPasswordFile:  passwordFilePath,
   164  		accountPasswordFile: passwordFilePath,
   165  		// Flags required for ImportAccounts to work.
   166  		keysDir: keysDir,
   167  		// Flags required for BackupAccounts to work.
   168  		backupPublicKeys:   backupPublicKeys,
   169  		backupPasswordFile: backupPasswordFile,
   170  		backupDir:          backupDir,
   171  	})
   172  	_, err = CreateWalletWithKeymanager(cliCtx.Context, &CreateWalletConfig{
   173  		WalletCfg: &wallet.Config{
   174  			WalletDir:      walletDir,
   175  			KeymanagerKind: keymanager.Imported,
   176  			WalletPassword: password,
   177  		},
   178  	})
   179  	require.NoError(t, err)
   180  
   181  	// We attempt to import accounts we wrote to the keys directory
   182  	// into our newly created wallet.
   183  	require.NoError(t, ImportAccountsCli(cliCtx))
   184  
   185  	// Next, we attempt to backup the accounts.
   186  	require.NoError(t, BackupAccountsCli(cliCtx))
   187  
   188  	// We check a backup.zip file was created at the output path.
   189  	zipFilePath := filepath.Join(backupDir, archiveFilename)
   190  	assert.DeepEqual(t, true, fileutil.FileExists(zipFilePath))
   191  
   192  	// We attempt to unzip the file and verify the keystores do match our accounts.
   193  	f, err := os.Open(zipFilePath)
   194  	require.NoError(t, err)
   195  	defer func() {
   196  		require.NoError(t, f.Close())
   197  	}()
   198  	fi, err := f.Stat()
   199  	require.NoError(t, err)
   200  	r, err := zip.NewReader(f, fi.Size())
   201  	require.NoError(t, err)
   202  
   203  	// We check we have 2 keystore files in the unzipped results.
   204  	require.DeepEqual(t, 2, len(r.File))
   205  	unzippedPublicKeys := make([]string, 2)
   206  	for i, unzipped := range r.File {
   207  		ff, err := unzipped.Open()
   208  		require.NoError(t, err)
   209  		encodedBytes, err := ioutil.ReadAll(ff)
   210  		require.NoError(t, err)
   211  		keystoreFile := &keymanager.Keystore{}
   212  		require.NoError(t, json.Unmarshal(encodedBytes, keystoreFile))
   213  		require.NoError(t, ff.Close())
   214  		unzippedPublicKeys[i] = keystoreFile.Pubkey
   215  	}
   216  	sort.Strings(unzippedPublicKeys)
   217  	sort.Strings(generatedPubKeys)
   218  	assert.DeepEqual(t, unzippedPublicKeys, generatedPubKeys)
   219  }