From e98849ee645d90e60a8d337e37e36528f09b3573 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Thu, 3 Aug 2023 20:57:01 +0800 Subject: [PATCH] add event-query-tx-for cmd to subscribe and wait for transaction --- CHANGELOG.md | 1 + x/auth/client/cli/query.go | 126 +++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d25ab2a7f81c..68ed62012ba7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features * (x/bank) [#16795](https://github.com/cosmos/cosmos-sdk/pull/16852) Add `DenomMetadataByQueryString` query in bank module to support metadata query by query string. +* (x/auth) [#17274](https://github.com/cosmos/cosmos-sdk/pull/17274) Add `QueryEventForTxCmd` cmd to subscribe and wait event for transaction by hash. ### Improvements diff --git a/x/auth/client/cli/query.go b/x/auth/client/cli/query.go index 8d3ee8e793db..9f7a8c847821 100644 --- a/x/auth/client/cli/query.go +++ b/x/auth/client/cli/query.go @@ -1,11 +1,17 @@ package cli import ( + "context" + "encoding/hex" "fmt" "strings" + "time" "github.com/spf13/cobra" + rpchttp "github.com/cometbft/cometbft/rpc/client/http" + coretypes "github.com/cometbft/cometbft/rpc/core/types" + tmtypes "github.com/cometbft/cometbft/types" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" sdk "github.com/cosmos/cosmos-sdk/types" @@ -179,6 +185,126 @@ $ %s query tx --%s=%s , return cmd } +func newTxResponseCheckTx(res *coretypes.ResultBroadcastTxCommit) *sdk.TxResponse { + if res == nil { + return nil + } + + var txHash string + if res.Hash != nil { + txHash = res.Hash.String() + } + + parsedLogs, _ := sdk.ParseABCILogs(res.CheckTx.Log) + + return &sdk.TxResponse{ + Height: res.Height, + TxHash: txHash, + Codespace: res.CheckTx.Codespace, + Code: res.CheckTx.Code, + Data: strings.ToUpper(hex.EncodeToString(res.CheckTx.Data)), + RawLog: res.CheckTx.Log, + Logs: parsedLogs, + Info: res.CheckTx.Info, + GasWanted: res.CheckTx.GasWanted, + GasUsed: res.CheckTx.GasUsed, + Events: res.CheckTx.Events, + } +} + +func newTxResponseDeliverTx(res *coretypes.ResultBroadcastTxCommit) *sdk.TxResponse { + if res == nil { + return nil + } + + var txHash string + if res.Hash != nil { + txHash = res.Hash.String() + } + + parsedLogs, _ := sdk.ParseABCILogs(res.TxResult.Log) + + return &sdk.TxResponse{ + Height: res.Height, + TxHash: txHash, + Codespace: res.TxResult.Codespace, + Code: res.TxResult.Code, + Data: strings.ToUpper(hex.EncodeToString(res.TxResult.Data)), + RawLog: res.TxResult.Log, + Logs: parsedLogs, + Info: res.TxResult.Info, + GasWanted: res.TxResult.GasWanted, + GasUsed: res.TxResult.GasUsed, + Events: res.TxResult.Events, + } +} + +func newResponseFormatBroadcastTxCommit(res *coretypes.ResultBroadcastTxCommit) *sdk.TxResponse { + if res == nil { + return nil + } + + if !res.CheckTx.IsOK() { + return newTxResponseCheckTx(res) + } + + return newTxResponseDeliverTx(res) +} + +// QueryEventForTxCmd returns a CLI command that subscribes to a WebSocket connection and waits for a transaction event with the given hash. +func QueryEventForTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "event-query-tx-for [hash]", + Short: "event-query-tx-for [hash]", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + c, err := rpchttp.New(clientCtx.NodeURI, "/websocket") + if err != nil { + return err + } + if err := c.Start(); err != nil { + return err + } + defer c.Stop() //nolint:errcheck // ignore stop error + + ctx, cancel := context.WithTimeout(context.Background(), time.Second*15) + defer cancel() + + hash := args[0] + query := fmt.Sprintf("%s='%s' AND %s='%s'", tmtypes.EventTypeKey, tmtypes.EventTx, tmtypes.TxHashKey, hash) + const subscriber = "subscriber" + eventCh, err := c.Subscribe(ctx, subscriber, query) + if err != nil { + return fmt.Errorf("failed to subscribe to tx: %w", err) + } + defer c.UnsubscribeAll(context.Background(), subscriber) //nolint:errcheck // ignore unsubscribe error + + select { + case evt := <-eventCh: + if txe, ok := evt.Data.(tmtypes.EventDataTx); ok { + res := &coretypes.ResultBroadcastTxCommit{ + TxResult: txe.Result, + Hash: tmtypes.Tx(txe.Tx).Hash(), + Height: txe.Height, + } + return clientCtx.PrintProto(newResponseFormatBroadcastTxCommit(res)) + } + case <-ctx.Done(): + return errors.ErrLogic.Wrapf("timed out waiting for event") + } + return nil + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + // ParseSigArgs parses comma-separated signatures from the CLI arguments. func ParseSigArgs(args []string) ([]string, error) { if len(args) != 1 || args[0] == "" {