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  }