github.com/Finschia/finschia-sdk@v0.49.1/client/keys/add_test.go (about) 1 package keys 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "io" 8 "testing" 9 10 "github.com/Finschia/ostracon/libs/cli" 11 "github.com/cosmos/go-bip39" 12 "github.com/spf13/pflag" 13 "github.com/stretchr/testify/require" 14 15 "github.com/Finschia/finschia-sdk/client" 16 "github.com/Finschia/finschia-sdk/client/flags" 17 "github.com/Finschia/finschia-sdk/crypto/hd" 18 "github.com/Finschia/finschia-sdk/crypto/keyring" 19 "github.com/Finschia/finschia-sdk/simapp" 20 "github.com/Finschia/finschia-sdk/testutil" 21 "github.com/Finschia/finschia-sdk/testutil/testdata" 22 sdk "github.com/Finschia/finschia-sdk/types" 23 ) 24 25 func Test_runAddCmdBasic(t *testing.T) { 26 cmd := AddKeyCommand() 27 cmd.Flags().AddFlagSet(Commands("home").PersistentFlags()) 28 29 mockIn := testutil.ApplyMockIODiscardOutErr(cmd) 30 kbHome := t.TempDir() 31 32 kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn) 33 require.NoError(t, err) 34 35 clientCtx := client.Context{}.WithKeyringDir(kbHome).WithInput(mockIn).WithKeyring(kb) 36 clientCtxPtr := &clientCtx 37 ctx := context.WithValue(context.Background(), client.ClientContextKey, clientCtxPtr) 38 39 t.Cleanup(func() { 40 _ = kb.Delete("keyname1") 41 _ = kb.Delete("keyname2") 42 }) 43 44 cmd.SetArgs([]string{ 45 "keyname1", 46 fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), 47 fmt.Sprintf("--%s=%s", cli.OutputFlag, OutputFormatText), 48 fmt.Sprintf("--%s=%s", flags.FlagKeyAlgorithm, string(hd.Secp256k1Type)), 49 fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), 50 }) 51 mockIn.Reset("y\n") 52 require.NoError(t, cmd.ExecuteContext(ctx)) 53 54 mockIn.Reset("N\n") 55 require.Error(t, cmd.ExecuteContext(ctx)) 56 57 cmd.SetArgs([]string{ 58 "keyname2", 59 fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), 60 fmt.Sprintf("--%s=%s", cli.OutputFlag, OutputFormatText), 61 fmt.Sprintf("--%s=%s", flags.FlagKeyAlgorithm, string(hd.Secp256k1Type)), 62 fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), 63 }) 64 65 require.NoError(t, cmd.ExecuteContext(ctx)) 66 67 mockIn.Reset("y\n") 68 require.NoError(t, cmd.ExecuteContext(ctx)) 69 70 cmd.SetArgs([]string{ 71 "keyname4", 72 fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), 73 fmt.Sprintf("--%s=%s", cli.OutputFlag, OutputFormatText), 74 fmt.Sprintf("--%s=%s", flags.FlagKeyAlgorithm, string(hd.Secp256k1Type)), 75 fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), 76 }) 77 78 require.NoError(t, cmd.ExecuteContext(ctx)) 79 80 // In Multisig 81 tcs := []struct { 82 args []string 83 err string 84 }{ 85 { 86 []string{ 87 "keyname1", 88 fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), 89 fmt.Sprintf("--%s=%s", cli.OutputFlag, OutputFormatText), 90 fmt.Sprintf("--%s=%s", flags.FlagKeyAlgorithm, string(hd.Secp256k1Type)), 91 fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), 92 fmt.Sprintf("--%s=%s", flagMultisig, "keyname1,keyname2"), 93 }, 94 "you cannot specify a new key as one of the names of the keys that make up a multisig", 95 }, 96 { 97 []string{ 98 "keyname-multi", 99 fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), 100 fmt.Sprintf("--%s=%s", cli.OutputFlag, OutputFormatText), 101 fmt.Sprintf("--%s=%s", flags.FlagKeyAlgorithm, string(hd.Secp256k1Type)), 102 fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), 103 fmt.Sprintf("--%s=%s", flagMultisig, "keyname1,keyname11"), 104 }, 105 "part of the multisig target key does not exist", 106 }, 107 { 108 []string{ 109 "keyname-multi", 110 fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), 111 fmt.Sprintf("--%s=%s", cli.OutputFlag, OutputFormatText), 112 fmt.Sprintf("--%s=%s", flags.FlagKeyAlgorithm, string(hd.Secp256k1Type)), 113 fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), 114 fmt.Sprintf("--%s=%s", flagMultisig, "keyname1,keyname2"), 115 fmt.Sprintf("--%s=%d", flagMultiSigThreshold, 3), 116 }, 117 "threshold k of n multisignature", 118 }, 119 { 120 []string{ 121 "keyname-multi", 122 fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), 123 fmt.Sprintf("--%s=%s", cli.OutputFlag, OutputFormatText), 124 fmt.Sprintf("--%s=%s", flags.FlagKeyAlgorithm, string(hd.Secp256k1Type)), 125 fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), 126 fmt.Sprintf("--%s=%s", flagMultisig, "keyname1,keyname2"), 127 fmt.Sprintf("--%s=%d", flagMultiSigThreshold, -1), 128 }, 129 "threshold must be a positive integer", 130 }, 131 { 132 []string{ 133 "keyname-multi", 134 fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), 135 fmt.Sprintf("--%s=%s", cli.OutputFlag, OutputFormatText), 136 fmt.Sprintf("--%s=%s", flags.FlagKeyAlgorithm, string(hd.Secp256k1Type)), 137 fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), 138 fmt.Sprintf("--%s=%s", flagMultisig, "keyname1,keyname2"), 139 fmt.Sprintf("--%s=%d", flagMultiSigThreshold, 2), 140 }, 141 "", 142 }, 143 } 144 145 for _, tc := range tcs { 146 cmd.SetArgs(tc.args) 147 if tc.err != "" { 148 require.Contains(t, cmd.ExecuteContext(ctx).Error(), tc.err) 149 } else { 150 require.NoError(t, cmd.ExecuteContext(ctx)) 151 } 152 153 cmd.Flags().Visit(func(f *pflag.Flag) { 154 if f.Name == flagMultisig { 155 err = f.Value.(pflag.SliceValue).Replace([]string{}) 156 require.NoError(t, err) 157 } 158 }) 159 } 160 161 cmd.SetArgs([]string{ 162 "keyname5", 163 fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), 164 fmt.Sprintf("--%s=true", flags.FlagDryRun), 165 fmt.Sprintf("--%s=%s", cli.OutputFlag, OutputFormatText), 166 fmt.Sprintf("--%s=%s", flags.FlagKeyAlgorithm, string(hd.Secp256k1Type)), 167 }) 168 mockIn.Reset("\n") 169 require.NoError(t, cmd.ExecuteContext(ctx)) 170 171 // In recovery mode 172 cmd.SetArgs([]string{ 173 "keyname6", 174 fmt.Sprintf("--%s=true", flagRecover), 175 }) 176 177 // use valid mnemonic and complete recovery key generation successfully 178 mockIn.Reset("decide praise business actor peasant farm drastic weather extend front hurt later song give verb rhythm worry fun pond reform school tumble august one\n") 179 require.NoError(t, cmd.ExecuteContext(ctx)) 180 181 // use invalid mnemonic and fail recovery key generation 182 mockIn.Reset("invalid mnemonic\n") 183 require.Error(t, cmd.ExecuteContext(ctx)) 184 185 // In interactive mode 186 cmd.SetArgs([]string{ 187 "keyname7", 188 "-i", 189 fmt.Sprintf("--%s=false", flagRecover), 190 }) 191 192 const password = "password1!" 193 194 // set password and complete interactive key generation successfully 195 mockIn.Reset("\n" + password + "\n" + password + "\n") 196 require.NoError(t, cmd.ExecuteContext(ctx)) 197 198 // passwords don't match and fail interactive key generation 199 mockIn.Reset("\n" + password + "\n" + "fail" + "\n") 200 require.Error(t, cmd.ExecuteContext(ctx)) 201 } 202 203 func TestAddRecoverFileBackend(t *testing.T) { 204 cmd := AddKeyCommand() 205 cmd.Flags().AddFlagSet(Commands("home").PersistentFlags()) 206 207 mockIn := testutil.ApplyMockIODiscardOutErr(cmd) 208 kbHome := t.TempDir() 209 210 clientCtx := client.Context{}.WithKeyringDir(kbHome).WithInput(mockIn) 211 ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx) 212 213 cmd.SetArgs([]string{ 214 "keyname1", 215 fmt.Sprintf("--%s=%s", flags.FlagHome, kbHome), 216 fmt.Sprintf("--%s=%s", cli.OutputFlag, OutputFormatText), 217 fmt.Sprintf("--%s=%s", flags.FlagKeyAlgorithm, string(hd.Secp256k1Type)), 218 fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendFile), 219 fmt.Sprintf("--%s", flagRecover), 220 }) 221 222 keyringPassword := "12345678" 223 224 entropySeed, err := bip39.NewEntropy(mnemonicEntropySize) 225 require.NoError(t, err) 226 227 mnemonic, err := bip39.NewMnemonic(entropySeed) 228 require.NoError(t, err) 229 230 mockIn.Reset(fmt.Sprintf("%s\n%s\n%s\n", mnemonic, keyringPassword, keyringPassword)) 231 require.NoError(t, cmd.ExecuteContext(ctx)) 232 233 kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendFile, kbHome, mockIn) 234 require.NoError(t, err) 235 236 t.Cleanup(func() { 237 mockIn.Reset(fmt.Sprintf("%s\n%s\n", keyringPassword, keyringPassword)) 238 _ = kb.Delete("keyname1") 239 }) 240 241 mockIn.Reset(fmt.Sprintf("%s\n%s\n", keyringPassword, keyringPassword)) 242 info, err := kb.Key("keyname1") 243 require.NoError(t, err) 244 require.Equal(t, "keyname1", info.GetName()) 245 } 246 247 func Test_runAddCmdDryRun(t *testing.T) { 248 pubkey1 := `{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AtObiFVE4s+9+RX5SP8TN9r2mxpoaT4eGj9CJfK7VRzN"}` 249 pubkey2 := `{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A/se1vkqgdQ7VJQCM4mxN+L+ciGhnnJ4XYsQCRBMrdRi"}` 250 251 testData := []struct { 252 name string 253 args []string 254 added bool 255 }{ 256 { 257 name: "account is added", 258 args: []string{ 259 "testkey", 260 fmt.Sprintf("--%s=%s", flags.FlagDryRun, "false"), 261 }, 262 added: true, 263 }, 264 { 265 name: "account is not added with dry run", 266 args: []string{ 267 "testkey", 268 fmt.Sprintf("--%s=%s", flags.FlagDryRun, "true"), 269 }, 270 added: false, 271 }, 272 { 273 name: "multisig account is added", 274 args: []string{ 275 "testkey", 276 fmt.Sprintf("--%s=%s", flags.FlagDryRun, "false"), 277 fmt.Sprintf("--%s=%s", flagMultisig, "subkey"), 278 }, 279 added: true, 280 }, 281 { 282 name: "multisig account is not added with dry run", 283 args: []string{ 284 "testkey", 285 fmt.Sprintf("--%s=%s", flags.FlagDryRun, "true"), 286 fmt.Sprintf("--%s=%s", flagMultisig, "subkey"), 287 }, 288 added: false, 289 }, 290 { 291 name: "pubkey account is added", 292 args: []string{ 293 "testkey", 294 fmt.Sprintf("--%s=%s", flags.FlagDryRun, "false"), 295 fmt.Sprintf("--%s=%s", FlagPublicKey, pubkey1), 296 }, 297 added: true, 298 }, 299 { 300 name: "pubkey account is not added with dry run", 301 args: []string{ 302 "testkey", 303 fmt.Sprintf("--%s=%s", flags.FlagDryRun, "true"), 304 fmt.Sprintf("--%s=%s", FlagPublicKey, pubkey2), 305 }, 306 added: false, 307 }, 308 } 309 for _, tt := range testData { 310 t.Run(tt.name, func(t *testing.T) { 311 cmd := AddKeyCommand() 312 cmd.Flags().AddFlagSet(Commands("home").PersistentFlags()) 313 314 kbHome := t.TempDir() 315 mockIn := testutil.ApplyMockIODiscardOutErr(cmd) 316 kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, kbHome, mockIn) 317 require.NoError(t, err) 318 319 appCodec := simapp.MakeTestEncodingConfig().Marshaler 320 clientCtx := client.Context{}. 321 WithCodec(appCodec). 322 WithKeyringDir(kbHome). 323 WithKeyring(kb) 324 ctx := context.WithValue(context.Background(), client.ClientContextKey, &clientCtx) 325 326 path := sdk.GetConfig().GetFullBIP44Path() 327 _, err = kb.NewAccount("subkey", testdata.TestMnemonic, "", path, hd.Secp256k1) 328 require.NoError(t, err) 329 330 t.Cleanup(func() { 331 _ = kb.Delete("subkey") 332 }) 333 334 b := bytes.NewBufferString("") 335 cmd.SetOut(b) 336 337 cmd.SetArgs(tt.args) 338 require.NoError(t, cmd.ExecuteContext(ctx)) 339 340 if tt.added { 341 _, err = kb.Key("testkey") 342 require.NoError(t, err) 343 344 out, err := io.ReadAll(b) 345 require.NoError(t, err) 346 require.Contains(t, string(out), "name: testkey") 347 } else { 348 _, err = kb.Key("testkey") 349 require.Error(t, err) 350 require.Equal(t, "testkey.info: key not found", err.Error()) 351 } 352 }) 353 } 354 }