github.com/line/ostracon@v1.0.10-0.20230328032236-7f20145f065d/abci/cmd/abci-cli/abci-cli.go (about) 1 package main 2 3 import ( 4 "bufio" 5 "bytes" 6 "encoding/hex" 7 "errors" 8 "fmt" 9 "io" 10 "os" 11 "path/filepath" 12 "strings" 13 14 "github.com/spf13/cobra" 15 16 "github.com/tendermint/tendermint/abci/types" 17 "github.com/tendermint/tendermint/proto/tendermint/crypto" 18 19 abcicli "github.com/line/ostracon/abci/client" 20 "github.com/line/ostracon/abci/example/code" 21 "github.com/line/ostracon/abci/example/counter" 22 "github.com/line/ostracon/abci/example/kvstore" 23 "github.com/line/ostracon/abci/server" 24 servertest "github.com/line/ostracon/abci/tests/server" 25 ocabci "github.com/line/ostracon/abci/types" 26 "github.com/line/ostracon/abci/version" 27 "github.com/line/ostracon/config" 28 "github.com/line/ostracon/crypto/encoding" 29 "github.com/line/ostracon/libs/log" 30 tmos "github.com/line/ostracon/libs/os" 31 ) 32 33 // client is a global variable so it can be reused by the console 34 var ( 35 client abcicli.Client 36 logger log.Logger 37 ) 38 39 // flags 40 var ( 41 // global 42 flagAddress string 43 flagAbci string 44 flagVerbose bool // for the println output 45 flagLogLevel string // for the logger 46 47 // query 48 flagPath string 49 flagHeight int 50 flagProve bool 51 52 // counter 53 flagSerial bool 54 55 // kvstore 56 flagPersist string 57 58 // voting power for make validator_tx 59 flagVotingPower int64 60 ) 61 62 var RootCmd = &cobra.Command{ 63 Use: "abci-cli", 64 Short: "the ABCI CLI tool wraps an ABCI client", 65 Long: "the ABCI CLI tool wraps an ABCI client and is used for testing ABCI servers", 66 PersistentPreRunE: func(cmd *cobra.Command, args []string) error { 67 68 switch cmd.Use { 69 case "counter", "kvstore": // for the examples apps, don't pre-run 70 return nil 71 case "version": // skip running for version command 72 return nil 73 } 74 75 if logger == nil { 76 allowLevel, err := log.AllowLevel(flagLogLevel) 77 if err != nil { 78 return err 79 } 80 logger = log.NewFilter(log.NewOCLogger(log.NewSyncWriter(os.Stdout)), allowLevel) 81 } 82 if client == nil { 83 var err error 84 client, err = abcicli.NewClient(flagAddress, flagAbci, false) 85 if err != nil { 86 return err 87 } 88 client.SetLogger(logger.With("module", "abci-client")) 89 if err := client.Start(); err != nil { 90 return err 91 } 92 } 93 return nil 94 }, 95 } 96 97 // Structure for data passed to print response. 98 type response struct { 99 // generic abci response 100 Data []byte 101 Code uint32 102 Info string 103 Log string 104 105 Query *queryResponse 106 } 107 108 type queryResponse struct { 109 Key []byte 110 Value []byte 111 Height int64 112 ProofOps *crypto.ProofOps 113 } 114 115 func Execute() error { 116 addGlobalFlags() 117 addCommands() 118 return RootCmd.Execute() 119 } 120 121 func addGlobalFlags() { 122 RootCmd.PersistentFlags().StringVarP(&flagAddress, 123 "address", 124 "", 125 "tcp://0.0.0.0:26658", 126 "address of application socket") 127 RootCmd.PersistentFlags().StringVarP(&flagAbci, "abci", "", "socket", "either socket or grpc") 128 RootCmd.PersistentFlags().BoolVarP(&flagVerbose, 129 "verbose", 130 "v", 131 false, 132 "print the command and results as if it were a console session") 133 RootCmd.PersistentFlags().StringVarP(&flagLogLevel, "log_level", "", "debug", "set the logger level") 134 } 135 136 func addQueryFlags() { 137 queryCmd.PersistentFlags().StringVarP(&flagPath, "path", "", "/store", "path to prefix query with") 138 queryCmd.PersistentFlags().IntVarP(&flagHeight, "height", "", 0, "height to query the blockchain at") 139 queryCmd.PersistentFlags().BoolVarP(&flagProve, 140 "prove", 141 "", 142 false, 143 "whether or not to return a merkle proof of the query result") 144 } 145 146 func addCounterFlags() { 147 counterCmd.PersistentFlags().BoolVarP(&flagSerial, "serial", "", false, 148 "enforce incrementing (serial) transactions") 149 } 150 151 func addKVStoreFlags() { 152 kvstoreCmd.PersistentFlags().StringVarP(&flagPersist, "persist", "", "", 153 "directory to use for a database") 154 } 155 156 func addPersistKVStoreMakeValSetChangeTxFlags() { 157 kvstoreCmd.PersistentFlags().Int64VarP(&flagVotingPower, "voting_power", "p", int64(10), 158 "voting power for ValSetChangeTx") 159 } 160 161 func addCommands() { 162 RootCmd.AddCommand(batchCmd) 163 RootCmd.AddCommand(consoleCmd) 164 RootCmd.AddCommand(echoCmd) 165 RootCmd.AddCommand(infoCmd) 166 RootCmd.AddCommand(setOptionCmd) 167 RootCmd.AddCommand(deliverTxCmd) 168 RootCmd.AddCommand(checkTxCmd) 169 RootCmd.AddCommand(commitCmd) 170 RootCmd.AddCommand(versionCmd) 171 RootCmd.AddCommand(testCmd) 172 addQueryFlags() 173 RootCmd.AddCommand(queryCmd) 174 175 // examples 176 addCounterFlags() 177 RootCmd.AddCommand(counterCmd) 178 addKVStoreFlags() 179 RootCmd.AddCommand(kvstoreCmd) 180 181 // for examples of persist_kvstore 182 addPersistKVStoreMakeValSetChangeTxFlags() 183 RootCmd.AddCommand(persistKvstoreMakeValSetChangeTxCmd) 184 } 185 186 var batchCmd = &cobra.Command{ 187 Use: "batch", 188 Short: "run a batch of abci commands against an application", 189 Long: `run a batch of abci commands against an application 190 191 This command is run by piping in a file containing a series of commands 192 you'd like to run: 193 194 abci-cli batch < example.file 195 196 where example.file looks something like: 197 198 set_option serial on 199 check_tx 0x00 200 check_tx 0xff 201 deliver_tx 0x00 202 check_tx 0x00 203 deliver_tx 0x01 204 deliver_tx 0x04 205 info 206 `, 207 Args: cobra.ExactArgs(0), 208 RunE: cmdBatch, 209 } 210 211 var consoleCmd = &cobra.Command{ 212 Use: "console", 213 Short: "start an interactive ABCI console for multiple commands", 214 Long: `start an interactive ABCI console for multiple commands 215 216 This command opens an interactive console for running any of the other commands 217 without opening a new connection each time 218 `, 219 Args: cobra.ExactArgs(0), 220 ValidArgs: []string{"echo", "info", "set_option", "deliver_tx", "check_tx", "commit", "query"}, 221 RunE: cmdConsole, 222 } 223 224 var echoCmd = &cobra.Command{ 225 Use: "echo", 226 Short: "have the application echo a message", 227 Long: "have the application echo a message", 228 Args: cobra.ExactArgs(1), 229 RunE: cmdEcho, 230 } 231 var infoCmd = &cobra.Command{ 232 Use: "info", 233 Short: "get some info about the application", 234 Long: "get some info about the application", 235 Args: cobra.ExactArgs(0), 236 RunE: cmdInfo, 237 } 238 var setOptionCmd = &cobra.Command{ 239 Use: "set_option", 240 Short: "set an option on the application", 241 Long: "set an option on the application", 242 Args: cobra.ExactArgs(2), 243 RunE: cmdSetOption, 244 } 245 246 var deliverTxCmd = &cobra.Command{ 247 Use: "deliver_tx", 248 Short: "deliver a new transaction to the application", 249 Long: "deliver a new transaction to the application", 250 Args: cobra.ExactArgs(1), 251 RunE: cmdDeliverTx, 252 } 253 254 var checkTxCmd = &cobra.Command{ 255 Use: "check_tx", 256 Short: "validate a transaction", 257 Long: "validate a transaction", 258 Args: cobra.ExactArgs(1), 259 RunE: cmdCheckTx, 260 } 261 262 var commitCmd = &cobra.Command{ 263 Use: "commit", 264 Short: "commit the application state and return the Merkle root hash", 265 Long: "commit the application state and return the Merkle root hash", 266 Args: cobra.ExactArgs(0), 267 RunE: cmdCommit, 268 } 269 270 var versionCmd = &cobra.Command{ 271 Use: "version", 272 Short: "print ABCI console version", 273 Long: "print ABCI console version", 274 Args: cobra.ExactArgs(0), 275 RunE: func(cmd *cobra.Command, args []string) error { 276 fmt.Println(version.Version) 277 return nil 278 }, 279 } 280 281 var queryCmd = &cobra.Command{ 282 Use: "query", 283 Short: "query the application state", 284 Long: "query the application state", 285 Args: cobra.ExactArgs(1), 286 RunE: cmdQuery, 287 } 288 289 var counterCmd = &cobra.Command{ 290 Use: "counter", 291 Short: "ABCI demo example - counter", 292 Long: "ABCI demo example - counter", 293 Args: cobra.ExactArgs(0), 294 RunE: cmdCounter, 295 } 296 297 var kvstoreCmd = &cobra.Command{ 298 Use: "kvstore", 299 Short: "ABCI demo example - kvstore", 300 Long: "ABCI demo example - kvstore", 301 Args: cobra.ExactArgs(0), 302 RunE: cmdKVStore, 303 } 304 305 var persistKvstoreMakeValSetChangeTxCmd = &cobra.Command{ 306 Use: "valset_change_tx", 307 Short: "persist_kvstore - make ValSetChangeTx", 308 Long: "persist_kvstore - make ValSetChangeTx", 309 Args: cobra.ExactArgs(0), 310 RunE: cmdPersistKVStoreMakeValSetChangeTx, 311 } 312 313 var testCmd = &cobra.Command{ 314 Use: "test", 315 Short: "run integration tests", 316 Long: "run integration tests", 317 Args: cobra.ExactArgs(0), 318 RunE: cmdTest, 319 } 320 321 // Generates new Args array based off of previous call args to maintain flag persistence 322 func persistentArgs(line []byte) []string { 323 324 // generate the arguments to run from original os.Args 325 // to maintain flag arguments 326 args := os.Args 327 args = args[:len(args)-1] // remove the previous command argument 328 329 if len(line) > 0 { // prevents introduction of extra space leading to argument parse errors 330 args = append(args, strings.Split(string(line), " ")...) 331 } 332 return args 333 } 334 335 //-------------------------------------------------------------------------------- 336 337 func compose(fs []func() error) error { 338 if len(fs) == 0 { 339 return nil 340 } 341 342 err := fs[0]() 343 if err == nil { 344 return compose(fs[1:]) 345 } 346 347 return err 348 } 349 350 func cmdTest(cmd *cobra.Command, args []string) error { 351 return compose( 352 []func() error{ 353 func() error { return servertest.InitChain(client) }, 354 func() error { return servertest.SetOption(client, "serial", "on") }, 355 func() error { return servertest.Commit(client, nil) }, 356 func() error { return servertest.DeliverTx(client, []byte("abc"), code.CodeTypeBadNonce, nil) }, 357 func() error { return servertest.Commit(client, nil) }, 358 func() error { return servertest.DeliverTx(client, []byte{0x00}, code.CodeTypeOK, nil) }, 359 func() error { return servertest.Commit(client, []byte{0, 0, 0, 0, 0, 0, 0, 1}) }, 360 func() error { return servertest.DeliverTx(client, []byte{0x00}, code.CodeTypeBadNonce, nil) }, 361 func() error { return servertest.DeliverTx(client, []byte{0x01}, code.CodeTypeOK, nil) }, 362 func() error { return servertest.DeliverTx(client, []byte{0x00, 0x02}, code.CodeTypeOK, nil) }, 363 func() error { return servertest.DeliverTx(client, []byte{0x00, 0x03}, code.CodeTypeOK, nil) }, 364 func() error { return servertest.DeliverTx(client, []byte{0x00, 0x00, 0x04}, code.CodeTypeOK, nil) }, 365 func() error { 366 return servertest.DeliverTx(client, []byte{0x00, 0x00, 0x06}, code.CodeTypeBadNonce, nil) 367 }, 368 func() error { return servertest.Commit(client, []byte{0, 0, 0, 0, 0, 0, 0, 5}) }, 369 }) 370 } 371 372 func cmdBatch(cmd *cobra.Command, args []string) error { 373 bufReader := bufio.NewReader(os.Stdin) 374 LOOP: 375 for { 376 377 line, more, err := bufReader.ReadLine() 378 switch { 379 case more: 380 return errors.New("input line is too long") 381 case err == io.EOF: 382 break LOOP 383 case len(line) == 0: 384 continue 385 case err != nil: 386 return err 387 } 388 389 cmdArgs := persistentArgs(line) 390 if err := muxOnCommands(cmd, cmdArgs); err != nil { 391 return err 392 } 393 fmt.Println() 394 } 395 return nil 396 } 397 398 func cmdConsole(cmd *cobra.Command, args []string) error { 399 for { 400 fmt.Printf("> ") 401 bufReader := bufio.NewReader(os.Stdin) 402 line, more, err := bufReader.ReadLine() 403 if more { 404 return errors.New("input is too long") 405 } else if err != nil { 406 return err 407 } 408 409 pArgs := persistentArgs(line) 410 if err := muxOnCommands(cmd, pArgs); err != nil { 411 return err 412 } 413 } 414 } 415 416 func muxOnCommands(cmd *cobra.Command, pArgs []string) error { 417 if len(pArgs) < 2 { 418 return errors.New("expecting persistent args of the form: abci-cli [command] <...>") 419 } 420 421 // TODO: this parsing is fragile 422 args := []string{} 423 for i := 0; i < len(pArgs); i++ { 424 arg := pArgs[i] 425 426 // check for flags 427 if strings.HasPrefix(arg, "-") { 428 // if it has an equal, we can just skip 429 if strings.Contains(arg, "=") { 430 continue 431 } 432 // if its a boolean, we can just skip 433 _, err := cmd.Flags().GetBool(strings.TrimLeft(arg, "-")) 434 if err == nil { 435 continue 436 } 437 438 // otherwise, we need to skip the next one too 439 i++ 440 continue 441 } 442 443 // append the actual arg 444 args = append(args, arg) 445 } 446 var subCommand string 447 var actualArgs []string 448 if len(args) > 1 { 449 subCommand = args[1] 450 } 451 if len(args) > 2 { 452 actualArgs = args[2:] 453 } 454 cmd.Use = subCommand // for later print statements ... 455 456 switch strings.ToLower(subCommand) { 457 case "check_tx": 458 return cmdCheckTx(cmd, actualArgs) 459 case "commit": 460 return cmdCommit(cmd, actualArgs) 461 case "deliver_tx": 462 return cmdDeliverTx(cmd, actualArgs) 463 case "echo": 464 return cmdEcho(cmd, actualArgs) 465 case "info": 466 return cmdInfo(cmd, actualArgs) 467 case "query": 468 return cmdQuery(cmd, actualArgs) 469 case "set_option": 470 return cmdSetOption(cmd, actualArgs) 471 default: 472 return cmdUnimplemented(cmd, pArgs) 473 } 474 } 475 476 func cmdUnimplemented(cmd *cobra.Command, args []string) error { 477 msg := "unimplemented command" 478 479 if len(args) > 0 { 480 msg += fmt.Sprintf(" args: [%s]", strings.Join(args, " ")) 481 } 482 printResponse(cmd, args, response{ 483 Code: codeBad, 484 Log: msg, 485 }) 486 487 fmt.Println("Available commands:") 488 fmt.Printf("%s: %s\n", echoCmd.Use, echoCmd.Short) 489 fmt.Printf("%s: %s\n", infoCmd.Use, infoCmd.Short) 490 fmt.Printf("%s: %s\n", checkTxCmd.Use, checkTxCmd.Short) 491 fmt.Printf("%s: %s\n", deliverTxCmd.Use, deliverTxCmd.Short) 492 fmt.Printf("%s: %s\n", queryCmd.Use, queryCmd.Short) 493 fmt.Printf("%s: %s\n", commitCmd.Use, commitCmd.Short) 494 fmt.Printf("%s: %s\n", setOptionCmd.Use, setOptionCmd.Short) 495 fmt.Println("Use \"[command] --help\" for more information about a command.") 496 497 return nil 498 } 499 500 // Have the application echo a message 501 func cmdEcho(cmd *cobra.Command, args []string) error { 502 msg := "" 503 if len(args) > 0 { 504 msg = args[0] 505 } 506 res, err := client.EchoSync(msg) 507 if err != nil { 508 return err 509 } 510 printResponse(cmd, args, response{ 511 Data: []byte(res.Message), 512 }) 513 return nil 514 } 515 516 // Get some info from the application 517 func cmdInfo(cmd *cobra.Command, args []string) error { 518 var version string 519 if len(args) == 1 { 520 version = args[0] 521 } 522 res, err := client.InfoSync(types.RequestInfo{Version: version}) 523 if err != nil { 524 return err 525 } 526 printResponse(cmd, args, response{ 527 Data: []byte(res.Data), 528 }) 529 return nil 530 } 531 532 const codeBad uint32 = 10 533 534 // Set an option on the application 535 func cmdSetOption(cmd *cobra.Command, args []string) error { 536 if len(args) < 2 { 537 printResponse(cmd, args, response{ 538 Code: codeBad, 539 Log: "want at least arguments of the form: <key> <value>", 540 }) 541 return nil 542 } 543 544 key, val := args[0], args[1] 545 _, err := client.SetOptionSync(types.RequestSetOption{Key: key, Value: val}) 546 if err != nil { 547 return err 548 } 549 printResponse(cmd, args, response{Log: "OK (SetOption doesn't return anything.)"}) // NOTE: Nothing to show... 550 return nil 551 } 552 553 // Append a new tx to application 554 func cmdDeliverTx(cmd *cobra.Command, args []string) error { 555 if len(args) == 0 { 556 printResponse(cmd, args, response{ 557 Code: codeBad, 558 Log: "want the tx", 559 }) 560 return nil 561 } 562 txBytes, err := stringOrHexToBytes(args[0]) 563 if err != nil { 564 return err 565 } 566 res, err := client.DeliverTxSync(types.RequestDeliverTx{Tx: txBytes}) 567 if err != nil { 568 return err 569 } 570 printResponse(cmd, args, response{ 571 Code: res.Code, 572 Data: res.Data, 573 Info: res.Info, 574 Log: res.Log, 575 }) 576 return nil 577 } 578 579 // Validate a tx 580 func cmdCheckTx(cmd *cobra.Command, args []string) error { 581 if len(args) == 0 { 582 printResponse(cmd, args, response{ 583 Code: codeBad, 584 Info: "want the tx", 585 }) 586 return nil 587 } 588 txBytes, err := stringOrHexToBytes(args[0]) 589 if err != nil { 590 return err 591 } 592 res, err := client.CheckTxSync(types.RequestCheckTx{Tx: txBytes}) 593 if err != nil { 594 return err 595 } 596 printResponse(cmd, args, response{ 597 Code: res.Code, 598 Data: res.Data, 599 Info: res.Info, 600 Log: res.Log, 601 }) 602 return nil 603 } 604 605 // Get application Merkle root hash 606 func cmdCommit(cmd *cobra.Command, args []string) error { 607 res, err := client.CommitSync() 608 if err != nil { 609 return err 610 } 611 printResponse(cmd, args, response{ 612 Data: res.Data, 613 }) 614 return nil 615 } 616 617 // Query application state 618 func cmdQuery(cmd *cobra.Command, args []string) error { 619 if len(args) == 0 { 620 printResponse(cmd, args, response{ 621 Code: codeBad, 622 Info: "want the query", 623 Log: "", 624 }) 625 return nil 626 } 627 queryBytes, err := stringOrHexToBytes(args[0]) 628 if err != nil { 629 return err 630 } 631 632 resQuery, err := client.QuerySync(types.RequestQuery{ 633 Data: queryBytes, 634 Path: flagPath, 635 Height: int64(flagHeight), 636 Prove: flagProve, 637 }) 638 if err != nil { 639 return err 640 } 641 printResponse(cmd, args, response{ 642 Code: resQuery.Code, 643 Info: resQuery.Info, 644 Log: resQuery.Log, 645 Query: &queryResponse{ 646 Key: resQuery.Key, 647 Value: resQuery.Value, 648 Height: resQuery.Height, 649 ProofOps: resQuery.ProofOps, 650 }, 651 }) 652 return nil 653 } 654 655 func cmdCounter(cmd *cobra.Command, args []string) error { 656 app := counter.NewApplication(flagSerial) 657 logger := log.NewOCLogger(log.NewSyncWriter(os.Stdout)) 658 659 // Start the listener 660 srv, err := server.NewServer(flagAddress, flagAbci, app) 661 if err != nil { 662 return err 663 } 664 srv.SetLogger(logger.With("module", "abci-server")) 665 if err := srv.Start(); err != nil { 666 return err 667 } 668 669 // Stop upon receiving SIGTERM or CTRL-C. 670 tmos.TrapSignal(logger, func() { 671 // Cleanup 672 if err := srv.Stop(); err != nil { 673 logger.Error("Error while stopping server", "err", err) 674 } 675 }) 676 677 // Run forever. 678 select {} 679 } 680 681 func cmdKVStore(cmd *cobra.Command, args []string) error { 682 logger := log.NewOCLogger(log.NewSyncWriter(os.Stdout)) 683 684 // Create the application - in memory or persisted to disk 685 var app ocabci.Application 686 if flagPersist == "" { 687 app = kvstore.NewApplication() 688 } else { 689 app = kvstore.NewPersistentKVStoreApplication(flagPersist) 690 app.(*kvstore.PersistentKVStoreApplication).SetLogger(logger.With("module", "kvstore")) 691 } 692 693 // Start the listener 694 srv, err := server.NewServer(flagAddress, flagAbci, app) 695 if err != nil { 696 return err 697 } 698 srv.SetLogger(logger.With("module", "abci-server")) 699 if err := srv.Start(); err != nil { 700 return err 701 } 702 703 // Stop upon receiving SIGTERM or CTRL-C. 704 tmos.TrapSignal(logger, func() { 705 // Cleanup 706 if err := srv.Stop(); err != nil { 707 logger.Error("Error while stopping server", "err", err) 708 } 709 }) 710 711 // Run forever. 712 select {} 713 } 714 715 func cmdPersistKVStoreMakeValSetChangeTx(cmd *cobra.Command, args []string) error { 716 c := config.DefaultConfig() 717 userHome, err := os.UserHomeDir() 718 if err != nil { 719 panic(err) 720 } 721 c.SetRoot(filepath.Join(userHome, config.DefaultOstraconDir)) 722 keyFilePath := c.PrivValidatorKeyFile() 723 if !tmos.FileExists(keyFilePath) { 724 return fmt.Errorf("private validator file %s does not exist", keyFilePath) 725 } 726 keyFile, err := kvstore.LoadPrivValidatorKeyFile(keyFilePath) 727 if err != nil { 728 panic(err) 729 } 730 publicKey, err := encoding.PubKeyToProto(keyFile.PubKey) 731 if err != nil { 732 panic(err) 733 } 734 pubStr, tx := kvstore.MakeValSetChangeTxAndMore(publicKey, flagVotingPower) 735 { 736 fmt.Printf("DeliverTxSync: data=%s, tx=%s\n", pubStr, tx) 737 res, err := client.DeliverTxSync(types.RequestDeliverTx{Tx: []byte(tx)}) 738 if err != nil { 739 return err 740 } 741 printResponse(cmd, args, response{ 742 Code: res.Code, 743 Data: res.Data, 744 Info: res.Info, 745 Log: res.Log, 746 }) 747 } 748 { 749 fmt.Printf("QuerySync: data=%s\n", pubStr) 750 res, err := client.QuerySync(types.RequestQuery{Path: "/val", Data: []byte(pubStr)}) 751 if err != nil { 752 return err 753 } 754 printResponse(cmd, args, response{ 755 Code: res.Code, 756 Info: res.Info, 757 Log: res.Log, 758 }) 759 fmt.Printf("original:publicKey:%s\n", publicKey) 760 validatorUpdate := types.ValidatorUpdate{} 761 err = ocabci.ReadMessage(bytes.NewReader(res.Value), &validatorUpdate) 762 if err != nil { 763 panic(err) 764 } 765 fmt.Printf("saved :publicKey:%s\n", validatorUpdate.PubKey) 766 } 767 return nil 768 } 769 770 //-------------------------------------------------------------------------------- 771 772 func printResponse(cmd *cobra.Command, args []string, rsp response) { 773 774 if flagVerbose { 775 fmt.Println(">", cmd.Use, strings.Join(args, " ")) 776 } 777 778 // Always print the status code. 779 if rsp.Code == ocabci.CodeTypeOK { 780 fmt.Printf("-> code: OK\n") 781 } else { 782 fmt.Printf("-> code: %d\n", rsp.Code) 783 784 } 785 786 if len(rsp.Data) != 0 { 787 // Do not print this line when using the commit command 788 // because the string comes out as gibberish 789 if cmd.Use != "commit" { 790 fmt.Printf("-> data: %s\n", rsp.Data) 791 } 792 fmt.Printf("-> data.hex: 0x%X\n", rsp.Data) 793 } 794 if rsp.Log != "" { 795 fmt.Printf("-> log: %s\n", rsp.Log) 796 } 797 798 if rsp.Query != nil { 799 fmt.Printf("-> height: %d\n", rsp.Query.Height) 800 if rsp.Query.Key != nil { 801 fmt.Printf("-> key: %s\n", rsp.Query.Key) 802 fmt.Printf("-> key.hex: %X\n", rsp.Query.Key) 803 } 804 if rsp.Query.Value != nil { 805 fmt.Printf("-> value: %s\n", rsp.Query.Value) 806 fmt.Printf("-> value.hex: %X\n", rsp.Query.Value) 807 } 808 if rsp.Query.ProofOps != nil { 809 fmt.Printf("-> proof: %#v\n", rsp.Query.ProofOps) 810 } 811 } 812 } 813 814 // NOTE: s is interpreted as a string unless prefixed with 0x 815 func stringOrHexToBytes(s string) ([]byte, error) { 816 if len(s) > 2 && strings.ToLower(s[:2]) == "0x" { 817 b, err := hex.DecodeString(s[2:]) 818 if err != nil { 819 err = fmt.Errorf("error decoding hex argument: %s", err.Error()) 820 return nil, err 821 } 822 return b, nil 823 } 824 825 if !strings.HasPrefix(s, "\"") || !strings.HasSuffix(s, "\"") { 826 err := fmt.Errorf("invalid string arg: \"%s\". Must be quoted or a \"0x\"-prefixed hex string", s) 827 return nil, err 828 } 829 830 return []byte(s[1 : len(s)-1]), nil 831 }