Skip to content

Commit e98849e

Browse files
committed
add event-query-tx-for cmd to subscribe and wait for transaction
1 parent 92dffb5 commit e98849e

File tree

2 files changed

+127
-0
lines changed

2 files changed

+127
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
4141
### Features
4242

4343
* (x/bank) [#16795](https://github.com/cosmos/cosmos-sdk/pull/16852) Add `DenomMetadataByQueryString` query in bank module to support metadata query by query string.
44+
* (x/auth) [#17274](https://github.com/cosmos/cosmos-sdk/pull/17274) Add `QueryEventForTxCmd` cmd to subscribe and wait event for transaction by hash.
4445

4546
### Improvements
4647

x/auth/client/cli/query.go

+126
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
package cli
22

33
import (
4+
"context"
5+
"encoding/hex"
46
"fmt"
57
"strings"
8+
"time"
69

710
"github.com/spf13/cobra"
811

12+
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
13+
coretypes "github.com/cometbft/cometbft/rpc/core/types"
14+
tmtypes "github.com/cometbft/cometbft/types"
915
"github.com/cosmos/cosmos-sdk/client"
1016
"github.com/cosmos/cosmos-sdk/client/flags"
1117
sdk "github.com/cosmos/cosmos-sdk/types"
@@ -179,6 +185,126 @@ $ %s query tx --%s=%s <sig1_base64>,<sig2_base64...>
179185
return cmd
180186
}
181187

188+
func newTxResponseCheckTx(res *coretypes.ResultBroadcastTxCommit) *sdk.TxResponse {
189+
if res == nil {
190+
return nil
191+
}
192+
193+
var txHash string
194+
if res.Hash != nil {
195+
txHash = res.Hash.String()
196+
}
197+
198+
parsedLogs, _ := sdk.ParseABCILogs(res.CheckTx.Log)
199+
200+
return &sdk.TxResponse{
201+
Height: res.Height,
202+
TxHash: txHash,
203+
Codespace: res.CheckTx.Codespace,
204+
Code: res.CheckTx.Code,
205+
Data: strings.ToUpper(hex.EncodeToString(res.CheckTx.Data)),
206+
RawLog: res.CheckTx.Log,
207+
Logs: parsedLogs,
208+
Info: res.CheckTx.Info,
209+
GasWanted: res.CheckTx.GasWanted,
210+
GasUsed: res.CheckTx.GasUsed,
211+
Events: res.CheckTx.Events,
212+
}
213+
}
214+
215+
func newTxResponseDeliverTx(res *coretypes.ResultBroadcastTxCommit) *sdk.TxResponse {
216+
if res == nil {
217+
return nil
218+
}
219+
220+
var txHash string
221+
if res.Hash != nil {
222+
txHash = res.Hash.String()
223+
}
224+
225+
parsedLogs, _ := sdk.ParseABCILogs(res.TxResult.Log)
226+
227+
return &sdk.TxResponse{
228+
Height: res.Height,
229+
TxHash: txHash,
230+
Codespace: res.TxResult.Codespace,
231+
Code: res.TxResult.Code,
232+
Data: strings.ToUpper(hex.EncodeToString(res.TxResult.Data)),
233+
RawLog: res.TxResult.Log,
234+
Logs: parsedLogs,
235+
Info: res.TxResult.Info,
236+
GasWanted: res.TxResult.GasWanted,
237+
GasUsed: res.TxResult.GasUsed,
238+
Events: res.TxResult.Events,
239+
}
240+
}
241+
242+
func newResponseFormatBroadcastTxCommit(res *coretypes.ResultBroadcastTxCommit) *sdk.TxResponse {
243+
if res == nil {
244+
return nil
245+
}
246+
247+
if !res.CheckTx.IsOK() {
248+
return newTxResponseCheckTx(res)
249+
}
250+
251+
return newTxResponseDeliverTx(res)
252+
}
253+
254+
// QueryEventForTxCmd returns a CLI command that subscribes to a WebSocket connection and waits for a transaction event with the given hash.
255+
func QueryEventForTxCmd() *cobra.Command {
256+
cmd := &cobra.Command{
257+
Use: "event-query-tx-for [hash]",
258+
Short: "event-query-tx-for [hash]",
259+
Args: cobra.ExactArgs(1),
260+
RunE: func(cmd *cobra.Command, args []string) error {
261+
clientCtx, err := client.GetClientTxContext(cmd)
262+
if err != nil {
263+
return err
264+
}
265+
c, err := rpchttp.New(clientCtx.NodeURI, "/websocket")
266+
if err != nil {
267+
return err
268+
}
269+
if err := c.Start(); err != nil {
270+
return err
271+
}
272+
defer c.Stop() //nolint:errcheck // ignore stop error
273+
274+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*15)
275+
defer cancel()
276+
277+
hash := args[0]
278+
query := fmt.Sprintf("%s='%s' AND %s='%s'", tmtypes.EventTypeKey, tmtypes.EventTx, tmtypes.TxHashKey, hash)
279+
const subscriber = "subscriber"
280+
eventCh, err := c.Subscribe(ctx, subscriber, query)
281+
if err != nil {
282+
return fmt.Errorf("failed to subscribe to tx: %w", err)
283+
}
284+
defer c.UnsubscribeAll(context.Background(), subscriber) //nolint:errcheck // ignore unsubscribe error
285+
286+
select {
287+
case evt := <-eventCh:
288+
if txe, ok := evt.Data.(tmtypes.EventDataTx); ok {
289+
res := &coretypes.ResultBroadcastTxCommit{
290+
TxResult: txe.Result,
291+
Hash: tmtypes.Tx(txe.Tx).Hash(),
292+
Height: txe.Height,
293+
}
294+
return clientCtx.PrintProto(newResponseFormatBroadcastTxCommit(res))
295+
}
296+
case <-ctx.Done():
297+
return errors.ErrLogic.Wrapf("timed out waiting for event")
298+
}
299+
return nil
300+
},
301+
}
302+
303+
flags.AddTxFlagsToCmd(cmd)
304+
305+
return cmd
306+
}
307+
182308
// ParseSigArgs parses comma-separated signatures from the CLI arguments.
183309
func ParseSigArgs(args []string) ([]string, error) {
184310
if len(args) != 1 || args[0] == "" {

0 commit comments

Comments
 (0)