github.com/cosmos/cosmos-sdk@v0.50.10/server/cmt_cmds.go (about) 1 package server 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "strconv" 8 "strings" 9 10 cmtcfg "github.com/cometbft/cometbft/config" 11 cmtjson "github.com/cometbft/cometbft/libs/json" 12 "github.com/cometbft/cometbft/node" 13 "github.com/cometbft/cometbft/p2p" 14 pvm "github.com/cometbft/cometbft/privval" 15 cmtversion "github.com/cometbft/cometbft/version" 16 "github.com/spf13/cobra" 17 "sigs.k8s.io/yaml" 18 19 "cosmossdk.io/log" 20 21 "github.com/cosmos/cosmos-sdk/client" 22 "github.com/cosmos/cosmos-sdk/client/flags" 23 "github.com/cosmos/cosmos-sdk/client/grpc/cmtservice" 24 rpc "github.com/cosmos/cosmos-sdk/client/rpc" 25 cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" 26 "github.com/cosmos/cosmos-sdk/server/types" 27 sdk "github.com/cosmos/cosmos-sdk/types" 28 "github.com/cosmos/cosmos-sdk/types/query" 29 "github.com/cosmos/cosmos-sdk/version" 30 auth "github.com/cosmos/cosmos-sdk/x/auth/client/cli" 31 ) 32 33 // StatusCommand returns the command to return the status of the network. 34 func StatusCommand() *cobra.Command { 35 cmd := &cobra.Command{ 36 Use: "status", 37 Short: "Query remote node for status", 38 RunE: func(cmd *cobra.Command, _ []string) error { 39 clientCtx, err := client.GetClientQueryContext(cmd) 40 if err != nil { 41 return err 42 } 43 44 status, err := cmtservice.GetNodeStatus(context.Background(), clientCtx) 45 if err != nil { 46 return err 47 } 48 49 output, err := cmtjson.Marshal(status) 50 if err != nil { 51 return err 52 } 53 54 // In order to maintain backwards compatibility, the default json format output 55 outputFormat, _ := cmd.Flags().GetString(flags.FlagOutput) 56 if outputFormat == flags.OutputFormatJSON { 57 clientCtx = clientCtx.WithOutputFormat(flags.OutputFormatJSON) 58 } 59 60 return clientCtx.PrintRaw(output) 61 }, 62 } 63 64 cmd.Flags().StringP(flags.FlagNode, "n", "tcp://localhost:26657", "Node to connect to") 65 cmd.Flags().StringP(flags.FlagOutput, "o", "json", "Output format (text|json)") 66 67 return cmd 68 } 69 70 // ShowNodeIDCmd - ported from CometBFT, dump node ID to stdout 71 func ShowNodeIDCmd() *cobra.Command { 72 return &cobra.Command{ 73 Use: "show-node-id", 74 Short: "Show this node's ID", 75 RunE: func(cmd *cobra.Command, args []string) error { 76 serverCtx := GetServerContextFromCmd(cmd) 77 cfg := serverCtx.Config 78 79 nodeKey, err := p2p.LoadNodeKey(cfg.NodeKeyFile()) 80 if err != nil { 81 return err 82 } 83 84 cmd.Println(nodeKey.ID()) 85 return nil 86 }, 87 } 88 } 89 90 // ShowValidatorCmd - ported from CometBFT, show this node's validator info 91 func ShowValidatorCmd() *cobra.Command { 92 cmd := cobra.Command{ 93 Use: "show-validator", 94 Short: "Show this node's CometBFT validator info", 95 RunE: func(cmd *cobra.Command, args []string) error { 96 serverCtx := GetServerContextFromCmd(cmd) 97 cfg := serverCtx.Config 98 99 privValidator := pvm.LoadFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile()) 100 pk, err := privValidator.GetPubKey() 101 if err != nil { 102 return err 103 } 104 105 sdkPK, err := cryptocodec.FromCmtPubKeyInterface(pk) 106 if err != nil { 107 return err 108 } 109 110 clientCtx := client.GetClientContextFromCmd(cmd) 111 bz, err := clientCtx.Codec.MarshalInterfaceJSON(sdkPK) 112 if err != nil { 113 return err 114 } 115 116 cmd.Println(string(bz)) 117 return nil 118 }, 119 } 120 121 return &cmd 122 } 123 124 // ShowAddressCmd - show this node's validator address 125 func ShowAddressCmd() *cobra.Command { 126 cmd := &cobra.Command{ 127 Use: "show-address", 128 Short: "Shows this node's CometBFT validator consensus address", 129 RunE: func(cmd *cobra.Command, args []string) error { 130 serverCtx := GetServerContextFromCmd(cmd) 131 cfg := serverCtx.Config 132 133 privValidator := pvm.LoadFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile()) 134 135 valConsAddr := (sdk.ConsAddress)(privValidator.GetAddress()) 136 137 cmd.Println(valConsAddr.String()) 138 return nil 139 }, 140 } 141 142 return cmd 143 } 144 145 // VersionCmd prints CometBFT and ABCI version numbers. 146 func VersionCmd() *cobra.Command { 147 return &cobra.Command{ 148 Use: "version", 149 Short: "Print CometBFT libraries' version", 150 Long: "Print protocols' and libraries' version numbers against which this app has been compiled.", 151 RunE: func(cmd *cobra.Command, args []string) error { 152 bs, err := yaml.Marshal(&struct { 153 CometBFT string 154 ABCI string 155 BlockProtocol uint64 156 P2PProtocol uint64 157 }{ 158 CometBFT: cmtversion.TMCoreSemVer, 159 ABCI: cmtversion.ABCIVersion, 160 BlockProtocol: cmtversion.BlockProtocol, 161 P2PProtocol: cmtversion.P2PProtocol, 162 }) 163 if err != nil { 164 return err 165 } 166 167 cmd.Println(string(bs)) 168 return nil 169 }, 170 } 171 } 172 173 // QueryBlocksCmd returns a command to search through blocks by events. 174 func QueryBlocksCmd() *cobra.Command { 175 cmd := &cobra.Command{ 176 Use: "blocks", 177 Short: "Query for paginated blocks that match a set of events", 178 Long: `Search for blocks that match the exact given events where results are paginated. 179 The events query is directly passed to CometBFT's RPC BlockSearch method and must 180 conform to CometBFT's query syntax. 181 Please refer to each module's documentation for the full set of events to query 182 for. Each module documents its respective events under 'xx_events.md'. 183 `, 184 Example: fmt.Sprintf( 185 "$ %s query blocks --query \"message.sender='cosmos1...' AND block.height > 7\" --page 1 --limit 30 --order_by asc", 186 version.AppName, 187 ), 188 RunE: func(cmd *cobra.Command, args []string) error { 189 clientCtx, err := client.GetClientQueryContext(cmd) 190 if err != nil { 191 return err 192 } 193 query, _ := cmd.Flags().GetString(auth.FlagQuery) 194 page, _ := cmd.Flags().GetInt(flags.FlagPage) 195 limit, _ := cmd.Flags().GetInt(flags.FlagLimit) 196 orderBy, _ := cmd.Flags().GetString(auth.FlagOrderBy) 197 198 blocks, err := rpc.QueryBlocks(clientCtx, page, limit, query, orderBy) 199 if err != nil { 200 return err 201 } 202 203 return clientCtx.PrintProto(blocks) 204 }, 205 } 206 207 flags.AddQueryFlagsToCmd(cmd) 208 cmd.Flags().Int(flags.FlagPage, query.DefaultPage, "Query a specific page of paginated results") 209 cmd.Flags().Int(flags.FlagLimit, query.DefaultLimit, "Query number of transactions results per page returned") 210 cmd.Flags().String(auth.FlagQuery, "", "The blocks events query per CometBFT's query semantics") 211 cmd.Flags().String(auth.FlagOrderBy, "", "The ordering semantics (asc|dsc)") 212 _ = cmd.MarkFlagRequired(auth.FlagQuery) 213 214 return cmd 215 } 216 217 // QueryBlockCmd implements the default command for a Block query. 218 func QueryBlockCmd() *cobra.Command { 219 cmd := &cobra.Command{ 220 Use: "block --type=[height|hash] [height|hash]", 221 Short: "Query for a committed block by height, hash, or event(s)", 222 Long: "Query for a specific committed block using the CometBFT RPC `block` and `block_by_hash` method", 223 Example: strings.TrimSpace(fmt.Sprintf(` 224 $ %s query block --%s=%s <height> 225 $ %s query block --%s=%s <hash> 226 `, 227 version.AppName, auth.FlagType, auth.TypeHeight, 228 version.AppName, auth.FlagType, auth.TypeHash)), 229 Args: cobra.MaximumNArgs(1), 230 RunE: func(cmd *cobra.Command, args []string) error { 231 clientCtx, err := client.GetClientQueryContext(cmd) 232 if err != nil { 233 return err 234 } 235 236 typ, _ := cmd.Flags().GetString(auth.FlagType) 237 if len(args) == 0 { 238 // do not break default v0.50 behavior of block hash 239 // if no args are provided, set the type to height 240 typ = auth.TypeHeight 241 } 242 243 switch typ { 244 case auth.TypeHeight: 245 var ( 246 err error 247 height int64 248 ) 249 heightStr := "" 250 if len(args) > 0 { 251 heightStr = args[0] 252 } 253 254 if heightStr == "" { 255 cmd.Println("Falling back to latest block height:") 256 height, err = rpc.GetChainHeight(clientCtx) 257 if err != nil { 258 return fmt.Errorf("failed to get chain height: %w", err) 259 } 260 } else { 261 height, err = strconv.ParseInt(heightStr, 10, 64) 262 if err != nil { 263 return fmt.Errorf("failed to parse block height: %w", err) 264 } 265 } 266 267 output, err := rpc.GetBlockByHeight(clientCtx, &height) 268 if err != nil { 269 return err 270 } 271 272 if output.Header.Height == 0 { 273 return fmt.Errorf("no block found with height %s", args[0]) 274 } 275 276 return clientCtx.PrintProto(output) 277 278 case auth.TypeHash: 279 280 if args[0] == "" { 281 return fmt.Errorf("argument should be a tx hash") 282 } 283 284 // If hash is given, then query the tx by hash. 285 output, err := rpc.GetBlockByHash(clientCtx, args[0]) 286 if err != nil { 287 return err 288 } 289 290 if output.Header.AppHash == nil { 291 return fmt.Errorf("no block found with hash %s", args[0]) 292 } 293 294 return clientCtx.PrintProto(output) 295 296 default: 297 return fmt.Errorf("unknown --%s value %s", auth.FlagType, typ) 298 } 299 }, 300 } 301 302 flags.AddQueryFlagsToCmd(cmd) 303 cmd.Flags().String(auth.FlagType, auth.TypeHash, fmt.Sprintf("The type to be used when querying tx, can be one of \"%s\", \"%s\"", auth.TypeHeight, auth.TypeHash)) 304 305 return cmd 306 } 307 308 // QueryBlockResultsCmd implements the default command for a BlockResults query. 309 func QueryBlockResultsCmd() *cobra.Command { 310 cmd := &cobra.Command{ 311 Use: "block-results [height]", 312 Short: "Query for a committed block's results by height", 313 Long: "Query for a specific committed block's results using the CometBFT RPC `block_results` method", 314 Args: cobra.RangeArgs(0, 1), 315 RunE: func(cmd *cobra.Command, args []string) error { 316 clientCtx, err := client.GetClientQueryContext(cmd) 317 if err != nil { 318 return err 319 } 320 321 node, err := clientCtx.GetNode() 322 if err != nil { 323 return err 324 } 325 326 // optional height 327 var height int64 328 if len(args) > 0 { 329 height, err = strconv.ParseInt(args[0], 10, 64) 330 if err != nil { 331 return err 332 } 333 } else { 334 cmd.Println("Falling back to latest block height:") 335 height, err = rpc.GetChainHeight(clientCtx) 336 if err != nil { 337 return fmt.Errorf("failed to get chain height: %w", err) 338 } 339 } 340 341 blockRes, err := node.BlockResults(context.Background(), &height) 342 if err != nil { 343 return err 344 } 345 346 // coretypes.ResultBlockResults doesn't implement proto.Message interface 347 // so we can't print it using clientCtx.PrintProto 348 // we choose to serialize it to json and print the json instead 349 blockResStr, err := json.Marshal(blockRes) 350 if err != nil { 351 return err 352 } 353 354 return clientCtx.PrintRaw(blockResStr) 355 }, 356 } 357 358 flags.AddQueryFlagsToCmd(cmd) 359 360 return cmd 361 } 362 363 func BootstrapStateCmd(appCreator types.AppCreator) *cobra.Command { 364 cmd := &cobra.Command{ 365 Use: "bootstrap-state", 366 Short: "Bootstrap CometBFT state at an arbitrary block height using a light client", 367 Args: cobra.NoArgs, 368 RunE: func(cmd *cobra.Command, args []string) error { 369 serverCtx := GetServerContextFromCmd(cmd) 370 logger := log.NewLogger(cmd.OutOrStdout()) 371 cfg := serverCtx.Config 372 373 height, err := cmd.Flags().GetInt64("height") 374 if err != nil { 375 return err 376 } 377 if height == 0 { 378 home := serverCtx.Viper.GetString(flags.FlagHome) 379 db, err := openDB(home, GetAppDBBackend(serverCtx.Viper)) 380 if err != nil { 381 return err 382 } 383 384 app := appCreator(logger, db, nil, serverCtx.Viper) 385 height = app.CommitMultiStore().LastCommitID().Version 386 } 387 388 return node.BootstrapStateWithGenProvider(cmd.Context(), cfg, cmtcfg.DefaultDBProvider, getGenDocProvider(cfg), uint64(height), nil) 389 }, 390 } 391 392 cmd.Flags().Int64("height", 0, "Block height to bootstrap state at, if not provided it uses the latest block height in app state") 393 394 return cmd 395 }