From b5fdb838305ec2e0abc066e6a52429b90c8cd94a Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Fri, 8 Feb 2019 21:45:23 +0100 Subject: [PATCH] Merge PR #3517: Increasing test coverage in keys/client package --- .circleci/config.yml | 2 +- Makefile | 7 +- PENDING.md | 1 + baseapp/baseapp.go | 2 +- client/input.go | 18 ++- client/keys/add.go | 6 +- client/keys/add_test.go | 104 ++++++++++++++++++ client/keys/codec_test.go | 100 +++++++++++++++++ client/keys/delete.go | 32 +++--- client/keys/delete_test.go | 103 ++++++++++++++++++ client/keys/keys/keys.db/LOCK | 0 client/keys/list.go | 21 ++-- client/keys/list_test.go | 57 ++++++++++ client/keys/mnemonic.go | 4 +- client/keys/mnemonic_test.go | 59 ++++++++++ client/keys/root.go | 2 +- client/keys/root_test.go | 22 ++++ client/keys/show.go | 15 ++- client/keys/show_test.go | 146 +++++++++++++++++++++++++ client/keys/update.go | 12 +- client/keys/update_test.go | 64 +++++++++++ client/keys/utils.go | 16 ++- client/lcd/lcd_test.go | 2 +- cmd/gaia/app/sim_test.go | 4 +- cmd/gaia/init/init_test.go | 12 +- crypto/keys/keybase.go | 29 ++--- crypto/keys/keybase_test.go | 77 +++++++++++-- crypto/ledger_integration_test.go | 157 --------------------------- crypto/ledger_mock.go | 79 ++++++++++++++ crypto/ledger_notavail.go | 17 +++ crypto/{ledger.go => ledger_real.go} | 6 +- crypto/ledger_secp256k1.go | 7 +- crypto/ledger_test.go | 140 +++++++++++++++++++++++- server/util.go | 2 +- store/iavl/store.go | 2 +- store/prefix/store_test.go | 10 +- store/rootmulti/proof.go | 6 +- tests/knownValues.go | 6 + tests/test_cover.sh | 4 +- tests/util.go | 19 ++++ types/address.go | 18 +-- types/address_test.go | 6 +- types/errors.go | 5 +- types/store_test.go | 3 +- x/gov/depositsvotes.go | 2 +- x/mock/app.go | 16 +-- x/staking/keeper/delegation.go | 13 ++- x/staking/keeper/test_common.go | 2 +- x/staking/simulation/msgs.go | 12 +- 49 files changed, 1137 insertions(+), 312 deletions(-) create mode 100644 client/keys/add_test.go create mode 100644 client/keys/codec_test.go create mode 100644 client/keys/delete_test.go create mode 100644 client/keys/keys/keys.db/LOCK create mode 100644 client/keys/list_test.go create mode 100644 client/keys/mnemonic_test.go create mode 100644 client/keys/root_test.go create mode 100644 client/keys/show_test.go create mode 100644 client/keys/update_test.go delete mode 100644 crypto/ledger_integration_test.go create mode 100644 crypto/ledger_mock.go create mode 100644 crypto/ledger_notavail.go rename crypto/{ledger.go => ledger_real.go} (81%) create mode 100644 tests/knownValues.go diff --git a/.circleci/config.yml b/.circleci/config.yml index 4de01e36cb99..bbbe7dd9d4d4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -204,7 +204,7 @@ jobs: export VERSION="$(git describe --tags --long | sed 's/v\(.*\)/\1/')" for pkg in $(go list ./... | grep -v github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test | grep -v '/simulation' | circleci tests split --split-by=timings); do id=$(echo "$pkg" | sed 's|[/.]|_|g') - GOCACHE=off go test -timeout 8m -race -coverprofile=/tmp/workspace/profiles/$id.out -covermode=atomic "$pkg" | tee "/tmp/logs/$id-$RANDOM.log" + GOCACHE=off go test -timeout 8m -race -coverprofile=/tmp/workspace/profiles/$id.out -covermode=atomic -tags='ledger test_ledger_mock' "$pkg" | tee "/tmp/logs/$id-$RANDOM.log" done - persist_to_workspace: root: /tmp/workspace diff --git a/Makefile b/Makefile index 91c6fa529546..de913e82caa6 100644 --- a/Makefile +++ b/Makefile @@ -145,10 +145,13 @@ test_cli: @go test -p 4 `go list github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test` -tags=cli_test test_ledger: - @go test `go list github.com/cosmos/cosmos-sdk/crypto` -tags='cgo ledger test_real_ledger' + # First test with mock + @go test `go list github.com/cosmos/cosmos-sdk/crypto` -tags='cgo ledger test_ledger_mock' + # Now test with a real device + @go test -v `go list github.com/cosmos/cosmos-sdk/crypto` -tags='cgo ledger' test_unit: - @VERSION=$(VERSION) go test $(PACKAGES_NOSIMULATION) + @VERSION=$(VERSION) go test $(PACKAGES_NOSIMULATION) -tags='test_ledger_mock' test_race: @VERSION=$(VERSION) go test -race $(PACKAGES_NOSIMULATION) diff --git a/PENDING.md b/PENDING.md index 6b7d20360e60..687030169124 100644 --- a/PENDING.md +++ b/PENDING.md @@ -77,6 +77,7 @@ IMPROVEMENTS * [\#3497](https://github.com/cosmos/cosmos-sdk/issues/3497) `gaiad gentx` supports `--ip` and `--node-id` flags to override defaults. * [\#3518](https://github.com/cosmos/cosmos-sdk/issues/3518) Fix flow in `keys add` to show the mnemonic by default. + * [\#3517](https://github.com/cosmos/cosmos-sdk/pull/3517) Increased test coverage * Gaia * [\#3418](https://github.com/cosmos/cosmos-sdk/issues/3418) Add vesting account diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 5e4601c8d429..c7f7cda86820 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -770,7 +770,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk ) if ctx.BlockGasMeter().GasConsumed() < startingGas { - panic(sdk.ErrorGasOverflow{"tx gas summation"}) + panic(sdk.ErrorGasOverflow{Descriptor: "tx gas summation"}) } } }() diff --git a/client/input.go b/client/input.go index 046508b3bf91..f229d7d3b0a1 100644 --- a/client/input.go +++ b/client/input.go @@ -15,10 +15,26 @@ import ( // MinPassLength is the minimum acceptable password length const MinPassLength = 8 +var currentStdin *bufio.Reader + +func init() { + currentStdin = bufio.NewReader(os.Stdin) +} + // BufferStdin is used to allow reading prompts for stdin // multiple times, when we read from non-tty func BufferStdin() *bufio.Reader { - return bufio.NewReader(os.Stdin) + return currentStdin +} + +// OverrideStdin allows to temporarily override stdin +func OverrideStdin(newStdin *bufio.Reader) (cleanUp func()) { + prevStdin := currentStdin + currentStdin = newStdin + cleanUp = func() { + currentStdin = prevStdin + } + return cleanUp } // GetPassword will prompt for a password one-time (to sign a tx) diff --git a/client/keys/add.go b/client/keys/add.go index ea57b0213db5..d9dfe985fc5d 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -90,7 +90,7 @@ input output - armor encrypted private key (saved to file) */ -func runAddCmd(cmd *cobra.Command, args []string) error { +func runAddCmd(_ *cobra.Command, args []string) error { var kb keys.Keybase var err error var encryptPassword string @@ -265,7 +265,7 @@ func printCreate(info keys.Info, showMnemonic bool, mnemonic string) error { output := viper.Get(cli.OutputFlag) switch output { - case "text": + case OutputFormatText: fmt.Fprintln(os.Stderr) printKeyInfo(info, Bech32KeyOutput) @@ -276,7 +276,7 @@ func printCreate(info keys.Info, showMnemonic bool, mnemonic string) error { fmt.Fprintln(os.Stderr, "") fmt.Fprintln(os.Stderr, mnemonic) } - case "json": + case OutputFormatJSON: out, err := Bech32KeyOutput(info) if err != nil { return err diff --git a/client/keys/add_test.go b/client/keys/add_test.go new file mode 100644 index 000000000000..8f996745ffd9 --- /dev/null +++ b/client/keys/add_test.go @@ -0,0 +1,104 @@ +package keys + +import ( + "bufio" + "net/http" + "strings" + "testing" + + "github.com/pkg/errors" + "github.com/stretchr/testify/require" + + "github.com/spf13/viper" + "github.com/tendermint/tendermint/libs/cli" + + "github.com/cosmos/cosmos-sdk/tests" + + "github.com/cosmos/cosmos-sdk/client" + + "github.com/stretchr/testify/assert" +) + +func Test_runAddCmdBasic(t *testing.T) { + cmd := addKeyCommand() + assert.NotNil(t, cmd) + + // Missing input (enter password) + err := runAddCmd(cmd, []string{"keyname"}) + assert.EqualError(t, err, "EOF") + + // Prepare a keybase + kbHome, kbCleanUp, err := tests.GetTempDir("Test_runDeleteCmd") + assert.NoError(t, err) + assert.NotNil(t, kbHome) + defer kbCleanUp() + viper.Set(cli.HomeFlag, kbHome) + + /// Test Text + viper.Set(cli.OutputFlag, OutputFormatText) + // Now enter password + cleanUp1 := client.OverrideStdin(bufio.NewReader(strings.NewReader("test1234\ntest1234\n"))) + defer cleanUp1() + err = runAddCmd(cmd, []string{"keyname1"}) + assert.NoError(t, err) + + /// Test Text - Replace? >> FAIL + viper.Set(cli.OutputFlag, OutputFormatText) + // Now enter password + cleanUp2 := client.OverrideStdin(bufio.NewReader(strings.NewReader("test1234\ntest1234\n"))) + defer cleanUp2() + err = runAddCmd(cmd, []string{"keyname1"}) + assert.Error(t, err) + + /// Test Text - Replace? Answer >> PASS + viper.Set(cli.OutputFlag, OutputFormatText) + // Now enter password + cleanUp3 := client.OverrideStdin(bufio.NewReader(strings.NewReader("y\ntest1234\ntest1234\n"))) + defer cleanUp3() + err = runAddCmd(cmd, []string{"keyname1"}) + assert.NoError(t, err) + + // Check JSON + viper.Set(cli.OutputFlag, OutputFormatJSON) + // Now enter password + cleanUp4 := client.OverrideStdin(bufio.NewReader(strings.NewReader("test1234\ntest1234\n"))) + defer cleanUp4() + err = runAddCmd(cmd, []string{"keyname2"}) + assert.NoError(t, err) +} + +type MockResponseWriter struct { + dataHeaderStatus int + dataBody []byte +} + +func (MockResponseWriter) Header() http.Header { + panic("Unexpected call!") +} + +func (w *MockResponseWriter) Write(data []byte) (int, error) { + w.dataBody = append(w.dataBody, data...) + return len(data), nil +} + +func (w *MockResponseWriter) WriteHeader(statusCode int) { + w.dataHeaderStatus = statusCode +} + +func TestCheckAndWriteErrorResponse(t *testing.T) { + mockRW := MockResponseWriter{} + + mockRW.WriteHeader(100) + assert.Equal(t, 100, mockRW.dataHeaderStatus) + + detected := CheckAndWriteErrorResponse(&mockRW, http.StatusBadRequest, errors.New("some ERROR")) + require.True(t, detected) + require.Equal(t, http.StatusBadRequest, mockRW.dataHeaderStatus) + require.Equal(t, "some ERROR", string(mockRW.dataBody[:])) + + mockRW = MockResponseWriter{} + detected = CheckAndWriteErrorResponse(&mockRW, http.StatusBadRequest, nil) + require.False(t, detected) + require.Equal(t, 0, mockRW.dataHeaderStatus) + require.Equal(t, "", string(mockRW.dataBody[:])) +} diff --git a/client/keys/codec_test.go b/client/keys/codec_test.go new file mode 100644 index 000000000000..3af946e59bd1 --- /dev/null +++ b/client/keys/codec_test.go @@ -0,0 +1,100 @@ +package keys + +import ( + "fmt" + "reflect" + "testing" + + "github.com/stretchr/testify/require" +) + +type testCases struct { + Keys []KeyOutput + Answers []KeyOutput + JSON [][]byte +} + +func getTestCases() testCases { + return testCases{ + []KeyOutput{ + {"A", "B", "C", "D", "E"}, + {"A", "B", "C", "D", ""}, + {"", "B", "C", "D", ""}, + {"", "", "", "", ""}, + }, + make([]KeyOutput, 4), + [][]byte{ + []byte(`{"name":"A","type":"B","address":"C","pub_key":"D","mnemonic":"E"}`), + []byte(`{"name":"A","type":"B","address":"C","pub_key":"D"}`), + []byte(`{"name":"","type":"B","address":"C","pub_key":"D"}`), + []byte(`{"name":"","type":"","address":"","pub_key":""}`), + }, + } +} + +func TestMarshalJSON(t *testing.T) { + type args struct { + o KeyOutput + } + + data := getTestCases() + + tests := []struct { + name string + args args + want []byte + wantErr bool + }{ + {"basic", args{data.Keys[0]}, []byte(data.JSON[0]), false}, + {"mnemonic is optional", args{data.Keys[1]}, []byte(data.JSON[1]), false}, + + // REVIEW: Are the next results expected?? + {"empty name", args{data.Keys[2]}, []byte(data.JSON[2]), false}, + {"empty object", args{data.Keys[3]}, []byte(data.JSON[3]), false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := MarshalJSON(tt.args.o) + if (err != nil) != tt.wantErr { + t.Errorf("MarshalJSON() error = %v, wantErr %v", err, tt.wantErr) + return + } + fmt.Printf("%s\n", got) + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("MarshalJSON() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestUnmarshalJSON(t *testing.T) { + type args struct { + bz []byte + ptr interface{} + } + + data := getTestCases() + + tests := []struct { + name string + args args + wantErr bool + }{ + {"basic", args{data.JSON[0], &data.Answers[0]}, false}, + {"mnemonic is optional", args{data.JSON[1], &data.Answers[1]}, false}, + + // REVIEW: Are the next results expected?? + {"empty name", args{data.JSON[2], &data.Answers[2]}, false}, + {"empty object", args{data.JSON[3], &data.Answers[3]}, false}, + } + for idx, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := UnmarshalJSON(tt.args.bz, tt.args.ptr); (err != nil) != tt.wantErr { + t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr) + } + + // Confirm deserialized objects are the same + require.Equal(t, data.Keys[idx], data.Answers[idx]) + }) + } +} diff --git a/client/keys/delete.go b/client/keys/delete.go index 11a9cf1afd27..614bcce7c98d 100644 --- a/client/keys/delete.go +++ b/client/keys/delete.go @@ -91,6 +91,17 @@ func runDeleteCmd(cmd *cobra.Command, args []string) error { return nil } +func confirmDeletion(buf *bufio.Reader) error { + answer, err := client.GetConfirmation("Key reference will be deleted. Continue?", buf) + if err != nil { + return err + } + if !answer { + return errors.New("aborted") + } + return nil +} + //////////////////////// // REST @@ -110,42 +121,31 @@ func DeleteKeyRequestHandler(w http.ResponseWriter, r *http.Request) { err := decoder.Decode(&m) if err != nil { w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(err.Error())) + _, _ = w.Write([]byte(err.Error())) return } kb, err = NewKeyBaseFromHomeFlag() if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) + _, _ = w.Write([]byte(err.Error())) return } err = kb.Delete(name, m.Password, false) if keyerror.IsErrKeyNotFound(err) { w.WriteHeader(http.StatusNotFound) - w.Write([]byte(err.Error())) + _, _ = w.Write([]byte(err.Error())) return } else if keyerror.IsErrWrongPassword(err) { w.WriteHeader(http.StatusUnauthorized) - w.Write([]byte(err.Error())) + _, _ = w.Write([]byte(err.Error())) return } else if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) + _, _ = w.Write([]byte(err.Error())) return } w.WriteHeader(http.StatusOK) } - -func confirmDeletion(buf *bufio.Reader) error { - answer, err := client.GetConfirmation("Key reference will be deleted. Continue?", buf) - if err != nil { - return err - } - if !answer { - return errors.New("aborted") - } - return nil -} diff --git a/client/keys/delete_test.go b/client/keys/delete_test.go new file mode 100644 index 000000000000..43da6b91800a --- /dev/null +++ b/client/keys/delete_test.go @@ -0,0 +1,103 @@ +package keys + +import ( + "bufio" + "strings" + "testing" + + "github.com/cosmos/cosmos-sdk/client" + + "github.com/cosmos/cosmos-sdk/tests" + "github.com/spf13/viper" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/cli" +) + +func Test_runDeleteCmd(t *testing.T) { + deleteKeyCommand := deleteKeyCommand() + + yesF, _ := deleteKeyCommand.Flags().GetBool(flagYes) + forceF, _ := deleteKeyCommand.Flags().GetBool(flagForce) + assert.False(t, yesF) + assert.False(t, forceF) + + fakeKeyName1 := "runDeleteCmd_Key1" + fakeKeyName2 := "runDeleteCmd_Key2" + + // Now add a temporary keybase + kbHome, cleanUp, err := tests.GetTempDir("Test_runDeleteCmd") + assert.NoError(t, err) + defer cleanUp() + viper.Set(cli.HomeFlag, kbHome) + + // Now + kb, err := NewKeyBaseFromHomeFlag() + assert.NoError(t, err) + _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", 0, 0) + assert.NoError(t, err) + _, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", 0, 1) + assert.NoError(t, err) + + err = runDeleteCmd(deleteKeyCommand, []string{"blah"}) + require.Error(t, err) + require.Equal(t, "Key blah not found", err.Error()) + + // User confirmation missing + err = runDeleteCmd(deleteKeyCommand, []string{fakeKeyName1}) + require.Error(t, err) + require.Equal(t, "EOF", err.Error()) + + { + _, err = kb.Get(fakeKeyName1) + require.NoError(t, err) + + // Now there is a confirmation + cleanUp := client.OverrideStdin(bufio.NewReader(strings.NewReader("y\n"))) + defer cleanUp() + err = runDeleteCmd(deleteKeyCommand, []string{fakeKeyName1}) + require.NoError(t, err) + + _, err = kb.Get(fakeKeyName1) + require.Error(t, err) // Key1 is gone + } + + viper.Set(flagYes, true) + _, err = kb.Get(fakeKeyName2) + require.NoError(t, err) + err = runDeleteCmd(deleteKeyCommand, []string{fakeKeyName2}) + require.NoError(t, err) + _, err = kb.Get(fakeKeyName2) + require.Error(t, err) // Key2 is gone + + // TODO: Write another case for !keys.Local +} + +func Test_confirmDeletion(t *testing.T) { + type args struct { + buf *bufio.Reader + } + + answerYes := bufio.NewReader(strings.NewReader("y\n")) + answerYes2 := bufio.NewReader(strings.NewReader("Y\n")) + answerNo := bufio.NewReader(strings.NewReader("n\n")) + answerInvalid := bufio.NewReader(strings.NewReader("245\n")) + + tests := []struct { + name string + args args + wantErr bool + }{ + {"Y", args{answerYes}, false}, + {"y", args{answerYes2}, false}, + {"N", args{answerNo}, true}, + {"BAD", args{answerInvalid}, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := confirmDeletion(tt.args.buf); (err != nil) != tt.wantErr { + t.Errorf("confirmDeletion() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/client/keys/keys/keys.db/LOCK b/client/keys/keys/keys.db/LOCK new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/client/keys/list.go b/client/keys/list.go index ccd94dee37af..81a45d0b70eb 100644 --- a/client/keys/list.go +++ b/client/keys/list.go @@ -6,15 +6,14 @@ import ( "github.com/spf13/cobra" ) -// CMD - -// listKeysCmd represents the list command -var listKeysCmd = &cobra.Command{ - Use: "list", - Short: "List all keys", - Long: `Return a list of all public keys stored by this key manager +func listKeysCmd() *cobra.Command { + return &cobra.Command{ + Use: "list", + Short: "List all keys", + Long: `Return a list of all public keys stored by this key manager along with their associated name and address.`, - RunE: runListCmd, + RunE: runListCmd, + } } func runListCmd(cmd *cobra.Command, args []string) error { @@ -39,13 +38,13 @@ func QueryKeysRequestHandler(indent bool) http.HandlerFunc { kb, err := NewKeyBaseFromHomeFlag() if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) + _, _ = w.Write([]byte(err.Error())) return } infos, err := kb.List() if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) + _, _ = w.Write([]byte(err.Error())) return } // an empty list will be JSONized as null, but we want to keep the empty list @@ -56,7 +55,7 @@ func QueryKeysRequestHandler(indent bool) http.HandlerFunc { keysOutput, err := Bech32KeysOutput(infos) if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) + _, _ = w.Write([]byte(err.Error())) return } PostProcessResponse(w, cdc, keysOutput, indent) diff --git a/client/keys/list_test.go b/client/keys/list_test.go new file mode 100644 index 000000000000..b82670e2b87b --- /dev/null +++ b/client/keys/list_test.go @@ -0,0 +1,57 @@ +package keys + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/tests" + "github.com/stretchr/testify/assert" + + "github.com/spf13/viper" + "github.com/tendermint/tendermint/libs/cli" + + "github.com/spf13/cobra" +) + +func Test_runListCmd(t *testing.T) { + type args struct { + cmd *cobra.Command + args []string + } + + cmdBasic := listKeysCmd() + + // Prepare some keybases + kbHome1, cleanUp1, err := tests.GetTempDir("Test_runListCmd") + defer cleanUp1() + assert.NoError(t, err) + // Do nothing, leave home1 empty + + kbHome2, cleanUp2, err := tests.GetTempDir("Test_runListCmd") + defer cleanUp2() + viper.Set(cli.HomeFlag, kbHome2) + assert.NoError(t, err) + + kb, err := NewKeyBaseFromHomeFlag() + assert.NoError(t, err) + _, err = kb.CreateAccount("something", tests.TestMnemonic, "", "", 0, 0) + assert.NoError(t, err) + + testData := []struct { + name string + kbDir string + args args + wantErr bool + }{ + {"invalid keybase", "/dev/null", args{cmdBasic, []string{}}, true}, + {"keybase: empty", kbHome1, args{cmdBasic, []string{}}, false}, + {"keybase: w/key", kbHome2, args{cmdBasic, []string{}}, false}, + } + for _, tt := range testData { + t.Run(tt.name, func(t *testing.T) { + viper.Set(cli.HomeFlag, tt.kbDir) + if err := runListCmd(tt.args.cmd, tt.args.args); (err != nil) != tt.wantErr { + t.Errorf("runListCmd() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/client/keys/mnemonic.go b/client/keys/mnemonic.go index ffa72fff4097..64641e1c480b 100644 --- a/client/keys/mnemonic.go +++ b/client/keys/mnemonic.go @@ -43,9 +43,7 @@ func runMnemonicCmd(cmd *cobra.Command, args []string) error { if len(inputEntropy) < 43 { return fmt.Errorf("256-bits is 43 characters in Base-64, and 100 in Base-6. You entered %v, and probably want more", len(inputEntropy)) } - conf, err := client.GetConfirmation( - fmt.Sprintf("> Input length: %d", len(inputEntropy)), - buf) + conf, err := client.GetConfirmation(fmt.Sprintf("> Input length: %d", len(inputEntropy)), buf) if err != nil { return err } diff --git a/client/keys/mnemonic_test.go b/client/keys/mnemonic_test.go new file mode 100644 index 000000000000..64fd404a17e4 --- /dev/null +++ b/client/keys/mnemonic_test.go @@ -0,0 +1,59 @@ +package keys + +import ( + "bufio" + "strings" + "testing" + + "github.com/cosmos/cosmos-sdk/client" + + "github.com/stretchr/testify/assert" + + "github.com/stretchr/testify/require" +) + +func Test_RunMnemonicCmdNormal(t *testing.T) { + cmdBasic := mnemonicKeyCommand() + err := runMnemonicCmd(cmdBasic, []string{}) + require.NoError(t, err) +} + +func Test_RunMnemonicCmdUser(t *testing.T) { + cmdUser := mnemonicKeyCommand() + err := cmdUser.Flags().Set(flagUserEntropy, "1") + assert.NoError(t, err) + + err = runMnemonicCmd(cmdUser, []string{}) + require.Error(t, err) + require.Equal(t, "EOF", err.Error()) + + // Try again + cleanUp := client.OverrideStdin(bufio.NewReader(strings.NewReader("Hi!\n"))) + defer cleanUp() + err = runMnemonicCmd(cmdUser, []string{}) + require.Error(t, err) + require.Equal(t, + "256-bits is 43 characters in Base-64, and 100 in Base-6. You entered 3, and probably want more", + err.Error()) + + // Now provide "good" entropy :) + fakeEntropy := strings.Repeat(":)", 40) + "\ny\n" // entropy + accept count + cleanUp2 := client.OverrideStdin(bufio.NewReader(strings.NewReader(fakeEntropy))) + defer cleanUp2() + err = runMnemonicCmd(cmdUser, []string{}) + require.NoError(t, err) + + // Now provide "good" entropy but no answer + fakeEntropy = strings.Repeat(":)", 40) + "\n" // entropy + accept count + cleanUp3 := client.OverrideStdin(bufio.NewReader(strings.NewReader(fakeEntropy))) + defer cleanUp3() + err = runMnemonicCmd(cmdUser, []string{}) + require.Error(t, err) + + // Now provide "good" entropy but say no + fakeEntropy = strings.Repeat(":)", 40) + "\nn\n" // entropy + accept count + cleanUp4 := client.OverrideStdin(bufio.NewReader(strings.NewReader(fakeEntropy))) + defer cleanUp4() + err = runMnemonicCmd(cmdUser, []string{}) + require.NoError(t, err) +} diff --git a/client/keys/root.go b/client/keys/root.go index f747d84a0489..5b70025fd008 100644 --- a/client/keys/root.go +++ b/client/keys/root.go @@ -22,7 +22,7 @@ func Commands() *cobra.Command { cmd.AddCommand( mnemonicKeyCommand(), addKeyCommand(), - listKeysCmd, + listKeysCmd(), showKeysCmd(), client.LineBreak, deleteKeyCommand(), diff --git a/client/keys/root_test.go b/client/keys/root_test.go new file mode 100644 index 000000000000..ef7671593dc9 --- /dev/null +++ b/client/keys/root_test.go @@ -0,0 +1,22 @@ +package keys + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/gorilla/mux" +) + +func TestCommands(t *testing.T) { + rootCommands := Commands() + assert.NotNil(t, rootCommands) + + // Commands are registered + assert.Equal(t, 7, len(rootCommands.Commands())) +} + +func TestRegisterRoutes(t *testing.T) { + fakeRouter := mux.Router{} + RegisterRoutes(&fakeRouter, false) +} diff --git a/client/keys/show.go b/client/keys/show.go index 9e2901aa8714..4c1ddf216c2e 100644 --- a/client/keys/show.go +++ b/client/keys/show.go @@ -93,7 +93,12 @@ func runShowCmd(cmd *cobra.Command, args []string) (err error) { isShowAddr := viper.GetBool(FlagAddress) isShowPubKey := viper.GetBool(FlagPublicKey) - isOutputSet := cmd.Flag(cli.OutputFlag).Changed + + isOutputSet := false + tmp := cmd.Flag(cli.OutputFlag) + if tmp != nil { + isOutputSet = tmp.Changed + } if isShowAddr && isShowPubKey { return errors.New("cannot use both --address and --pubkey at once") @@ -161,25 +166,25 @@ func GetKeyRequestHandler(indent bool) http.HandlerFunc { bechKeyOut, err := getBechKeyOut(bechPrefix) if err != nil { w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(err.Error())) + _, _ = w.Write([]byte(err.Error())) return } info, err := GetKeyInfo(name) if keyerror.IsErrKeyNotFound(err) { w.WriteHeader(http.StatusNotFound) - w.Write([]byte(err.Error())) + _, _ = w.Write([]byte(err.Error())) return } else if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) + _, _ = w.Write([]byte(err.Error())) return } keyOutput, err := bechKeyOut(info) if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) + _, _ = w.Write([]byte(err.Error())) return } diff --git a/client/keys/show_test.go b/client/keys/show_test.go new file mode 100644 index 000000000000..d4ba0ff8c1b0 --- /dev/null +++ b/client/keys/show_test.go @@ -0,0 +1,146 @@ +package keys + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/tests" + "github.com/spf13/viper" + "github.com/tendermint/tendermint/libs/cli" + + "github.com/tendermint/tendermint/crypto/secp256k1" + + "github.com/stretchr/testify/assert" + + "github.com/cosmos/cosmos-sdk/crypto/keys" +) + +func Test_multiSigKey_Properties(t *testing.T) { + tmpKey1 := secp256k1.GenPrivKeySecp256k1([]byte("mySecret")) + + tmp := multiSigKey{ + name: "myMultisig", + key: tmpKey1.PubKey(), + } + + assert.Equal(t, "myMultisig", tmp.GetName()) + assert.Equal(t, keys.TypeLocal, tmp.GetType()) + assert.Equal(t, "015ABFFB09DB738A45745A91E8C401423ECE4016", tmp.GetPubKey().Address().String()) + assert.Equal(t, "cosmos1q9dtl7cfmdec53t5t2g733qpgglvusqk6xdntl", tmp.GetAddress().String()) +} + +func Test_showKeysCmd(t *testing.T) { + cmd := showKeysCmd() + assert.NotNil(t, cmd) + assert.Equal(t, "false", cmd.Flag(FlagAddress).DefValue) + assert.Equal(t, "false", cmd.Flag(FlagPublicKey).DefValue) +} + +func Test_runShowCmd(t *testing.T) { + cmd := showKeysCmd() + + err := runShowCmd(cmd, []string{"invalid"}) + assert.EqualError(t, err, "Key invalid not found") + + err = runShowCmd(cmd, []string{"invalid1", "invalid2"}) + assert.EqualError(t, err, "Key invalid1 not found") + + // Prepare a key base + // Now add a temporary keybase + kbHome, cleanUp, err := tests.GetTempDir("Test_runShowCmd") + assert.NoError(t, err) + defer cleanUp() + viper.Set(cli.HomeFlag, kbHome) + + fakeKeyName1 := "runShowCmd_Key1" + fakeKeyName2 := "runShowCmd_Key2" + kb, err := NewKeyBaseFromHomeFlag() + assert.NoError(t, err) + _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", 0, 0) + assert.NoError(t, err) + _, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", 0, 1) + assert.NoError(t, err) + + // Now try single key + err = runShowCmd(cmd, []string{fakeKeyName1}) + assert.EqualError(t, err, "invalid Bech32 prefix encoding provided: ") + + // Now try single key - set bech to acc + viper.Set(FlagBechPrefix, "acc") + err = runShowCmd(cmd, []string{fakeKeyName1}) + assert.NoError(t, err) + + // Now try multisig key - set bech to acc + viper.Set(FlagBechPrefix, "acc") + err = runShowCmd(cmd, []string{fakeKeyName1, fakeKeyName2}) + assert.EqualError(t, err, "threshold must be a positive integer") + + // Now try multisig key - set bech to acc + threshold=2 + viper.Set(FlagBechPrefix, "acc") + viper.Set(flagMultiSigThreshold, 2) + err = runShowCmd(cmd, []string{fakeKeyName1, fakeKeyName2}) + assert.NoError(t, err) + + // TODO: Capture stdout and compare +} + +func Test_validateMultisigThreshold(t *testing.T) { + type args struct { + k int + nKeys int + } + tests := []struct { + name string + args args + wantErr bool + }{ + {"zeros", args{0, 0}, true}, + {"1-0", args{1, 0}, true}, + {"1-1", args{1, 1}, false}, + {"1-2", args{1, 1}, false}, + {"1-2", args{2, 1}, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := validateMultisigThreshold(tt.args.k, tt.args.nKeys); (err != nil) != tt.wantErr { + t.Errorf("validateMultisigThreshold() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func Test_getBechKeyOut(t *testing.T) { + type args struct { + bechPrefix string + } + tests := []struct { + name string + args args + want bechKeyOutFn + wantErr bool + }{ + {"empty", args{""}, nil, true}, + {"wrong", args{"???"}, nil, true}, + {"acc", args{"acc"}, Bech32KeyOutput, false}, + {"val", args{"val"}, Bech32ValKeyOutput, false}, + {"cons", args{"cons"}, Bech32ConsKeyOutput, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := getBechKeyOut(tt.args.bechPrefix) + if (err != nil) != tt.wantErr { + t.Errorf("getBechKeyOut() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if !tt.wantErr { + assert.NotNil(t, got) + } + + // TODO: Still not possible to compare functions + // Maybe in next release: https://github.com/stretchr/testify/issues/182 + //if &got != &tt.want { + // t.Errorf("getBechKeyOut() = %v, want %v", got, tt.want) + //} + }) + } +} diff --git a/client/keys/update.go b/client/keys/update.go index cbb704887ef1..d3a03f22c7c3 100644 --- a/client/keys/update.go +++ b/client/keys/update.go @@ -8,7 +8,7 @@ import ( "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client" - keys "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/spf13/cobra" @@ -73,14 +73,14 @@ func UpdateKeyRequestHandler(w http.ResponseWriter, r *http.Request) { err := decoder.Decode(&m) if err != nil { w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(err.Error())) + _, _ = w.Write([]byte(err.Error())) return } kb, err = NewKeyBaseFromHomeFlag() if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) + _, _ = w.Write([]byte(err.Error())) return } @@ -89,15 +89,15 @@ func UpdateKeyRequestHandler(w http.ResponseWriter, r *http.Request) { err = kb.Update(name, m.OldPassword, getNewpass) if keyerror.IsErrKeyNotFound(err) { w.WriteHeader(http.StatusNotFound) - w.Write([]byte(err.Error())) + _, _ = w.Write([]byte(err.Error())) return } else if keyerror.IsErrWrongPassword(err) { w.WriteHeader(http.StatusUnauthorized) - w.Write([]byte(err.Error())) + _, _ = w.Write([]byte(err.Error())) return } else if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) + _, _ = w.Write([]byte(err.Error())) return } diff --git a/client/keys/update_test.go b/client/keys/update_test.go new file mode 100644 index 000000000000..c54c428e3c13 --- /dev/null +++ b/client/keys/update_test.go @@ -0,0 +1,64 @@ +package keys + +import ( + "bufio" + "strings" + "testing" + + "github.com/cosmos/cosmos-sdk/client" + + "github.com/cosmos/cosmos-sdk/tests" + "github.com/spf13/viper" + "github.com/tendermint/tendermint/libs/cli" + + "github.com/stretchr/testify/assert" +) + +func Test_updateKeyCommand(t *testing.T) { + cmd := updateKeyCommand() + assert.NotNil(t, cmd) + // No flags or defaults to validate +} + +func Test_runUpdateCmd(t *testing.T) { + fakeKeyName1 := "runUpdateCmd_Key1" + fakeKeyName2 := "runUpdateCmd_Key2" + + cmd := updateKeyCommand() + + // fails because it requests a password + err := runUpdateCmd(cmd, []string{fakeKeyName1}) + assert.EqualError(t, err, "EOF") + + cleanUp := client.OverrideStdin(bufio.NewReader(strings.NewReader("pass1234\n"))) + defer cleanUp() + + // try again + err = runUpdateCmd(cmd, []string{fakeKeyName1}) + assert.EqualError(t, err, "Key runUpdateCmd_Key1 not found") + + // Prepare a key base + // Now add a temporary keybase + kbHome, cleanUp1, err := tests.GetTempDir("Test_runShowCmd") + assert.NoError(t, err) + defer cleanUp1() + viper.Set(cli.HomeFlag, kbHome) + + kb, err := NewKeyBaseFromHomeFlag() + assert.NoError(t, err) + _, err = kb.CreateAccount(fakeKeyName1, tests.TestMnemonic, "", "", 0, 0) + assert.NoError(t, err) + _, err = kb.CreateAccount(fakeKeyName2, tests.TestMnemonic, "", "", 0, 1) + assert.NoError(t, err) + + // Try again now that we have keys + cleanUp2 := client.OverrideStdin(bufio.NewReader(strings.NewReader("pass1234\nNew1234\nNew1234"))) + defer cleanUp2() + + // Incorrect key type + err = runUpdateCmd(cmd, []string{fakeKeyName1}) + assert.EqualError(t, err, "locally stored key required. Received: keys.offlineInfo") + + // TODO: Check for other type types? + +} diff --git a/client/keys/utils.go b/client/keys/utils.go index 5c0b6db19fb4..d772b815144c 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -15,7 +15,11 @@ import ( ) // KeyDBName is the directory under root where we store the keys -const KeyDBName = "keys" +const ( + KeyDBName = "keys" + OutputFormatText = "text" + OutputFormatJSON = "json" +) type bechKeyOutFn func(keyInfo keys.Info) (KeyOutput, error) @@ -157,7 +161,7 @@ func printKeyInfo(keyInfo keys.Info, bechKeyOut bechKeyOutFn) { } switch viper.Get(cli.OutputFlag) { - case "text": + case OutputFormatText: fmt.Printf("NAME:\tTYPE:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n") printKeyOutput(ko) case "json": @@ -176,12 +180,12 @@ func printInfos(infos []keys.Info) { panic(err) } switch viper.Get(cli.OutputFlag) { - case "text": + case OutputFormatText: fmt.Printf("NAME:\tTYPE:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n") for _, ko := range kos { printKeyOutput(ko) } - case "json": + case OutputFormatJSON: out, err := MarshalJSON(kos) if err != nil { panic(err) @@ -225,12 +229,12 @@ func PostProcessResponse(w http.ResponseWriter, cdc *codec.Codec, response inter } if err != nil { w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(err.Error())) + _, _ = w.Write([]byte(err.Error())) return } case []byte: output = response.([]byte) } w.Header().Set("Content-Type", "application/json") - w.Write(output) + _, _ = w.Write(output) } diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index ff9da7ace97e..7648d86a3012 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -175,7 +175,7 @@ func TestVersion(t *testing.T) { reg, err := regexp.Compile(`\d+\.\d+\.\d+.*`) require.Nil(t, err) match := reg.MatchString(body) - require.True(t, match, body, fmt.Sprintf("%s", body)) + require.True(t, match, body, body) // node info res, body = Request(t, port, "GET", "/node_version", nil) diff --git a/cmd/gaia/app/sim_test.go b/cmd/gaia/app/sim_test.go index 32bb46113bc6..6e0c1f3292e6 100644 --- a/cmd/gaia/app/sim_test.go +++ b/cmd/gaia/app/sim_test.go @@ -301,8 +301,8 @@ func fauxMerkleModeOpt(bapp *baseapp.BaseApp) { // /usr/local/go/bin/go test -benchmem -run=^$ github.com/cosmos/cosmos-sdk/cmd/gaia/app -bench ^BenchmarkFullGaiaSimulation$ -SimulationCommit=true -cpuprofile cpu.out func BenchmarkFullGaiaSimulation(b *testing.B) { // Setup Gaia application - var logger log.Logger - logger = log.NewNopLogger() + logger := log.NewNopLogger() + var db dbm.DB dir, _ := ioutil.TempDir("", "goleveldb-gaia-sim") db, _ = dbm.NewGoLevelDB("Simulation", dir) diff --git a/cmd/gaia/init/init_test.go b/cmd/gaia/init/init_test.go index e10347334f17..8dac1695286b 100644 --- a/cmd/gaia/init/init_test.go +++ b/cmd/gaia/init/init_test.go @@ -8,20 +8,16 @@ import ( "testing" "time" - "github.com/tendermint/tendermint/libs/cli" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/cmd/gaia/app" - + "github.com/cosmos/cosmos-sdk/server" + "github.com/cosmos/cosmos-sdk/server/mock" + "github.com/spf13/viper" "github.com/stretchr/testify/require" abciServer "github.com/tendermint/tendermint/abci/server" tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" + "github.com/tendermint/tendermint/libs/cli" "github.com/tendermint/tendermint/libs/log" - - "github.com/cosmos/cosmos-sdk/server" - "github.com/cosmos/cosmos-sdk/server/mock" - - "github.com/spf13/viper" ) func TestInitCmd(t *testing.T) { diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index f6b6ecd88198..1a7b06d165f0 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -4,6 +4,7 @@ import ( "bufio" "fmt" "os" + "reflect" "strings" "errors" @@ -147,13 +148,13 @@ func (kb dbKeybase) CreateLedger(name string, algo SigningAlgo, account uint32, } pub := priv.PubKey() - return kb.writeLedgerKey(pub, *hdPath, name), nil + return kb.writeLedgerKey(name, pub, *hdPath), nil } // CreateOffline creates a new reference to an offline keypair // It returns the created key info func (kb dbKeybase) CreateOffline(name string, pub tmcrypto.PubKey) (Info, error) { - return kb.writeOfflineKey(pub, name), nil + return kb.writeOfflineKey(name, pub), nil } func (kb *dbKeybase) persistDerivedKey(seed []byte, passwd, name, fullHdPath string) (info Info, err error) { @@ -167,10 +168,10 @@ func (kb *dbKeybase) persistDerivedKey(seed []byte, passwd, name, fullHdPath str // if we have a password, use it to encrypt the private key and store it // else store the public key only if passwd != "" { - info = kb.writeLocalKey(secp256k1.PrivKeySecp256k1(derivedPriv), name, passwd) + info = kb.writeLocalKey(name, secp256k1.PrivKeySecp256k1(derivedPriv), passwd) } else { pubk := secp256k1.PrivKeySecp256k1(derivedPriv).PubKey() - info = kb.writeOfflineKey(pubk, name) + info = kb.writeOfflineKey(name, pubk) } return } @@ -342,7 +343,7 @@ func (kb dbKeybase) ImportPubKey(name string, armor string) (err error) { if err != nil { return } - kb.writeOfflineKey(pubKey, name) + kb.writeOfflineKey(name, pubKey) return } @@ -390,10 +391,10 @@ func (kb dbKeybase) Update(name, oldpass string, getNewpass func() (string, erro if err != nil { return err } - kb.writeLocalKey(key, name, newpass) + kb.writeLocalKey(name, key, newpass) return nil default: - return fmt.Errorf("locally stored key required") + return fmt.Errorf("locally stored key required. Received: %v", reflect.TypeOf(info).String()) } } @@ -402,29 +403,29 @@ func (kb dbKeybase) CloseDB() { kb.db.Close() } -func (kb dbKeybase) writeLocalKey(priv tmcrypto.PrivKey, name, passphrase string) Info { +func (kb dbKeybase) writeLocalKey(name string, priv tmcrypto.PrivKey, passphrase string) Info { // encrypt private key using passphrase privArmor := mintkey.EncryptArmorPrivKey(priv, passphrase) // make Info pub := priv.PubKey() info := newLocalInfo(name, pub, privArmor) - kb.writeInfo(info, name) + kb.writeInfo(name, info) return info } -func (kb dbKeybase) writeLedgerKey(pub tmcrypto.PubKey, path hd.BIP44Params, name string) Info { +func (kb dbKeybase) writeLedgerKey(name string, pub tmcrypto.PubKey, path hd.BIP44Params) Info { info := newLedgerInfo(name, pub, path) - kb.writeInfo(info, name) + kb.writeInfo(name, info) return info } -func (kb dbKeybase) writeOfflineKey(pub tmcrypto.PubKey, name string) Info { +func (kb dbKeybase) writeOfflineKey(name string, pub tmcrypto.PubKey) Info { info := newOfflineInfo(name, pub) - kb.writeInfo(info, name) + kb.writeInfo(name, info) return info } -func (kb dbKeybase) writeInfo(info Info, name string) { +func (kb dbKeybase) writeInfo(name string, info Info) { // write the info by key key := infoKey(name) kb.db.SetSync(key, writeInfo(info)) diff --git a/crypto/keys/keybase_test.go b/crypto/keys/keybase_test.go index 36a05d3741ff..f5c214a37b72 100644 --- a/crypto/keys/keybase_test.go +++ b/crypto/keys/keybase_test.go @@ -2,6 +2,7 @@ package keys import ( "fmt" + "io/ioutil" "testing" "github.com/stretchr/testify/assert" @@ -9,26 +10,84 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys/hd" "github.com/cosmos/cosmos-sdk/crypto/keys/mintkey" - + "github.com/cosmos/cosmos-sdk/types" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" - dbm "github.com/tendermint/tendermint/libs/db" - - "github.com/cosmos/cosmos-sdk/types" ) func init() { mintkey.BcryptSecurityParameter = 1 } +func TestKeybaseOpenClose(t *testing.T) { + dir, err := ioutil.TempDir("", "TestKeybaseOpenClose") + assert.Nil(t, err) + + kb := New(dbm.NewDB("TestKeybaseOpenClose", dbm.LevelDBBackend, dir)) + kb.CloseDB() + + // The DB has been closed. At the moment, the expected behaviour is to panic + assert.Panics(t, func() { + _, _ = kb.CreateAccount( + "some_account", + "key pair crucial catch public canyon evil outer stage ten gym tornado", + "", "", 0, 1) + }) +} + +func TestLanguage(t *testing.T) { + kb := New(dbm.NewMemDB()) + _, _, err := kb.CreateMnemonic("something", Japanese, "no_pass", Secp256k1) + assert.Error(t, err) + assert.Equal(t, "unsupported language: only english is supported", err.Error()) +} + +func TestCreateAccountInvalidMnemonic(t *testing.T) { + kb := New(dbm.NewMemDB()) + _, err := kb.CreateAccount( + "some_account", + "malarkey pair crucial catch public canyon evil outer stage ten gym tornado", + "", "", 0, 1) + assert.Error(t, err) + assert.Equal(t, "Invalid mnemonic", err.Error()) +} + +func TestCreateLedgerUnsupportedAlgo(t *testing.T) { + kb := New(dbm.NewMemDB()) + _, err := kb.CreateLedger("some_account", Ed25519, 0, 1) + assert.Error(t, err) + assert.Equal(t, "unsupported signing algo: only secp256k1 is supported", err.Error()) +} + +func TestCreateLedger(t *testing.T) { + kb := New(dbm.NewMemDB()) + + // test_cover and test_unit will result in different answers + // test_cover does not compile some dependencies so ledger is disabled + // test_unit may add a ledger mock + // both cases are acceptable + ledger, err := kb.CreateLedger("some_account", Secp256k1, 0, 1) + + if err != nil { + assert.Error(t, err) + assert.Equal(t, "ledger nano S: support for ledger devices is not available in this executable", err.Error()) + assert.Nil(t, ledger) + } else { + // The mock is available, check that the address is correct + pubKey := ledger.GetPubKey() + addr, err := sdk.Bech32ifyAccPub(pubKey) + assert.NoError(t, err) + assert.Equal(t, "cosmospub1addwnpepqfsdqjr68h7wjg5wacksmqaypasnra232fkgu5sxdlnlu8j22ztxvlqvd65", addr) + } +} + // TestKeyManagement makes sure we can manipulate these keys well func TestKeyManagement(t *testing.T) { // make the storage with reasonable defaults db := dbm.NewMemDB() - cstore := New( - db, - ) + cstore := New(db) algo := Secp256k1 n1, n2, n3 := "personal", "business", "other" @@ -112,9 +171,7 @@ func TestKeyManagement(t *testing.T) { // TestSignVerify does some detailed checks on how we sign and validate // signatures func TestSignVerify(t *testing.T) { - cstore := New( - dbm.NewMemDB(), - ) + cstore := New(dbm.NewMemDB()) algo := Secp256k1 n1, n2, n3 := "some dude", "a dudette", "dude-ish" diff --git a/crypto/ledger_integration_test.go b/crypto/ledger_integration_test.go deleted file mode 100644 index 30c66c765286..000000000000 --- a/crypto/ledger_integration_test.go +++ /dev/null @@ -1,157 +0,0 @@ -// +build cgo,ledger,test_real_ledger - -package crypto - -import ( - "fmt" - "testing" - - "github.com/cosmos/cosmos-sdk/crypto/keys/hd" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/crypto/encoding/amino" - ledger "github.com/zondax/ledger-cosmos-go" -) - -const ( - // These tests expect a ledger device initialized to the following mnemonic - testMnemonic = "equip will roof matter pink blind book anxiety banner elbow sun young" -) - -func TestDiscoverDevice(t *testing.T) { - device, err := discoverLedger() - require.NoError(t, err) - require.NotNil(t, device) - defer device.Close() -} - -func TestDiscoverDeviceTwice(t *testing.T) { - // We expect the second call not to find a device - device, err := discoverLedger() - require.NoError(t, err) - require.NotNil(t, device) - defer device.Close() - - device2, err := discoverLedger() - require.Error(t, err) - require.Equal(t, "no ledger connected", err.Error()) - require.Nil(t, device2) -} - -func TestDiscoverDeviceTwiceClosing(t *testing.T) { - { - device, err := ledger.FindLedgerCosmosUserApp() - require.NoError(t, err) - require.NotNil(t, device) - require.NoError(t, device.Close()) - } - - device2, err := discoverLedger() - require.NoError(t, err) - require.NotNil(t, device2) - require.NoError(t, device2.Close()) -} - -func TestPublicKey(t *testing.T) { - path := *hd.NewFundraiserParams(0, 0) - priv, err := NewPrivKeyLedgerSecp256k1(path) - require.Nil(t, err, "%s", err) - require.NotNil(t, priv) - - pubKeyAddr, err := sdk.Bech32ifyAccPub(priv.PubKey()) - require.NoError(t, err) - require.Equal(t, "cosmospub1addwnpepqd87l8xhcnrrtzxnkql7k55ph8fr9jarf4hn6udwukfprlalu8lgw0urza0", pubKeyAddr, "Is your device using test mnemonic: %s ?", testMnemonic) - require.Equal(t, "5075624b6579536563703235366b317b303334464546394344374334433633353838443342303"+ - "3464542353238314239443233324342413334443646334437314145453539323131464642464531464538377d", - fmt.Sprintf("%x", priv.PubKey())) -} - -func TestPublicKeyHDPath(t *testing.T) { - expectedAnswers := []string{ - "cosmospub1addwnpepqd87l8xhcnrrtzxnkql7k55ph8fr9jarf4hn6udwukfprlalu8lgw0urza0", - "cosmospub1addwnpepqfsdqjr68h7wjg5wacksmqaypasnra232fkgu5sxdlnlu8j22ztxvlqvd65", - "cosmospub1addwnpepqw3xwqun6q43vtgw6p4qspq7srvxhcmvq4jrx5j5ma6xy3r7k6dtxmrkh3d", - "cosmospub1addwnpepqvez9lrp09g8w7gkv42y4yr5p6826cu28ydrhrujv862yf4njmqyyjr4pjs", - "cosmospub1addwnpepq06hw3enfrtmq8n67teytcmtnrgcr0yntmyt25kdukfjkerdc7lqg32rcz7", - "cosmospub1addwnpepqg3trf2gd0s2940nckrxherwqhgmm6xd5h4pcnrh4x7y35h6yafmcpk5qns", - "cosmospub1addwnpepqdm6rjpx6wsref8wjn7ym6ntejet430j4szpngfgc20caz83lu545vuv8hp", - "cosmospub1addwnpepqvdhtjzy2wf44dm03jxsketxc07vzqwvt3vawqqtljgsr9s7jvydjmt66ew", - "cosmospub1addwnpepqwystfpyxwcava7v3t7ndps5xzu6s553wxcxzmmnxevlzvwrlqpzz695nw9", - "cosmospub1addwnpepqw970u6gjqkccg9u3rfj99857wupj2z9fqfzy2w7e5dd7xn7kzzgkgqch0r", - } - - // Check with device - for i := uint32(0); i < 10; i++ { - path := *hd.NewFundraiserParams(0, i) - fmt.Printf("Checking keys at %v\n", path) - - priv, err := NewPrivKeyLedgerSecp256k1(path) - require.Nil(t, err, "%s", err) - require.NotNil(t, priv) - - pubKeyAddr, err := sdk.Bech32ifyAccPub(priv.PubKey()) - require.NoError(t, err) - require.Equal(t, expectedAnswers[i], pubKeyAddr, "Is your device using test mnemonic: %s ?", testMnemonic) - } -} - -func getFakeTx(accountNumber uint32) []byte { - tmp := fmt.Sprintf( - `{"account_number":"%d","chain_id":"1234","fee":{"amount":[{"amount":"150","denom":"atom"}],"gas":"5000"},"memo":"memo","msgs":[[""]],"sequence":"6"}`, - accountNumber) - - return []byte(tmp) -} - -func TestSignaturesHD(t *testing.T) { - for account := uint32(0); account < 100; account += 30 { - msg := getFakeTx(account) - - path := *hd.NewFundraiserParams(account, account/5) - fmt.Printf("Checking signature at %v\n", path) - - priv, err := NewPrivKeyLedgerSecp256k1(path) - require.Nil(t, err, "%s", err) - - pub := priv.PubKey() - sig, err := priv.Sign(msg) - require.Nil(t, err) - - valid := pub.VerifyBytes(msg, sig) - require.True(t, valid, "Is your device using test mnemonic: %s ?", testMnemonic) - } -} - -func TestRealLedgerSecp256k1(t *testing.T) { - msg := getFakeTx(50) - path := *hd.NewFundraiserParams(0, 0) - priv, err := NewPrivKeyLedgerSecp256k1(path) - require.Nil(t, err, "%s", err) - - pub := priv.PubKey() - sig, err := priv.Sign(msg) - require.Nil(t, err) - - valid := pub.VerifyBytes(msg, sig) - require.True(t, valid) - - // now, let's serialize the public key and make sure it still works - bs := priv.PubKey().Bytes() - pub2, err := cryptoAmino.PubKeyFromBytes(bs) - require.Nil(t, err, "%+v", err) - - // make sure we get the same pubkey when we load from disk - require.Equal(t, pub, pub2) - - // signing with the loaded key should match the original pubkey - sig, err = priv.Sign(msg) - require.Nil(t, err) - valid = pub.VerifyBytes(msg, sig) - require.True(t, valid) - - // make sure pubkeys serialize properly as well - bs = pub.Bytes() - bpub, err := cryptoAmino.PubKeyFromBytes(bs) - require.NoError(t, err) - require.Equal(t, pub, bpub) -} diff --git a/crypto/ledger_mock.go b/crypto/ledger_mock.go new file mode 100644 index 000000000000..df7cf6d4e1f4 --- /dev/null +++ b/crypto/ledger_mock.go @@ -0,0 +1,79 @@ +// +build ledger,test_ledger_mock + +package crypto + +import ( + "github.com/btcsuite/btcd/btcec" + "github.com/cosmos/cosmos-sdk/crypto/keys/hd" + "github.com/cosmos/cosmos-sdk/tests" + "github.com/cosmos/go-bip39" + "github.com/pkg/errors" + secp256k1 "github.com/tendermint/btcd/btcec" + "github.com/tendermint/tendermint/crypto" +) + +// If ledger support (build tag) has been enabled, which implies a CGO dependency, +// set the discoverLedger function which is responsible for loading the Ledger +// device at runtime or returning an error. +func init() { + discoverLedger = func() (LedgerSECP256K1, error) { + return LedgerSECP256K1Mock{}, nil + } +} + +type LedgerSECP256K1Mock struct { +} + +func (mock LedgerSECP256K1Mock) Close() error { + return nil +} + +func (mock LedgerSECP256K1Mock) GetPublicKeySECP256K1(derivationPath []uint32) ([]byte, error) { + if derivationPath[0] != 44 { + return nil, errors.New("Invalid derivation path") + } + if derivationPath[1] != 118 { + return nil, errors.New("Invalid derivation path") + } + + seed, err := bip39.NewSeedWithErrorChecking(tests.TestMnemonic, "") + if err != nil { + return nil, err + } + + path := hd.NewParams(derivationPath[0], derivationPath[1], derivationPath[2], derivationPath[3] != 0, derivationPath[4]) + masterPriv, ch := hd.ComputeMastersFromSeed(seed) + derivedPriv, err := hd.DerivePrivateKeyForPath(masterPriv, ch, path.String()) + if err != nil { + return nil, err + } + + _, pubkeyObject := secp256k1.PrivKeyFromBytes(secp256k1.S256(), derivedPriv[:]) + + return pubkeyObject.SerializeUncompressed(), nil +} + +func (mock LedgerSECP256K1Mock) SignSECP256K1(derivationPath []uint32, message []byte) ([]byte, error) { + path := hd.NewParams(derivationPath[0], derivationPath[1], derivationPath[2], derivationPath[3] != 0, derivationPath[4]) + seed, err := bip39.NewSeedWithErrorChecking(tests.TestMnemonic, "") + if err != nil { + return nil, err + } + + masterPriv, ch := hd.ComputeMastersFromSeed(seed) + derivedPriv, err := hd.DerivePrivateKeyForPath(masterPriv, ch, path.String()) + if err != nil { + return nil, err + } + + priv, _ := secp256k1.PrivKeyFromBytes(secp256k1.S256(), derivedPriv[:]) + + sig, err := priv.Sign(crypto.Sha256(message)) + if err != nil { + return nil, err + } + + // Need to return DER as the ledger does + sig2 := btcec.Signature{R: sig.R, S: sig.S} + return sig2.Serialize(), nil +} diff --git a/crypto/ledger_notavail.go b/crypto/ledger_notavail.go new file mode 100644 index 000000000000..8ad672720afa --- /dev/null +++ b/crypto/ledger_notavail.go @@ -0,0 +1,17 @@ +// +build !cgo !ledger +// test_ledger_mock + +package crypto + +import ( + "github.com/pkg/errors" +) + +// If ledger support (build tag) has been enabled, which implies a CGO dependency, +// set the discoverLedger function which is responsible for loading the Ledger +// device at runtime or returning an error. +func init() { + discoverLedger = func() (LedgerSECP256K1, error) { + return nil, errors.New("support for ledger devices is not available in this executable") + } +} diff --git a/crypto/ledger.go b/crypto/ledger_real.go similarity index 81% rename from crypto/ledger.go rename to crypto/ledger_real.go index 36b5646b86f7..7aa4f8a84016 100644 --- a/crypto/ledger.go +++ b/crypto/ledger_real.go @@ -1,10 +1,8 @@ -// +build cgo,ledger +// +build cgo,ledger,!test_ledger_mock package crypto -import ( - ledger "github.com/zondax/ledger-cosmos-go" -) +import ledger "github.com/zondax/ledger-cosmos-go" // If ledger support (build tag) has been enabled, which implies a CGO dependency, // set the discoverLedger function which is responsible for loading the Ledger diff --git a/crypto/ledger_secp256k1.go b/crypto/ledger_secp256k1.go index 5be8405f5e60..0a7b9707b08d 100644 --- a/crypto/ledger_secp256k1.go +++ b/crypto/ledger_secp256k1.go @@ -45,9 +45,6 @@ type ( // NewPrivKeyLedgerSecp256k1 will generate a new key and store the public key // for later use. -// -// CONTRACT: The ledger device, ledgerDevice, must be loaded and set prior to -// any creation of a PrivKeyLedgerSecp256k1. func NewPrivKeyLedgerSecp256k1(path hd.BIP44Params) (tmcrypto.PrivKey, error) { device, err := getLedgerDevice() if err != nil { @@ -103,8 +100,8 @@ func (pkl PrivKeyLedgerSecp256k1) Bytes() []byte { // Equals implements the PrivKey interface. It makes sure two private keys // refer to the same public key. func (pkl PrivKeyLedgerSecp256k1) Equals(other tmcrypto.PrivKey) bool { - if ledger, ok := other.(*PrivKeyLedgerSecp256k1); ok { - return pkl.CachedPubKey.Equals(ledger.CachedPubKey) + if otherKey, ok := other.(PrivKeyLedgerSecp256k1); ok { + return pkl.CachedPubKey.Equals(otherKey.CachedPubKey) } return false } diff --git a/crypto/ledger_test.go b/crypto/ledger_test.go index cb2c7b325153..6418a57324a1 100644 --- a/crypto/ledger_test.go +++ b/crypto/ledger_test.go @@ -1,13 +1,19 @@ package crypto import ( + "fmt" "testing" + "github.com/cosmos/cosmos-sdk/tests" + + tmcrypto "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/crypto/encoding/amino" + "github.com/cosmos/cosmos-sdk/crypto/keys/hd" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" ) -// This tests assume a ledger is not plugged in func TestLedgerErrorHandling(t *testing.T) { // first, try to generate a key, must return an error // (no panic) @@ -15,3 +21,135 @@ func TestLedgerErrorHandling(t *testing.T) { _, err := NewPrivKeyLedgerSecp256k1(path) require.Error(t, err) } + +func TestPublicKey(t *testing.T) { + path := *hd.NewFundraiserParams(0, 0) + priv, err := NewPrivKeyLedgerSecp256k1(path) + require.Nil(t, err, "%s", err) + require.NotNil(t, priv) + + pubKeyAddr, err := sdk.Bech32ifyAccPub(priv.PubKey()) + require.NoError(t, err) + require.Equal(t, "cosmospub1addwnpepqd87l8xhcnrrtzxnkql7k55ph8fr9jarf4hn6udwukfprlalu8lgw0urza0", + pubKeyAddr, "Is your device using test mnemonic: %s ?", tests.TestMnemonic) + + require.Equal(t, "5075624b6579536563703235366b317b303334464546394344374334433633353838443342303"+ + "3464542353238314239443233324342413334443646334437314145453539323131464642464531464538377d", + fmt.Sprintf("%x", priv.PubKey())) +} + +func TestPublicKeyHDPath(t *testing.T) { + expectedAnswers := []string{ + "cosmospub1addwnpepqd87l8xhcnrrtzxnkql7k55ph8fr9jarf4hn6udwukfprlalu8lgw0urza0", + "cosmospub1addwnpepqfsdqjr68h7wjg5wacksmqaypasnra232fkgu5sxdlnlu8j22ztxvlqvd65", + "cosmospub1addwnpepqw3xwqun6q43vtgw6p4qspq7srvxhcmvq4jrx5j5ma6xy3r7k6dtxmrkh3d", + "cosmospub1addwnpepqvez9lrp09g8w7gkv42y4yr5p6826cu28ydrhrujv862yf4njmqyyjr4pjs", + "cosmospub1addwnpepq06hw3enfrtmq8n67teytcmtnrgcr0yntmyt25kdukfjkerdc7lqg32rcz7", + "cosmospub1addwnpepqg3trf2gd0s2940nckrxherwqhgmm6xd5h4pcnrh4x7y35h6yafmcpk5qns", + "cosmospub1addwnpepqdm6rjpx6wsref8wjn7ym6ntejet430j4szpngfgc20caz83lu545vuv8hp", + "cosmospub1addwnpepqvdhtjzy2wf44dm03jxsketxc07vzqwvt3vawqqtljgsr9s7jvydjmt66ew", + "cosmospub1addwnpepqwystfpyxwcava7v3t7ndps5xzu6s553wxcxzmmnxevlzvwrlqpzz695nw9", + "cosmospub1addwnpepqw970u6gjqkccg9u3rfj99857wupj2z9fqfzy2w7e5dd7xn7kzzgkgqch0r", + } + + const numIters = 10 + + privKeys := make([]tmcrypto.PrivKey, numIters) + + // Check with device + for i := uint32(0); i < 10; i++ { + path := *hd.NewFundraiserParams(0, i) + fmt.Printf("Checking keys at %v\n", path) + + priv, err := NewPrivKeyLedgerSecp256k1(path) + require.Nil(t, err, "%s", err) + require.NotNil(t, priv) + + // Check other methods + require.NoError(t, priv.(PrivKeyLedgerSecp256k1).ValidateKey()) + tmp := priv.(PrivKeyLedgerSecp256k1) + (&tmp).AssertIsPrivKeyInner() + + pubKeyAddr, err := sdk.Bech32ifyAccPub(priv.PubKey()) + require.NoError(t, err) + require.Equal(t, + expectedAnswers[i], pubKeyAddr, + "Is your device using test mnemonic: %s ?", tests.TestMnemonic) + + // Store and restore + serializedPk := priv.Bytes() + require.NotNil(t, serializedPk) + require.Equal(t, 44, len(serializedPk)) + + privKeys[i] = priv + } + + // Now check equality + for i := 0; i < 10; i++ { + for j := 0; j < 10; j++ { + require.Equal(t, i == j, privKeys[i].Equals(privKeys[j])) + require.Equal(t, i == j, privKeys[j].Equals(privKeys[i])) + } + } +} + +func getFakeTx(accountNumber uint32) []byte { + tmp := fmt.Sprintf( + `{"account_number":"%d","chain_id":"1234","fee":{"amount":[{"amount":"150","denom":"atom"}],"gas":"5000"},"memo":"memo","msgs":[[""]],"sequence":"6"}`, + accountNumber) + + return []byte(tmp) +} + +func TestSignaturesHD(t *testing.T) { + for account := uint32(0); account < 100; account += 30 { + msg := getFakeTx(account) + + path := *hd.NewFundraiserParams(account, account/5) + fmt.Printf("Checking signature at %v --- PLEASE REVIEW AND ACCEPT IN THE DEVICE\n", path) + + priv, err := NewPrivKeyLedgerSecp256k1(path) + require.Nil(t, err, "%s", err) + + pub := priv.PubKey() + sig, err := priv.Sign(msg) + require.Nil(t, err) + + valid := pub.VerifyBytes(msg, sig) + require.True(t, valid, "Is your device using test mnemonic: %s ?", tests.TestMnemonic) + } +} + +func TestRealLedgerSecp256k1(t *testing.T) { + msg := getFakeTx(50) + path := *hd.NewFundraiserParams(0, 0) + priv, err := NewPrivKeyLedgerSecp256k1(path) + require.Nil(t, err, "%s", err) + + pub := priv.PubKey() + sig, err := priv.Sign(msg) + require.Nil(t, err) + + valid := pub.VerifyBytes(msg, sig) + require.True(t, valid) + + // now, let's serialize the public key and make sure it still works + bs := priv.PubKey().Bytes() + pub2, err := cryptoAmino.PubKeyFromBytes(bs) + require.Nil(t, err, "%+v", err) + + // make sure we get the same pubkey when we load from disk + require.Equal(t, pub, pub2) + + // signing with the loaded key should match the original pubkey + sig, err = priv.Sign(msg) + require.Nil(t, err) + valid = pub.VerifyBytes(msg, sig) + require.True(t, valid) + + // make sure pubkeys serialize properly as well + bs = pub.Bytes() + bpub, err := cryptoAmino.PubKeyFromBytes(bs) + require.NoError(t, err) + require.Equal(t, pub, bpub) +} diff --git a/server/util.go b/server/util.go index 35f35e9976e5..2b81ce817a35 100644 --- a/server/util.go +++ b/server/util.go @@ -120,7 +120,7 @@ func interceptLoadConfig() (conf *cfg.Config, err error) { // validate the config with the sdk's requirements. func validateConfig(conf *cfg.Config) error { - if conf.Consensus.CreateEmptyBlocks == false { + if !conf.Consensus.CreateEmptyBlocks { return errors.New("config option CreateEmptyBlocks = false is currently unsupported") } return nil diff --git a/store/iavl/store.go b/store/iavl/store.go index 49299301ef15..c2d5af3440b4 100644 --- a/store/iavl/store.go +++ b/store/iavl/store.go @@ -293,7 +293,7 @@ func newIAVLIterator(tree *iavl.ImmutableTree, start, end []byte, ascending bool start: types.Cp(start), end: types.Cp(end), ascending: ascending, - iterCh: make(chan cmn.KVPair, 0), // Set capacity > 0? + iterCh: make(chan cmn.KVPair), // Set capacity > 0? quitCh: make(chan struct{}), initCh: make(chan struct{}), } diff --git a/store/prefix/store_test.go b/store/prefix/store_test.go index 04019ead30b0..72eeb400d62b 100644 --- a/store/prefix/store_test.go +++ b/store/prefix/store_test.go @@ -1,18 +1,16 @@ package prefix import ( - "math/rand" + "crypto/rand" "testing" - "github.com/stretchr/testify/require" - - tiavl "github.com/tendermint/iavl" - dbm "github.com/tendermint/tendermint/libs/db" - "github.com/cosmos/cosmos-sdk/store/dbadapter" "github.com/cosmos/cosmos-sdk/store/gaskv" "github.com/cosmos/cosmos-sdk/store/iavl" "github.com/cosmos/cosmos-sdk/store/types" + "github.com/stretchr/testify/require" + tiavl "github.com/tendermint/iavl" + dbm "github.com/tendermint/tendermint/libs/db" ) // copied from iavl/store_test.go diff --git a/store/rootmulti/proof.go b/store/rootmulti/proof.go index 6657a6007a66..0c913ee093ab 100644 --- a/store/rootmulti/proof.go +++ b/store/rootmulti/proof.go @@ -33,11 +33,7 @@ func RequireProof(subpath string) bool { // Currently, only when query subpath is "/key", will proof be included in // response. If there are some changes about proof building in iavlstore.go, // we must change code here to keep consistency with iavlStore#Query. - if subpath == "/key" { - return true - } - - return false + return subpath == "/key" } //----------------------------------------------------------------------------- diff --git a/tests/knownValues.go b/tests/knownValues.go new file mode 100644 index 000000000000..eb2063fa1666 --- /dev/null +++ b/tests/knownValues.go @@ -0,0 +1,6 @@ +package tests + +const ( + // Tests expect a ledger device initialized to the following mnemonic + TestMnemonic = "equip will roof matter pink blind book anxiety banner elbow sun young" +) diff --git a/tests/test_cover.sh b/tests/test_cover.sh index 3d3a6097e546..e7629d6238fd 100644 --- a/tests/test_cover.sh +++ b/tests/test_cover.sh @@ -5,8 +5,8 @@ PKGS=$(go list ./... | grep -v /vendor/ | grep -v github.com/cosmos/cosmos-sdk/c set -e echo "mode: atomic" > coverage.txt -for pkg in ${PKGS}; do - go test -v -timeout 30m -race -coverprofile=profile.out -covermode=atomic "$pkg" +for pkg in ${PKGS[@]}; do + go test -v -timeout 30m -race -coverprofile=profile.out -covermode=atomic -tags='ledger test_ledger_mock' "$pkg" if [ -f profile.out ]; then tail -n +2 profile.out >> coverage.txt; rm profile.out diff --git a/tests/util.go b/tests/util.go index 7838243733ca..be365bfa979e 100644 --- a/tests/util.go +++ b/tests/util.go @@ -4,6 +4,7 @@ import ( "fmt" "io/ioutil" "net/http" + "os" "time" "strings" @@ -201,3 +202,21 @@ var cdc = amino.NewCodec() func init() { ctypes.RegisterAmino(cdc) } + +// GetTempDir creates a temporary directory and returns a clean up function +// to be deferred +func GetTempDir(prefix string) (string, func(), error) { + rootDir, err := ioutil.TempDir("", prefix) + if err != nil { + return "", nil, err + } + + cleanUp := func() { + err := os.RemoveAll(rootDir) + if err != nil { + panic(err) + } + } + + return rootDir, cleanUp, nil +} diff --git a/types/address.go b/types/address.go index a1663aebb528..5a3b2d2a8017 100644 --- a/types/address.go +++ b/types/address.go @@ -86,7 +86,7 @@ func (aa AccAddress) Equals(aa2 Address) bool { return true } - return bytes.Compare(aa.Bytes(), aa2.Bytes()) == 0 + return bytes.Equal(aa.Bytes(), aa2.Bytes()) } // Returns boolean for whether an AccAddress is empty @@ -96,7 +96,7 @@ func (aa AccAddress) Empty() bool { } aa2 := AccAddress{} - return bytes.Compare(aa.Bytes(), aa2.Bytes()) == 0 + return bytes.Equal(aa.Bytes(), aa2.Bytes()) } // Marshal returns the raw address bytes. It is needed for protobuf @@ -155,7 +155,7 @@ func (aa AccAddress) String() string { func (aa AccAddress) Format(s fmt.State, verb rune) { switch verb { case 's': - s.Write([]byte(fmt.Sprintf("%s", aa.String()))) + s.Write([]byte(aa.String())) case 'p': s.Write([]byte(fmt.Sprintf("%p", aa))) default: @@ -202,7 +202,7 @@ func (va ValAddress) Equals(va2 Address) bool { return true } - return bytes.Compare(va.Bytes(), va2.Bytes()) == 0 + return bytes.Equal(va.Bytes(), va2.Bytes()) } // Returns boolean for whether an AccAddress is empty @@ -212,7 +212,7 @@ func (va ValAddress) Empty() bool { } va2 := ValAddress{} - return bytes.Compare(va.Bytes(), va2.Bytes()) == 0 + return bytes.Equal(va.Bytes(), va2.Bytes()) } // Marshal returns the raw address bytes. It is needed for protobuf @@ -272,7 +272,7 @@ func (va ValAddress) String() string { func (va ValAddress) Format(s fmt.State, verb rune) { switch verb { case 's': - s.Write([]byte(fmt.Sprintf("%s", va.String()))) + s.Write([]byte(va.String())) case 'p': s.Write([]byte(fmt.Sprintf("%p", va))) default: @@ -324,7 +324,7 @@ func (ca ConsAddress) Equals(ca2 Address) bool { return true } - return bytes.Compare(ca.Bytes(), ca2.Bytes()) == 0 + return bytes.Equal(ca.Bytes(), ca2.Bytes()) } // Returns boolean for whether an ConsAddress is empty @@ -334,7 +334,7 @@ func (ca ConsAddress) Empty() bool { } ca2 := ConsAddress{} - return bytes.Compare(ca.Bytes(), ca2.Bytes()) == 0 + return bytes.Equal(ca.Bytes(), ca2.Bytes()) } // Marshal returns the raw address bytes. It is needed for protobuf @@ -394,7 +394,7 @@ func (ca ConsAddress) String() string { func (ca ConsAddress) Format(s fmt.State, verb rune) { switch verb { case 's': - s.Write([]byte(fmt.Sprintf("%s", ca.String()))) + s.Write([]byte(ca.String())) case 'p': s.Write([]byte(fmt.Sprintf("%p", ca))) default: diff --git a/types/address_test.go b/types/address_test.go index f3c44e4d34d4..251ceb9f0620 100644 --- a/types/address_test.go +++ b/types/address_test.go @@ -5,13 +5,11 @@ import ( "math/rand" "testing" - "github.com/stretchr/testify/require" - - "github.com/tendermint/tendermint/crypto/ed25519" - "strings" "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/crypto/ed25519" ) var invalidStrs = []string{ diff --git a/types/errors.go b/types/errors.go index a400fec6f95b..9f728adfa895 100644 --- a/types/errors.go +++ b/types/errors.go @@ -19,10 +19,7 @@ type CodespaceType string // IsOK - is everything okay? func (code CodeType) IsOK() bool { - if code == CodeOK { - return true - } - return false + return code == CodeOK } // SDK error codes diff --git a/types/store_test.go b/types/store_test.go index b5e36c487636..06f609d17471 100644 --- a/types/store_test.go +++ b/types/store_test.go @@ -30,8 +30,7 @@ func TestCommitID(t *testing.T) { var empty CommitID require.True(t, empty.IsZero()) - var nonempty CommitID - nonempty = CommitID{ + var nonempty = CommitID{ Version: 1, Hash: []byte("testhash"), } diff --git a/x/gov/depositsvotes.go b/x/gov/depositsvotes.go index 8b553e158d3b..ce70150dd3e9 100644 --- a/x/gov/depositsvotes.go +++ b/x/gov/depositsvotes.go @@ -164,7 +164,7 @@ func (vo VoteOption) String() string { func (vo VoteOption) Format(s fmt.State, verb rune) { switch verb { case 's': - s.Write([]byte(fmt.Sprintf("%s", vo.String()))) + s.Write([]byte(vo.String())) default: s.Write([]byte(fmt.Sprintf("%v", byte(vo)))) } diff --git a/x/mock/app.go b/x/mock/app.go index 117afa668f01..e4826fc8f17d 100644 --- a/x/mock/app.go +++ b/x/mock/app.go @@ -238,7 +238,7 @@ func GenTx(msgs []sdk.Msg, accnums []uint64, seq []uint64, priv ...crypto.PrivKe // GeneratePrivKeys generates a total n Ed25519 private keys. func GeneratePrivKeys(n int) (keys []crypto.PrivKey) { // TODO: Randomize this between ed25519 and secp256k1 - keys = make([]crypto.PrivKey, n, n) + keys = make([]crypto.PrivKey, n) for i := 0; i < n; i++ { keys[i] = ed25519.GenPrivKey() } @@ -249,8 +249,8 @@ func GeneratePrivKeys(n int) (keys []crypto.PrivKey) { // GeneratePrivKeyAddressPairs generates a total of n private key, address // pairs. func GeneratePrivKeyAddressPairs(n int) (keys []crypto.PrivKey, addrs []sdk.AccAddress) { - keys = make([]crypto.PrivKey, n, n) - addrs = make([]sdk.AccAddress, n, n) + keys = make([]crypto.PrivKey, n) + addrs = make([]sdk.AccAddress, n) for i := 0; i < n; i++ { if rand.Int63()%2 == 0 { keys[i] = secp256k1.GenPrivKey() @@ -265,8 +265,8 @@ func GeneratePrivKeyAddressPairs(n int) (keys []crypto.PrivKey, addrs []sdk.AccA // GeneratePrivKeyAddressPairsFromRand generates a total of n private key, address // pairs using the provided randomness source. func GeneratePrivKeyAddressPairsFromRand(rand *rand.Rand, n int) (keys []crypto.PrivKey, addrs []sdk.AccAddress) { - keys = make([]crypto.PrivKey, n, n) - addrs = make([]sdk.AccAddress, n, n) + keys = make([]crypto.PrivKey, n) + addrs = make([]sdk.AccAddress, n) for i := 0; i < n; i++ { secret := make([]byte, 32) _, err := rand.Read(secret) @@ -287,7 +287,7 @@ func GeneratePrivKeyAddressPairsFromRand(rand *rand.Rand, n int) (keys []crypto. // provided addresses and coin denominations. // nolint: errcheck func RandomSetGenesis(r *rand.Rand, app *App, addrs []sdk.AccAddress, denoms []string) { - accts := make([]auth.Account, len(addrs), len(addrs)) + accts := make([]auth.Account, len(addrs)) randCoinIntervals := []BigInterval{ {sdk.NewIntWithDecimal(1, 0), sdk.NewIntWithDecimal(1, 1)}, {sdk.NewIntWithDecimal(1, 2), sdk.NewIntWithDecimal(1, 3)}, @@ -295,7 +295,7 @@ func RandomSetGenesis(r *rand.Rand, app *App, addrs []sdk.AccAddress, denoms []s } for i := 0; i < len(accts); i++ { - coins := make([]sdk.Coin, len(denoms), len(denoms)) + coins := make([]sdk.Coin, len(denoms)) // generate a random coin for each denomination for j := 0; j < len(denoms); j++ { @@ -328,7 +328,7 @@ func GetAllAccounts(mapper auth.AccountKeeper, ctx sdk.Context) []auth.Account { // that they differ only by having the sequence numbers incremented between // every transaction. func GenSequenceOfTxs(msgs []sdk.Msg, accnums []uint64, initSeqNums []uint64, numToGenerate int, priv ...crypto.PrivKey) []auth.StdTx { - txs := make([]auth.StdTx, numToGenerate, numToGenerate) + txs := make([]auth.StdTx, numToGenerate) for i := 0; i < numToGenerate; i++ { txs[i] = GenTx(msgs, accnums, initSeqNums, priv...) incrementAllSequenceNumbers(initSeqNums) diff --git a/x/staking/keeper/delegation.go b/x/staking/keeper/delegation.go index f1588477e8e6..fcecbb73da79 100644 --- a/x/staking/keeper/delegation.go +++ b/x/staking/keeper/delegation.go @@ -222,7 +222,7 @@ func (k Keeper) InsertUBDQueue(ctx sdk.Context, ubd types.UnbondingDelegation, completionTime time.Time) { timeSlice := k.GetUBDQueueTimeSlice(ctx, completionTime) - dvPair := types.DVPair{ubd.DelegatorAddr, ubd.ValidatorAddr} + dvPair := types.DVPair{DelegatorAddr: ubd.DelegatorAddr, ValidatorAddr: ubd.ValidatorAddr} if len(timeSlice) == 0 { k.SetUBDQueueTimeSlice(ctx, completionTime, []types.DVPair{dvPair}) } else { @@ -314,10 +314,7 @@ func (k Keeper) HasReceivingRedelegation(ctx sdk.Context, iterator := sdk.KVStorePrefixIterator(store, prefix) defer iterator.Close() - if iterator.Valid() { - return true - } - return false + return iterator.Valid() } // HasMaxRedelegationEntries - redelegation has maximum number of entries @@ -411,7 +408,11 @@ func (k Keeper) InsertRedelegationQueue(ctx sdk.Context, red types.Redelegation, completionTime time.Time) { timeSlice := k.GetRedelegationQueueTimeSlice(ctx, completionTime) - dvvTriplet := types.DVVTriplet{red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr} + dvvTriplet := types.DVVTriplet{ + DelegatorAddr: red.DelegatorAddr, + ValidatorSrcAddr: red.ValidatorSrcAddr, + ValidatorDstAddr: red.ValidatorDstAddr} + if len(timeSlice) == 0 { k.SetRedelegationQueueTimeSlice(ctx, completionTime, []types.DVVTriplet{dvvTriplet}) } else { diff --git a/x/staking/keeper/test_common.go b/x/staking/keeper/test_common.go index 9036bddd751f..83b6eb3ed88d 100644 --- a/x/staking/keeper/test_common.go +++ b/x/staking/keeper/test_common.go @@ -166,7 +166,7 @@ func TestAddr(addr string, bech string) sdk.AccAddress { if err != nil { panic(err) } - if bytes.Compare(bechres, res) != 0 { + if !bytes.Equal(bechres, res) { panic("Bech decode and hex decode don't match") } diff --git a/x/staking/simulation/msgs.go b/x/staking/simulation/msgs.go index 8ae5c4baa2e1..69be7d330145 100644 --- a/x/staking/simulation/msgs.go +++ b/x/staking/simulation/msgs.go @@ -12,6 +12,10 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/keeper" ) +const ( + noOperation = "no-operation" +) + // SimulateMsgCreateValidator func SimulateMsgCreateValidator(m auth.AccountKeeper, k staking.Keeper) simulation.Operation { handler := staking.NewHandler(k) @@ -39,7 +43,7 @@ func SimulateMsgCreateValidator(m auth.AccountKeeper, k staking.Keeper) simulati } if amount.Equal(sdk.ZeroInt()) { - return "no-operation", nil, nil + return noOperation, nil, nil } selfDelegation := sdk.NewCoin(denom, amount) @@ -146,13 +150,13 @@ func SimulateMsgUndelegate(m auth.AccountKeeper, k staking.Keeper) simulation.Op delegatorAddress := delegatorAcc.Address delegations := k.GetAllDelegatorDelegations(ctx, delegatorAddress) if len(delegations) == 0 { - return "no-operation", nil, nil + return noOperation, nil, nil } delegation := delegations[r.Intn(len(delegations))] numShares := simulation.RandomDecAmount(r, delegation.Shares) if numShares.Equal(sdk.ZeroDec()) { - return "no-operation", nil, nil + return noOperation, nil, nil } msg := staking.MsgUndelegate{ DelegatorAddr: delegatorAddress, @@ -194,7 +198,7 @@ func SimulateMsgBeginRedelegate(m auth.AccountKeeper, k staking.Keeper) simulati amount = simulation.RandomAmount(r, amount) } if amount.Equal(sdk.ZeroInt()) { - return "no-operation", nil, nil + return noOperation, nil, nil } msg := staking.MsgBeginRedelegate{ DelegatorAddr: delegatorAddress,