github.com/prysmaticlabs/prysm@v1.4.4/validator/accounts/wallet_create_test.go (about) 1 package accounts 2 3 import ( 4 "context" 5 "flag" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "strconv" 10 "testing" 11 12 "github.com/pkg/errors" 13 "github.com/prysmaticlabs/prysm/cmd/validator/flags" 14 "github.com/prysmaticlabs/prysm/shared/params" 15 "github.com/prysmaticlabs/prysm/shared/testutil/assert" 16 "github.com/prysmaticlabs/prysm/shared/testutil/require" 17 "github.com/prysmaticlabs/prysm/validator/accounts/wallet" 18 "github.com/prysmaticlabs/prysm/validator/keymanager" 19 "github.com/prysmaticlabs/prysm/validator/keymanager/imported" 20 "github.com/prysmaticlabs/prysm/validator/keymanager/remote" 21 "github.com/sirupsen/logrus" 22 logTest "github.com/sirupsen/logrus/hooks/test" 23 "github.com/urfave/cli/v2" 24 ) 25 26 const ( 27 walletDirName = "wallet" 28 passwordFileName = "password.txt" 29 password = "OhWOWthisisatest42!$" 30 mnemonicFileName = "mnemonic.txt" 31 mnemonic = "garage car helmet trade salmon embrace market giant movie wet same champion dawn chair shield drill amazing panther accident puzzle garden mosquito kind arena" 32 ) 33 34 func init() { 35 logrus.SetLevel(logrus.DebugLevel) 36 logrus.SetOutput(ioutil.Discard) 37 } 38 39 type testWalletConfig struct { 40 exitAll bool 41 skipDepositConfirm bool 42 keymanagerKind keymanager.Kind 43 numAccounts int64 44 grpcHeaders string 45 privateKeyFile string 46 accountPasswordFile string 47 walletPasswordFile string 48 backupPasswordFile string 49 backupPublicKeys string 50 voluntaryExitPublicKeys string 51 deletePublicKeys string 52 keysDir string 53 backupDir string 54 passwordsDir string 55 walletDir string 56 } 57 58 func setupWalletCtx( 59 tb testing.TB, 60 cfg *testWalletConfig, 61 ) *cli.Context { 62 app := cli.App{} 63 set := flag.NewFlagSet("test", 0) 64 set.String(flags.WalletDirFlag.Name, cfg.walletDir, "") 65 set.String(flags.KeysDirFlag.Name, cfg.keysDir, "") 66 set.String(flags.KeymanagerKindFlag.Name, cfg.keymanagerKind.String(), "") 67 set.String(flags.DeletePublicKeysFlag.Name, cfg.deletePublicKeys, "") 68 set.String(flags.VoluntaryExitPublicKeysFlag.Name, cfg.voluntaryExitPublicKeys, "") 69 set.String(flags.BackupDirFlag.Name, cfg.backupDir, "") 70 set.String(flags.BackupPasswordFile.Name, cfg.backupPasswordFile, "") 71 set.String(flags.BackupPublicKeysFlag.Name, cfg.backupPublicKeys, "") 72 set.String(flags.WalletPasswordFileFlag.Name, cfg.walletPasswordFile, "") 73 set.String(flags.AccountPasswordFileFlag.Name, cfg.accountPasswordFile, "") 74 set.Int64(flags.NumAccountsFlag.Name, cfg.numAccounts, "") 75 set.Bool(flags.SkipDepositConfirmationFlag.Name, cfg.skipDepositConfirm, "") 76 set.Bool(flags.SkipMnemonic25thWordCheckFlag.Name, true, "") 77 set.Bool(flags.ExitAllFlag.Name, cfg.exitAll, "") 78 set.String(flags.GrpcHeadersFlag.Name, cfg.grpcHeaders, "") 79 80 if cfg.privateKeyFile != "" { 81 set.String(flags.ImportPrivateKeyFileFlag.Name, cfg.privateKeyFile, "") 82 assert.NoError(tb, set.Set(flags.ImportPrivateKeyFileFlag.Name, cfg.privateKeyFile)) 83 } 84 assert.NoError(tb, set.Set(flags.WalletDirFlag.Name, cfg.walletDir)) 85 assert.NoError(tb, set.Set(flags.SkipMnemonic25thWordCheckFlag.Name, "true")) 86 assert.NoError(tb, set.Set(flags.KeysDirFlag.Name, cfg.keysDir)) 87 assert.NoError(tb, set.Set(flags.KeymanagerKindFlag.Name, cfg.keymanagerKind.String())) 88 assert.NoError(tb, set.Set(flags.DeletePublicKeysFlag.Name, cfg.deletePublicKeys)) 89 assert.NoError(tb, set.Set(flags.VoluntaryExitPublicKeysFlag.Name, cfg.voluntaryExitPublicKeys)) 90 assert.NoError(tb, set.Set(flags.BackupDirFlag.Name, cfg.backupDir)) 91 assert.NoError(tb, set.Set(flags.BackupPublicKeysFlag.Name, cfg.backupPublicKeys)) 92 assert.NoError(tb, set.Set(flags.BackupPasswordFile.Name, cfg.backupPasswordFile)) 93 assert.NoError(tb, set.Set(flags.WalletPasswordFileFlag.Name, cfg.walletPasswordFile)) 94 assert.NoError(tb, set.Set(flags.AccountPasswordFileFlag.Name, cfg.accountPasswordFile)) 95 assert.NoError(tb, set.Set(flags.NumAccountsFlag.Name, strconv.Itoa(int(cfg.numAccounts)))) 96 assert.NoError(tb, set.Set(flags.SkipDepositConfirmationFlag.Name, strconv.FormatBool(cfg.skipDepositConfirm))) 97 assert.NoError(tb, set.Set(flags.ExitAllFlag.Name, strconv.FormatBool(cfg.exitAll))) 98 assert.NoError(tb, set.Set(flags.GrpcHeadersFlag.Name, cfg.grpcHeaders)) 99 return cli.NewContext(&app, set, nil) 100 } 101 102 func setupWalletAndPasswordsDir(t testing.TB) (string, string, string) { 103 walletDir := filepath.Join(t.TempDir(), "wallet") 104 passwordsDir := filepath.Join(t.TempDir(), "passwords") 105 passwordFileDir := filepath.Join(t.TempDir(), "passwordFile") 106 require.NoError(t, os.MkdirAll(passwordFileDir, params.BeaconIoConfig().ReadWriteExecutePermissions)) 107 passwordFilePath := filepath.Join(passwordFileDir, passwordFileName) 108 require.NoError(t, ioutil.WriteFile(passwordFilePath, []byte(password), os.ModePerm)) 109 return walletDir, passwordsDir, passwordFilePath 110 } 111 112 func TestCreateOrOpenWallet(t *testing.T) { 113 hook := logTest.NewGlobal() 114 walletDir, passwordsDir, walletPasswordFile := setupWalletAndPasswordsDir(t) 115 cliCtx := setupWalletCtx(t, &testWalletConfig{ 116 walletDir: walletDir, 117 passwordsDir: passwordsDir, 118 keymanagerKind: keymanager.Imported, 119 walletPasswordFile: walletPasswordFile, 120 }) 121 createImportedWallet := func(cliCtx *cli.Context) (*wallet.Wallet, error) { 122 cfg, err := extractWalletCreationConfigFromCli(cliCtx, keymanager.Imported) 123 if err != nil { 124 return nil, err 125 } 126 w := wallet.New(&wallet.Config{ 127 KeymanagerKind: cfg.WalletCfg.KeymanagerKind, 128 WalletDir: cfg.WalletCfg.WalletDir, 129 WalletPassword: cfg.WalletCfg.WalletPassword, 130 }) 131 if err = createImportedKeymanagerWallet(cliCtx.Context, w); err != nil { 132 return nil, errors.Wrap(err, "could not create keymanager") 133 } 134 log.WithField("wallet-path", cfg.WalletCfg.WalletDir).Info( 135 "Successfully created new wallet", 136 ) 137 return w, nil 138 } 139 createdWallet, err := wallet.OpenWalletOrElseCli(cliCtx, createImportedWallet) 140 require.NoError(t, err) 141 require.LogsContain(t, hook, "Successfully created new wallet") 142 143 openedWallet, err := wallet.OpenWalletOrElseCli(cliCtx, createImportedWallet) 144 require.NoError(t, err) 145 assert.Equal(t, createdWallet.KeymanagerKind(), openedWallet.KeymanagerKind()) 146 assert.Equal(t, createdWallet.AccountsDir(), openedWallet.AccountsDir()) 147 } 148 149 func TestCreateWallet_Imported(t *testing.T) { 150 walletDir, passwordsDir, walletPasswordFile := setupWalletAndPasswordsDir(t) 151 cliCtx := setupWalletCtx(t, &testWalletConfig{ 152 walletDir: walletDir, 153 passwordsDir: passwordsDir, 154 keymanagerKind: keymanager.Imported, 155 walletPasswordFile: walletPasswordFile, 156 }) 157 158 // We attempt to create the wallet. 159 _, err := CreateAndSaveWalletCli(cliCtx) 160 require.NoError(t, err) 161 162 // We attempt to open the newly created wallet. 163 w, err := wallet.OpenWallet(cliCtx.Context, &wallet.Config{ 164 WalletDir: walletDir, 165 }) 166 assert.NoError(t, err) 167 _, err = w.ReadFileAtPath(cliCtx.Context, imported.AccountsPath, imported.AccountsKeystoreFileName) 168 require.NoError(t, err) 169 } 170 171 func TestCreateWallet_Derived(t *testing.T) { 172 walletDir, passwordsDir, passwordFile := setupWalletAndPasswordsDir(t) 173 cliCtx := setupWalletCtx(t, &testWalletConfig{ 174 walletDir: walletDir, 175 passwordsDir: passwordsDir, 176 walletPasswordFile: passwordFile, 177 keymanagerKind: keymanager.Derived, 178 numAccounts: 1, 179 }) 180 181 // We attempt to create the wallet. 182 _, err := CreateAndSaveWalletCli(cliCtx) 183 require.NoError(t, err) 184 185 // We attempt to open the newly created wallet. 186 _, err = wallet.OpenWallet(cliCtx.Context, &wallet.Config{ 187 WalletDir: walletDir, 188 }) 189 assert.NoError(t, err) 190 } 191 192 // TestCreateWallet_WalletAlreadyExists checks for expected error if trying to create a wallet when there is one already. 193 func TestCreateWallet_WalletAlreadyExists(t *testing.T) { 194 walletDir, passwordsDir, passwordFile := setupWalletAndPasswordsDir(t) 195 cliCtx := setupWalletCtx(t, &testWalletConfig{ 196 walletDir: walletDir, 197 passwordsDir: passwordsDir, 198 walletPasswordFile: passwordFile, 199 keymanagerKind: keymanager.Derived, 200 numAccounts: 1, 201 }) 202 203 // We attempt to create the wallet. 204 _, err := CreateAndSaveWalletCli(cliCtx) 205 require.NoError(t, err) 206 207 // We attempt to create another wallet of the same type at the same location. We expect an error. 208 _, err = CreateAndSaveWalletCli(cliCtx) 209 require.ErrorContains(t, "already exists", err) 210 211 cliCtx = setupWalletCtx(t, &testWalletConfig{ 212 walletDir: walletDir, 213 passwordsDir: passwordsDir, 214 walletPasswordFile: passwordFile, 215 keymanagerKind: keymanager.Imported, 216 }) 217 218 // We attempt to create another wallet of different type at the same location. We expect an error. 219 _, err = CreateAndSaveWalletCli(cliCtx) 220 require.ErrorContains(t, "already exists", err) 221 } 222 223 func TestCreateWallet_Remote(t *testing.T) { 224 walletDir, _, walletPasswordFile := setupWalletAndPasswordsDir(t) 225 wantCfg := &remote.KeymanagerOpts{ 226 RemoteCertificate: &remote.CertificateConfig{ 227 RequireTls: true, 228 ClientCertPath: "/tmp/client.crt", 229 ClientKeyPath: "/tmp/client.key", 230 CACertPath: "/tmp/ca.crt", 231 }, 232 RemoteAddr: "host.example.com:4000", 233 } 234 app := cli.App{} 235 set := flag.NewFlagSet("test", 0) 236 keymanagerKind := "remote" 237 set.String(flags.WalletDirFlag.Name, walletDir, "") 238 set.String(flags.WalletPasswordFileFlag.Name, walletDir, "") 239 set.String(flags.KeymanagerKindFlag.Name, keymanagerKind, "") 240 set.String(flags.GrpcRemoteAddressFlag.Name, wantCfg.RemoteAddr, "") 241 set.String(flags.RemoteSignerCertPathFlag.Name, wantCfg.RemoteCertificate.ClientCertPath, "") 242 set.String(flags.RemoteSignerKeyPathFlag.Name, wantCfg.RemoteCertificate.ClientKeyPath, "") 243 set.String(flags.RemoteSignerCACertPathFlag.Name, wantCfg.RemoteCertificate.CACertPath, "") 244 assert.NoError(t, set.Set(flags.WalletDirFlag.Name, walletDir)) 245 assert.NoError(t, set.Set(flags.WalletPasswordFileFlag.Name, walletPasswordFile)) 246 assert.NoError(t, set.Set(flags.KeymanagerKindFlag.Name, keymanagerKind)) 247 assert.NoError(t, set.Set(flags.GrpcRemoteAddressFlag.Name, wantCfg.RemoteAddr)) 248 assert.NoError(t, set.Set(flags.RemoteSignerCertPathFlag.Name, wantCfg.RemoteCertificate.ClientCertPath)) 249 assert.NoError(t, set.Set(flags.RemoteSignerKeyPathFlag.Name, wantCfg.RemoteCertificate.ClientKeyPath)) 250 assert.NoError(t, set.Set(flags.RemoteSignerCACertPathFlag.Name, wantCfg.RemoteCertificate.CACertPath)) 251 cliCtx := cli.NewContext(&app, set, nil) 252 253 // We attempt to create the wallet. 254 _, err := CreateAndSaveWalletCli(cliCtx) 255 require.NoError(t, err) 256 257 // We attempt to open the newly created wallet. 258 ctx := context.Background() 259 w, err := wallet.OpenWallet(cliCtx.Context, &wallet.Config{ 260 WalletDir: walletDir, 261 }) 262 assert.NoError(t, err) 263 264 // We read the keymanager config for the newly created wallet. 265 encoded, err := w.ReadKeymanagerConfigFromDisk(ctx) 266 assert.NoError(t, err) 267 cfg, err := remote.UnmarshalOptionsFile(encoded) 268 assert.NoError(t, err) 269 270 // We assert the created configuration was as desired. 271 assert.DeepEqual(t, wantCfg, cfg) 272 }