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