github.com/evdatsion/aphelion-dpos-bft@v0.32.1/abci/cmd/abci-cli/abci-cli.go (about)

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