From 1ef55e62f03f75dca9fcc3c64518254eada646fa Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 12 Jul 2021 17:34:50 +0200 Subject: [PATCH 1/6] docs: add v0.43 release version option (backport #9506) (#9677) * docs: add v0.43 version option (#9506) Co-authored-by: ryanchrypto <12519942+ryanchrypto@users.noreply.github.com> (cherry picked from commit 325dabd83c66c23a1f2320783de552a14090a086) # Conflicts: # docs/versions * fix conflicts Co-authored-by: Ryan Christoffersen <12519942+ryanchristo@users.noreply.github.com> Co-authored-by: Amaury M <1293565+amaurym@users.noreply.github.com> --- docs/.vuepress/config.js | 4 ++++ docs/versions | 2 ++ 2 files changed, 6 insertions(+) diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index a7e732c67224..223d2d91aa8b 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -46,6 +46,10 @@ module.exports = { "label": "v0.42", "key": "v0.42" }, + { + "label": "v0.43", + "key": "v0.43" + }, { "label": "master", "key": "master" diff --git a/docs/versions b/docs/versions index d5dc85eb286f..d01230080817 100644 --- a/docs/versions +++ b/docs/versions @@ -1,2 +1,4 @@ master master launchpad/backports v0.39 +release/v0.42.x v0.42 +release/v0.43.x v0.43 From 1d25de1059e41e5892464fcbd31ba0b01de43c23 Mon Sep 17 00:00:00 2001 From: Amaury <1293565+amaurym@users.noreply.github.com> Date: Tue, 20 Jul 2021 12:29:51 +0200 Subject: [PATCH 2/6] chore: Add missing entry in 0.42.7 Changelog (#9722) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90bebf64c64e..c4724447b159 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [\#9645](https://github.com/cosmos/cosmos-sdk/pull/9645) Use correct Prometheus format for metric labels. * [\#9299](https://github.com/cosmos/cosmos-sdk/pull/9299) Fix `[appd] keys parse cosmos1...` freezing. * (keyring) [\#9563](https://github.com/cosmos/cosmos-sdk/pull/9563) fix keyring kwallet backend when using with empty wallet. +* (x/capability) [\#9392](https://github.com/cosmos/cosmos-sdk/pull/9392) initialization fix, which fixes the consensus error when using statesync. ## [v0.42.6](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.42.6) - 2021-06-18 From c26244c3a8ddbbc8d846d2cf48c62741a2cd02a1 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 26 Jul 2021 17:23:13 +0200 Subject: [PATCH 3/6] fix: support output flag on tx commands (backport #9717) (#9772) * fix: support output flag on tx commands (#9717) ## Description Closes: #9684 --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable) (cherry picked from commit 92535034d6fa16858394e1470e7ec1784ecc6ad4) # Conflicts: # CHANGELOG.md * Fix changelog Co-authored-by: Sai Kumar <17549398+gsk967@users.noreply.github.com> Co-authored-by: Amaury M <1293565+amaurym@users.noreply.github.com> --- CHANGELOG.md | 3 +++ client/flags/flags.go | 1 + 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c4724447b159..548f2ed065ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,9 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## Unreleased +### Improvements + +* (cli) [\#9717](https://github.com/cosmos/cosmos-sdk/pull/9717) Added CLI flag `--output json/text` to `tx` cli commands. ## [v0.42.7](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.42.7) - 2021-07-09 diff --git a/client/flags/flags.go b/client/flags/flags.go index b305412d4667..7d4de556b69c 100644 --- a/client/flags/flags.go +++ b/client/flags/flags.go @@ -94,6 +94,7 @@ func AddQueryFlagsToCmd(cmd *cobra.Command) { // AddTxFlagsToCmd adds common flags to a module tx command. func AddTxFlagsToCmd(cmd *cobra.Command) { + cmd.Flags().StringP(tmcli.OutputFlag, "o", "json", "Output format (text|json)") cmd.Flags().String(FlagKeyringDir, "", "The client Keyring directory; if omitted, the default 'home' directory will be used") cmd.Flags().String(FlagFrom, "", "Name or address of private key with which to sign") cmd.Flags().Uint64P(FlagAccountNumber, "a", 0, "The account number of the signing account (offline mode only)") From 9db413bc80bdcc3768f42728e22a92433c74b9db Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 28 Jul 2021 15:23:38 +0200 Subject: [PATCH 4/6] feat: Query txs by signature and by address+seq (backport #9750) (#9783) * feat: Query txs by signature and by address+seq (#9750) ## Description Closes: #9741 --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable) (cherry picked from commit 7c194340006b186c99b1a8d6417f621f9d480efd) # Conflicts: # CHANGELOG.md # x/auth/client/cli/cli_test.go # x/auth/client/cli/query.go * Fix conflicts * Fix build * Fix IBC test * use createBankMsg from master Co-authored-by: Amaury <1293565+amaurym@users.noreply.github.com> --- CHANGELOG.md | 4 + types/events.go | 5 + x/auth/ante/sigverify.go | 68 ++++++++ x/auth/client/cli/cli_test.go | 181 ++++++++++++++++++--- x/auth/client/cli/query.go | 111 +++++++++++-- x/auth/client/cli/query_test.go | 32 ++++ x/ibc/core/02-client/keeper/client_test.go | 4 +- 7 files changed, 367 insertions(+), 38 deletions(-) create mode 100644 x/auth/client/cli/query_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 548f2ed065ee..830ce54bd607 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## Unreleased +### Features + +* [\#9750](https://github.com/cosmos/cosmos-sdk/pull/9750) Emit events for tx signature and sequence, so clients can now query txs by signature (`tx.signature=''`) or by address and sequence combo (`tx.acc_seq='/'`). + ### Improvements * (cli) [\#9717](https://github.com/cosmos/cosmos-sdk/pull/9717) Added CLI flag `--output json/text` to `tx` cli commands. diff --git a/types/events.go b/types/events.go index 5a2bf3af4b08..27a0017635af 100644 --- a/types/events.go +++ b/types/events.go @@ -223,6 +223,11 @@ func toBytes(i interface{}) []byte { // Common event types and attribute keys var ( + EventTypeTx = "tx" + + AttributeKeyAccountSequence = "acc_seq" + AttributeKeySignature = "signature" + EventTypeMessage = "message" AttributeKeyAction = "action" diff --git a/x/auth/ante/sigverify.go b/x/auth/ante/sigverify.go index 79fbbcdc676a..6aa0c2a345f9 100644 --- a/x/auth/ante/sigverify.go +++ b/x/auth/ante/sigverify.go @@ -2,6 +2,7 @@ package ante import ( "bytes" + "encoding/base64" "encoding/hex" "fmt" @@ -90,6 +91,34 @@ func (spkd SetPubKeyDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b spkd.ak.SetAccount(ctx, acc) } + // Also emit the following events, so that txs can be indexed by these + // indices: + // - signature (via `tx.signature=''`), + // - concat(address,"/",sequence) (via `tx.acc_seq='cosmos1abc...def/42'`). + sigs, err := sigTx.GetSignaturesV2() + if err != nil { + return ctx, err + } + + var events sdk.Events + for i, sig := range sigs { + events = append(events, sdk.NewEvent(sdk.EventTypeTx, + sdk.NewAttribute(sdk.AttributeKeyAccountSequence, fmt.Sprintf("%s/%d", signers[i], sig.Sequence)), + )) + + sigBzs, err := signatureDataToBz(sig.Data) + if err != nil { + return ctx, err + } + for _, sigBz := range sigBzs { + events = append(events, sdk.NewEvent(sdk.EventTypeTx, + sdk.NewAttribute(sdk.AttributeKeySignature, base64.StdEncoding.EncodeToString(sigBz)), + )) + } + } + + ctx.EventManager().EmitEvents(events) + return next(ctx, tx, simulate) } @@ -436,3 +465,42 @@ func CountSubKeys(pub cryptotypes.PubKey) int { return numKeys } + +// signatureDataToBz converts a SignatureData into raw bytes signature. +// For SingleSignatureData, it returns the signature raw bytes. +// For MultiSignatureData, it returns an array of all individual signatures, +// as well as the aggregated signature. +func signatureDataToBz(data signing.SignatureData) ([][]byte, error) { + if data == nil { + return nil, fmt.Errorf("got empty SignatureData") + } + + switch data := data.(type) { + case *signing.SingleSignatureData: + return [][]byte{data.Signature}, nil + case *signing.MultiSignatureData: + sigs := [][]byte{} + var err error + + for _, d := range data.Signatures { + nestedSigs, err := signatureDataToBz(d) + if err != nil { + return nil, err + } + sigs = append(sigs, nestedSigs...) + } + + multisig := cryptotypes.MultiSignature{ + Signatures: sigs, + } + aggregatedSig, err := multisig.Marshal() + if err != nil { + return nil, err + } + sigs = append(sigs, aggregatedSig) + + return sigs, nil + default: + return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "unexpected signature data type %T", data) + } +} diff --git a/x/auth/client/cli/cli_test.go b/x/auth/client/cli/cli_test.go index 2b305e809256..c78e03a86a29 100644 --- a/x/auth/client/cli/cli_test.go +++ b/x/auth/client/cli/cli_test.go @@ -4,6 +4,7 @@ package cli_test import ( "context" + "encoding/base64" "encoding/json" "fmt" "io/ioutil" @@ -78,11 +79,17 @@ func (s *IntegrationTestSuite) TearDownSuite() { func (s *IntegrationTestSuite) TestCLIValidateSignatures() { val := s.network.Validators[0] - res := s.createBankMsg(val, val.Address) + sendTokens := sdk.NewCoins( + sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(10)), + sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))) + + res, err := s.createBankMsg(val, val.Address, sendTokens, + fmt.Sprintf("--%s=true", flags.FlagGenerateOnly)) + s.Require().NoError(err) // write unsigned tx to file unsignedTx := testutil.WriteToNewTempFile(s.T(), res.String()) - res, err := authtest.TxSignExec(val.ClientCtx, val.Address, unsignedTx.Name()) + res, err = authtest.TxSignExec(val.ClientCtx, val.Address, unsignedTx.Name()) s.Require().NoError(err) signedTx, err := val.ClientCtx.TxConfig.TxJSONDecoder()(res.Bytes()) s.Require().NoError(err) @@ -104,7 +111,15 @@ func (s *IntegrationTestSuite) TestCLIValidateSignatures() { func (s *IntegrationTestSuite) TestCLISignBatch() { val := s.network.Validators[0] - generatedStd := s.createBankMsg(val, val.Address) + var sendTokens = sdk.NewCoins( + sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(10)), + sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)), + ) + + generatedStd, err := s.createBankMsg(val, val.Address, + sendTokens, fmt.Sprintf("--%s=true", flags.FlagGenerateOnly)) + s.Require().NoError(err) + outputFile := testutil.WriteToNewTempFile(s.T(), strings.Repeat(generatedStd.String(), 3)) val.ClientCtx.HomeDir = strings.Replace(val.ClientCtx.HomeDir, "simd", "simcli", 1) @@ -136,7 +151,13 @@ func (s *IntegrationTestSuite) TestCLISign_AminoJSON() { require := s.Require() val1 := s.network.Validators[0] txCfg := val1.ClientCtx.TxConfig - txBz := s.createBankMsg(val1, val1.Address) + var sendTokens = sdk.NewCoins( + sdk.NewCoin(fmt.Sprintf("%stoken", val1.Moniker), sdk.NewInt(10)), + sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)), + ) + txBz, err := s.createBankMsg(val1, val1.Address, + sendTokens, fmt.Sprintf("--%s=true", flags.FlagGenerateOnly)) + require.NoError(err) fileUnsigned := testutil.WriteToNewTempFile(s.T(), txBz.String()) chainFlag := fmt.Sprintf("--%s=%s", flags.FlagChainID, val1.ClientCtx.ChainID) sigOnlyFlag := "--signature-only" @@ -224,7 +245,7 @@ func checkSignatures(require *require.Assertions, txCfg client.TxConfig, output } } -func (s *IntegrationTestSuite) TestCLIQueryTxCmd() { +func (s *IntegrationTestSuite) TestCLIQueryTxCmdByHash() { val := s.network.Validators[0] account2, err := val.ClientCtx.Keyring.Key("newAccount2") @@ -271,17 +292,20 @@ func (s *IntegrationTestSuite) TestCLIQueryTxCmd() { expectErr bool rawLogContains string }{ + { + "not enough args", + []string{}, + true, "", + }, { "with invalid hash", []string{"somethinginvalid", fmt.Sprintf("--%s=json", tmcli.OutputFlag)}, - true, - "", + true, "", }, { "with valid and not existing hash", []string{"C7E7D3A86A17AB3A321172239F3B61357937AF0F25D9FA4D2F4DCCAD9B0D7747", fmt.Sprintf("--%s=json", tmcli.OutputFlag)}, - true, - "", + true, "", }, { "happy case (legacy Msg)", @@ -318,6 +342,120 @@ func (s *IntegrationTestSuite) TestCLIQueryTxCmd() { } } +func (s *IntegrationTestSuite) TestCLIQueryTxCmdByEvents() { + val := s.network.Validators[0] + + account2, err := val.ClientCtx.Keyring.Key("newAccount2") + s.Require().NoError(err) + + sendTokens := sdk.NewInt64Coin(s.cfg.BondDenom, 10) + + // Send coins. + out, err := s.createBankMsg( + val, account2.GetAddress(), + sdk.NewCoins(sendTokens), + ) + s.Require().NoError(err) + var txRes sdk.TxResponse + s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &txRes)) + s.Require().NoError(s.network.WaitForNextBlock()) + + // Query the tx by hash to get the inner tx. + out, err = clitestutil.ExecTestCLICmd(val.ClientCtx, authcli.QueryTxCmd(), []string{txRes.TxHash, fmt.Sprintf("--%s=json", tmcli.OutputFlag)}) + s.Require().NoError(err) + s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &txRes)) + protoTx := txRes.GetTx().(*tx.Tx) + + testCases := []struct { + name string + args []string + expectErr bool + expectErrStr string + }{ + { + "invalid --type", + []string{ + fmt.Sprintf("--type=%s", "foo"), + "bar", + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, "unknown --type value foo", + }, + { + "--type=acc_seq with no addr+seq", + []string{ + "--type=acc_seq", + "", + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, "`acc_seq` type takes an argument '/'", + }, + { + "non-existing addr+seq combo", + []string{ + "--type=acc_seq", + "foobar", + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, "found no txs matching given address and sequence combination", + }, + { + "addr+seq happy case", + []string{ + "--type=acc_seq", + fmt.Sprintf("%s/%d", val.Address, protoTx.AuthInfo.SignerInfos[0].Sequence), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, "", + }, + { + "--type=signature with no signature", + []string{ + "--type=signature", + "", + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, "argument should be comma-separated signatures", + }, + { + "non-existing signatures", + []string{ + "--type=signature", + "foo", + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, "found no txs matching given signatures", + }, + { + "with --signatures happy case", + []string{ + "--type=signature", + base64.StdEncoding.EncodeToString(protoTx.Signatures[0]), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, "", + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := authcli.QueryTxCmd() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + s.Require().Contains(err.Error(), tc.expectErrStr) + } else { + var result sdk.TxResponse + s.Require().NoError(val.ClientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &result)) + s.Require().NotNil(result.Height) + } + }) + } +} + func (s *IntegrationTestSuite) TestCLISendGenerateSignAndBroadcast() { val1 := s.network.Validators[0] @@ -732,7 +870,7 @@ func (s *IntegrationTestSuite) TestCLIMultisign() { sign1File := testutil.WriteToNewTempFile(s.T(), account1Signature.String()) - // Sign with account1 + // Sign with account2 account2Signature, err := authtest.TxSignExec(val1.ClientCtx, account2.GetAddress(), multiGeneratedTxFile.Name(), "--multisig", multisigInfo.GetAddress().String()) s.Require().NoError(err) @@ -1136,22 +1274,15 @@ func (s *IntegrationTestSuite) TestSignWithMultiSigners_AminoJSON() { require.Equal(sdk.NewCoins(val0Coin, val1Coin), queryRes.Balances) } -func (s *IntegrationTestSuite) createBankMsg(val *network.Validator, toAddr sdk.AccAddress) testutil.BufferWriter { - res, err := bankcli.MsgSendExec( - val.ClientCtx, - val.Address, - toAddr, - sdk.NewCoins( - sdk.NewCoin(fmt.Sprintf("%stoken", val.Moniker), sdk.NewInt(10)), - sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10)), - ), - fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), +func (s *IntegrationTestSuite) createBankMsg(val *network.Validator, toAddr sdk.AccAddress, amount sdk.Coins, extraFlags ...string) (testutil.BufferWriter, error) { + flags := []string{fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), - fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), - fmt.Sprintf("--%s=true", flags.FlagGenerateOnly), - ) - s.Require().NoError(err) - return res + fmt.Sprintf("--%s=%s", flags.FlagFees, + sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()), + } + + flags = append(flags, extraFlags...) + return bankcli.MsgSendExec(val.ClientCtx, val.Address, toAddr, amount, flags...) } func TestIntegrationTestSuite(t *testing.T) { diff --git a/x/auth/client/cli/query.go b/x/auth/client/cli/query.go index 2590858b4c20..c136630c2c6c 100644 --- a/x/auth/client/cli/query.go +++ b/x/auth/client/cli/query.go @@ -11,6 +11,8 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/query" "github.com/cosmos/cosmos-sdk/types/rest" "github.com/cosmos/cosmos-sdk/version" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" @@ -19,6 +21,11 @@ import ( const ( flagEvents = "events" + flagType = "type" + + typeHash = "hash" + typeAccSeq = "acc_seq" + typeSig = "signature" eventFormat = "{eventType}.{eventAttribute}={value}" ) @@ -179,28 +186,110 @@ $ %s query txs --%s 'message.sender=cosmos1...&message.action=withdraw_delegator // QueryTxCmd implements the default command for a tx query. func QueryTxCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "tx [hash]", - Short: "Query for a transaction by hash in a committed block", - Args: cobra.ExactArgs(1), + Use: "tx --type=[hash|acc_seq|signature] [hash|acc_seq|signature]", + Short: "Query for a transaction by hash, addr++seq combination or signature in a committed block", + Long: strings.TrimSpace(fmt.Sprintf(` +Example: +$ %s query tx +$ %s query tx --%s=%s : +$ %s query tx --%s=%s +`, + version.AppName, + version.AppName, flagType, typeAccSeq, + version.AppName, flagType, typeSig)), + Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { return err } - output, err := authclient.QueryTx(clientCtx, args[0]) - if err != nil { - return err - } - if output.Empty() { - return fmt.Errorf("no transaction found with hash %s", args[0]) - } + typ, _ := cmd.Flags().GetString(flagType) + + switch typ { + case typeHash: + { + if args[0] == "" { + return fmt.Errorf("argument should be a tx hash") + } + + // If hash is given, then query the tx by hash. + output, err := authclient.QueryTx(clientCtx, args[0]) + if err != nil { + return err + } - return clientCtx.PrintProto(output) + if output.Empty() { + return fmt.Errorf("no transaction found with hash %s", args[0]) + } + + return clientCtx.PrintProto(output) + } + case typeSig: + { + sigParts, err := parseSigArgs(args) + if err != nil { + return err + } + tmEvents := make([]string, len(sigParts)) + for i, sig := range sigParts { + tmEvents[i] = fmt.Sprintf("%s.%s='%s'", sdk.EventTypeTx, sdk.AttributeKeySignature, sig) + } + + txs, err := authclient.QueryTxsByEvents(clientCtx, tmEvents, rest.DefaultPage, query.DefaultLimit, "") + if err != nil { + return err + } + if len(txs.Txs) == 0 { + return fmt.Errorf("found no txs matching given signatures") + } + if len(txs.Txs) > 1 { + // This case means there's a bug somewhere else in the code. Should not happen. + return errors.Wrapf(errors.ErrLogic, "found %d txs matching given signatures", len(txs.Txs)) + } + + return clientCtx.PrintProto(txs.Txs[0]) + } + case typeAccSeq: + { + if args[0] == "" { + return fmt.Errorf("`acc_seq` type takes an argument '/'") + } + + tmEvents := []string{ + fmt.Sprintf("%s.%s='%s'", sdk.EventTypeTx, sdk.AttributeKeyAccountSequence, args[0]), + } + txs, err := authclient.QueryTxsByEvents(clientCtx, tmEvents, rest.DefaultPage, query.DefaultLimit, "") + if err != nil { + return err + } + if len(txs.Txs) == 0 { + return fmt.Errorf("found no txs matching given address and sequence combination") + } + if len(txs.Txs) > 1 { + // This case means there's a bug somewhere else in the code. Should not happen. + return fmt.Errorf("found %d txs matching given address and sequence combination", len(txs.Txs)) + } + + return clientCtx.PrintProto(txs.Txs[0]) + } + default: + return fmt.Errorf("unknown --%s value %s", flagType, typ) + } }, } flags.AddQueryFlagsToCmd(cmd) + cmd.Flags().String(flagType, typeHash, fmt.Sprintf("The type to be used when querying tx, can be one of \"%s\", \"%s\", \"%s\"", typeHash, typeAccSeq, typeSig)) return cmd } + +// parseSigArgs parses comma-separated signatures from the CLI arguments. +func parseSigArgs(args []string) ([]string, error) { + if len(args) != 1 || args[0] == "" { + return nil, fmt.Errorf("argument should be comma-separated signatures") + } + + return strings.Split(args[0], ","), nil +} diff --git a/x/auth/client/cli/query_test.go b/x/auth/client/cli/query_test.go new file mode 100644 index 000000000000..0168d3008179 --- /dev/null +++ b/x/auth/client/cli/query_test.go @@ -0,0 +1,32 @@ +package cli + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestParseSigs(t *testing.T) { + cases := []struct { + name string + args []string + expErr bool + expNumSigs int + }{ + {"no args", []string{}, true, 0}, + {"empty args", []string{""}, true, 0}, + {"too many args", []string{"foo", "bar"}, true, 0}, + {"1 sig", []string{"foo"}, false, 1}, + {"3 sigs", []string{"foo,bar,baz"}, false, 3}, + } + + for _, tc := range cases { + sigs, err := parseSigArgs(tc.args) + if tc.expErr { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, tc.expNumSigs, len(sigs)) + } + } +} diff --git a/x/ibc/core/02-client/keeper/client_test.go b/x/ibc/core/02-client/keeper/client_test.go index 21d59b74025c..0f14ef2135bf 100644 --- a/x/ibc/core/02-client/keeper/client_test.go +++ b/x/ibc/core/02-client/keeper/client_test.go @@ -615,8 +615,8 @@ func (suite *KeeperTestSuite) TestUpdateClientEventEmission() { result, err := suite.chainA.SendMsgs(msg) suite.Require().NoError(err) - // first event type is "message" - updateEvent := result.Events[1] + // first 3 event type are "tx.signature", "tx.acc_seq", and "message" + updateEvent := result.Events[3] suite.Require().Equal(clienttypes.EventTypeUpdateClient, updateEvent.Type) From 6fb1a17a21b15ccc515c8304d2515040d905f74a Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 28 Jul 2021 16:51:58 +0200 Subject: [PATCH 5/6] fix: hardcoded ledger algo on `keys add` (backport #9766) (#9804) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: hardcoded ledger algo on `keys add` (#9766) ## Description Closes: #9734 cc: @jleni --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [x] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [x] added `!` to the type prefix if API or client breaking change - [x] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [x] provided a link to the relevant issue or specification - [x] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [x] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [x] added a changelog entry to `CHANGELOG.md` - [x] included comments for [documenting Go code](https://blog.golang.org/godoc) - [x] updated the relevant documentation or specification - [x] reviewed "Files changed" and left comments if necessary - [x] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [x] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [x] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [x] reviewed tests and test coverage - [ ] manually tested (if applicable) (cherry picked from commit f1e64878d8a66e3343112605ad19e48306b77273) # Conflicts: # CHANGELOG.md * fix conflict Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Amaury M <1293565+amaurym@users.noreply.github.com> --- CHANGELOG.md | 4 ++++ client/keys/add.go | 2 +- crypto/keyring/keyring.go | 7 +++++-- crypto/keyring/keyring_ledger_test.go | 4 +++- crypto/ledger/ledger_secp256k1.go | 6 +++--- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 830ce54bd607..2134cc863ff5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (cli) [\#9717](https://github.com/cosmos/cosmos-sdk/pull/9717) Added CLI flag `--output json/text` to `tx` cli commands. +### Bug Fixes + +* [\#9766](https://github.com/cosmos/cosmos-sdk/pull/9766) Fix hardcoded ledger signing algorithm on `keys add` command. + ## [v0.42.7](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.42.7) - 2021-07-09 ### Improvements diff --git a/client/keys/add.go b/client/keys/add.go index 979983b9bdfe..20c142c777b3 100644 --- a/client/keys/add.go +++ b/client/keys/add.go @@ -200,8 +200,8 @@ func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf // If we're using ledger, only thing we need is the path and the bech32 prefix. if useLedger { bech32PrefixAccAddr := sdk.GetConfig().GetBech32AccountAddrPrefix() - info, err := kb.SaveLedgerKey(name, hd.Secp256k1, bech32PrefixAccAddr, coinType, account, index) + info, err := kb.SaveLedgerKey(name, algo, bech32PrefixAccAddr, coinType, account, index) if err != nil { return err } diff --git a/crypto/keyring/keyring.go b/crypto/keyring/keyring.go index febad555df9c..b18d6073228e 100644 --- a/crypto/keyring/keyring.go +++ b/crypto/keyring/keyring.go @@ -379,14 +379,17 @@ func (ks keystore) SignByAddress(address sdk.Address, msg []byte) ([]byte, types func (ks keystore) SaveLedgerKey(uid string, algo SignatureAlgo, hrp string, coinType, account, index uint32) (Info, error) { if !ks.options.SupportedAlgosLedger.Contains(algo) { - return nil, ErrUnsupportedSigningAlgo + return nil, fmt.Errorf( + "%w: signature algo %s is not defined in the keyring options", + ErrUnsupportedSigningAlgo, algo.Name(), + ) } hdPath := hd.NewFundraiserParams(account, coinType, index) priv, _, err := ledger.NewPrivKeySecp256k1(*hdPath, hrp) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to generate ledger key: %w", err) } return ks.writeLedgerKey(uid, priv.PubKey(), *hdPath, algo.Name()) diff --git a/crypto/keyring/keyring_ledger_test.go b/crypto/keyring/keyring_ledger_test.go index eb7e85f9e89c..b940970af1df 100644 --- a/crypto/keyring/keyring_ledger_test.go +++ b/crypto/keyring/keyring_ledger_test.go @@ -95,7 +95,8 @@ func TestAltKeyring_SaveLedgerKey(t *testing.T) { // Test unsupported Algo _, err = keyring.SaveLedgerKey("key", notSupportedAlgo{}, "cosmos", 118, 0, 0) - require.EqualError(t, err, ErrUnsupportedSigningAlgo.Error()) + require.Error(t, err) + require.Contains(t, err.Error(), ErrUnsupportedSigningAlgo.Error()) ledger, err := keyring.SaveLedgerKey("some_account", hd.Secp256k1, "cosmos", 118, 3, 1) if err != nil { @@ -103,6 +104,7 @@ func TestAltKeyring_SaveLedgerKey(t *testing.T) { t.Skip("ledger nano S: support for ledger devices is not available in this executable") return } + // The mock is available, check that the address is correct require.Equal(t, "some_account", ledger.GetName()) pubKey := ledger.GetPubKey() diff --git a/crypto/ledger/ledger_secp256k1.go b/crypto/ledger/ledger_secp256k1.go index 659181d30648..ee2f873544c4 100644 --- a/crypto/ledger/ledger_secp256k1.go +++ b/crypto/ledger/ledger_secp256k1.go @@ -73,13 +73,13 @@ func NewPrivKeySecp256k1Unsafe(path hd.BIP44Params) (types.LedgerPrivKey, error) func NewPrivKeySecp256k1(path hd.BIP44Params, hrp string) (types.LedgerPrivKey, string, error) { device, err := getDevice() if err != nil { - return nil, "", err + return nil, "", fmt.Errorf("failed to retrieve device: %w", err) } defer warnIfErrors(device.Close) pubKey, addr, err := getPubKeyAddrSafe(device, path, hrp) if err != nil { - return nil, "", err + return nil, "", fmt.Errorf("failed to recover pubkey: %w", err) } return PrivKeyLedgerSecp256k1{pubKey, path}, addr, nil @@ -261,7 +261,7 @@ func getPubKeyUnsafe(device SECP256K1, path hd.BIP44Params) (types.PubKey, error func getPubKeyAddrSafe(device SECP256K1, path hd.BIP44Params, hrp string) (types.PubKey, string, error) { publicKey, addr, err := device.GetAddressPubKeySECP256K1(path.DerivationPath(), hrp) if err != nil { - return nil, "", fmt.Errorf("address %s rejected", addr) + return nil, "", fmt.Errorf("%w: address rejected for path %s", err, path.String()) } // re-serialize in the 33-byte compressed format From ef823eacbbe1d56c8bb2764dd782c6cbd6505486 Mon Sep 17 00:00:00 2001 From: Amaury <1293565+amaurym@users.noreply.github.com> Date: Fri, 30 Jul 2021 10:27:24 +0200 Subject: [PATCH 6/6] chore: Add Changelog and Release Notes for v0.42.8 (#9807) * chore: Add Changelog and Release Notes for v0.42.8 * Change date --- CHANGELOG.md | 2 ++ RELEASE_NOTES.md | 11 +++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2134cc863ff5..2c05bc1a6211 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## Unreleased +## [v0.42.8](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.42.8) - 2021-07-30 + ### Features * [\#9750](https://github.com/cosmos/cosmos-sdk/pull/9750) Emit events for tx signature and sequence, so clients can now query txs by signature (`tx.signature=''`) or by address and sequence combo (`tx.acc_seq='/'`). diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 78536d4d7b99..f7ef04b1e531 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,10 +1,9 @@ -# Cosmos SDK v0.42.7 "Stargate" Release Notes +# Cosmos SDK v0.42.8 "Stargate" Release Notes This release includes various minor bugfixes and improvments, including: -- a x/capability initialization fix, which fixes the consensus error when using statesync, -- CLI improvements such as fixing the `{appd} keys parse` subcommand and a better user error when `--chain-id` is not passed in the `{appd} tx multisign` subcommand, -- add a new `Trace()` method on BaseApp to return the `trace` value for logging error stack traces, -- IBC fixes for the `Transfer` event and telemetry metrics. +- emit events for tx signature and sequence, so clients can now query txs by signature (`tx.signature=''`) or by address and sequence combo (`tx.acc_seq='/'`), +- support other signing algorithms than `secp256k1` with `--ledger` in with the CLI `keys add` command, +- add missing documentation for CLI flag `--output json/text` to all `tx` cli commands. -See the [Cosmos SDK v0.42.7 milestone](https://github.com/cosmos/cosmos-sdk/milestone/48?closed=1) on our issue tracker for the exhaustive list of all changes. +See the [Cosmos SDK v0.42.8 milestone](https://github.com/cosmos/cosmos-sdk/milestone/50?closed=1) on our issue tracker for the exhaustive list of all changes.