|
1 | 1 | package cli
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "context" |
| 5 | + "encoding/hex" |
4 | 6 | "fmt"
|
5 | 7 | "strings"
|
| 8 | + "time" |
6 | 9 |
|
7 | 10 | "github.com/spf13/cobra"
|
8 | 11 |
|
| 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" |
9 | 15 | "github.com/cosmos/cosmos-sdk/client"
|
10 | 16 | "github.com/cosmos/cosmos-sdk/client/flags"
|
11 | 17 | sdk "github.com/cosmos/cosmos-sdk/types"
|
@@ -179,6 +185,126 @@ $ %s query tx --%s=%s <sig1_base64>,<sig2_base64...>
|
179 | 185 | return cmd
|
180 | 186 | }
|
181 | 187 |
|
| 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 | + |
182 | 308 | // ParseSigArgs parses comma-separated signatures from the CLI arguments.
|
183 | 309 | func ParseSigArgs(args []string) ([]string, error) {
|
184 | 310 | if len(args) != 1 || args[0] == "" {
|
|
0 commit comments