Skip to content

Commit 4d3108b

Browse files
committed
feat(client): replace event-query-tx-for with wait-tx
1 parent 6e9528a commit 4d3108b

File tree

3 files changed

+84
-11
lines changed

3 files changed

+84
-11
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i
5555
* (gRPC) [#19049](https://github.com/cosmos/cosmos-sdk/pull/19049) Add debug log prints for each gRPC request.
5656
* (x/consensus) [#19483](https://github.com/cosmos/cosmos-sdk/pull/19483) Add consensus messages registration to consensus module.
5757
* (types) [#19759](https://github.com/cosmos/cosmos-sdk/pull/19759) Align SignerExtractionAdapter in PriorityNonceMempool Remove.
58+
* (client) [#19870](https://github.com/cosmos/cosmos-sdk/pull/19870) Replace `event-query-tx-for` command with a new one called `wait-tx`
5859

5960
### Improvements
6061

client/rpc/tx.go

+82-10
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package rpc
33
import (
44
"context"
55
"encoding/hex"
6+
"encoding/json"
67
"fmt"
8+
"io"
79
"strings"
810
"time"
911

@@ -16,8 +18,11 @@ import (
1618
"github.com/cosmos/cosmos-sdk/client/flags"
1719
sdk "github.com/cosmos/cosmos-sdk/types"
1820
"github.com/cosmos/cosmos-sdk/types/errors"
21+
"github.com/cosmos/cosmos-sdk/version"
1922
)
2023

24+
const TimeoutFlag = "timeout"
25+
2126
func newTxResponseCheckTx(res *coretypes.ResultBroadcastTxCommit) *sdk.TxResponse {
2227
if res == nil {
2328
return nil
@@ -84,18 +89,30 @@ func newResponseFormatBroadcastTxCommit(res *coretypes.ResultBroadcastTxCommit)
8489
return newTxResponseDeliverTx(res)
8590
}
8691

87-
// QueryEventForTxCmd returns a CLI command that subscribes to a WebSocket connection and waits for a transaction event with the given hash.
88-
func QueryEventForTxCmd() *cobra.Command {
92+
// WaitTx returns a CLI command that waits for a transaction with the given hash to be included in a block.
93+
func WaitTxCmd() *cobra.Command {
8994
cmd := &cobra.Command{
90-
Use: "event-query-tx-for [hash]",
91-
Short: "Query for a transaction by hash",
95+
Use: "wait-tx [hash]",
96+
Short: "Wait for a transaction to be included in a block",
9297
Long: `Subscribes to a CometBFT WebSocket connection and waits for a transaction event with the given hash.`,
93-
Args: cobra.ExactArgs(1),
98+
Example: fmt.Sprintf(`By providing the transaction hash:
99+
$ %[1]sd q wait-tx [hash]
100+
101+
Or, by piping a "tx" command:
102+
$ %[1]sd tx [flags] | %[1]sd q wait-tx
103+
`, version.AppName),
104+
Args: cobra.MaximumNArgs(1),
94105
RunE: func(cmd *cobra.Command, args []string) error {
95106
clientCtx, err := client.GetClientTxContext(cmd)
96107
if err != nil {
97108
return err
98109
}
110+
111+
timeout, err := cmd.Flags().GetDuration(TimeoutFlag)
112+
if err != nil {
113+
return err
114+
}
115+
99116
c, err := rpchttp.New(clientCtx.NodeURI, "/websocket")
100117
if err != nil {
101118
return err
@@ -105,18 +122,54 @@ func QueryEventForTxCmd() *cobra.Command {
105122
}
106123
defer c.Stop() //nolint:errcheck // ignore stop error
107124

108-
ctx, cancel := context.WithTimeout(context.Background(), time.Second*15)
125+
ctx, cancel := context.WithTimeout(context.Background(), timeout)
109126
defer cancel()
110127

111-
hash := args[0]
112-
query := fmt.Sprintf("%s='%s' AND %s='%s'", tmtypes.EventTypeKey, tmtypes.EventTx, tmtypes.TxHashKey, hash)
128+
var hash []byte
129+
if len(args) == 0 {
130+
// read hash from stdin
131+
in, err := io.ReadAll(cmd.InOrStdin())
132+
if err != nil {
133+
return err
134+
}
135+
hashByt, err := parseHashFromInput(in)
136+
if err != nil {
137+
return err
138+
}
139+
140+
hash = hashByt
141+
} else {
142+
// read hash from args
143+
hashByt, err := hex.DecodeString(args[0])
144+
if err != nil {
145+
return err
146+
}
147+
148+
hash = hashByt
149+
}
150+
151+
// subscribe to websocket events
152+
query := fmt.Sprintf("%s='%s' AND %s='%X'", tmtypes.EventTypeKey, tmtypes.EventTx, tmtypes.TxHashKey, hash)
113153
const subscriber = "subscriber"
114154
eventCh, err := c.Subscribe(ctx, subscriber, query)
115155
if err != nil {
116156
return fmt.Errorf("failed to subscribe to tx: %w", err)
117157
}
118158
defer c.UnsubscribeAll(context.Background(), subscriber) //nolint:errcheck // ignore unsubscribe error
119159

160+
// return immediately if tx is already included in a block
161+
res, err := c.Tx(ctx, hash, false)
162+
if err == nil {
163+
// tx already included in a block
164+
res := &coretypes.ResultBroadcastTxCommit{
165+
TxResult: res.TxResult,
166+
Hash: res.Hash,
167+
Height: res.Height,
168+
}
169+
return clientCtx.PrintProto(newResponseFormatBroadcastTxCommit(res))
170+
}
171+
172+
// tx not yet included in a block, wait for event on websocket
120173
select {
121174
case evt := <-eventCh:
122175
if txe, ok := evt.Data.(tmtypes.EventDataTx); ok {
@@ -128,13 +181,32 @@ func QueryEventForTxCmd() *cobra.Command {
128181
return clientCtx.PrintProto(newResponseFormatBroadcastTxCommit(res))
129182
}
130183
case <-ctx.Done():
131-
return errors.ErrLogic.Wrapf("timed out waiting for event, the transaction could have already been included or wasn't yet included")
184+
return errors.ErrLogic.Wrapf("timed out waiting for transaction %X to be included in a block", hash)
132185
}
133186
return nil
134187
},
135188
}
136189

137-
flags.AddTxFlagsToCmd(cmd)
190+
cmd.Flags().Duration(TimeoutFlag, 15*time.Second, "The maximum time to wait for the transaction to be included in a block")
191+
flags.AddQueryFlagsToCmd(cmd)
138192

139193
return cmd
140194
}
195+
196+
func parseHashFromInput(in []byte) ([]byte, error) {
197+
var resultTx coretypes.ResultTx
198+
if err := json.Unmarshal(in, &resultTx); err == nil {
199+
// input was JSON, return the hash
200+
return resultTx.Hash, nil
201+
}
202+
203+
// try to parse the hash from the output of a tx command
204+
lines := strings.Split(string(in), "\n")
205+
for _, line := range lines {
206+
if strings.HasPrefix(line, "txhash:") {
207+
hash := strings.TrimSpace(line[len("txhash:"):])
208+
return hex.DecodeString(hash)
209+
}
210+
}
211+
return nil, fmt.Errorf("txhash not found")
212+
}

simapp/simd/cmd/commands.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ func queryCommand() *cobra.Command {
8585
}
8686

8787
cmd.AddCommand(
88-
rpc.QueryEventForTxCmd(),
88+
rpc.WaitTxCmd(),
8989
server.QueryBlockCmd(),
9090
authcmd.QueryTxsByEventsCmd(),
9191
server.QueryBlocksCmd(),

0 commit comments

Comments
 (0)