13 abcicli "github.com/tendermint/abci/client"
14 "github.com/tendermint/abci/example/counter"
15 "github.com/tendermint/abci/example/dummy"
16 "github.com/tendermint/abci/server"
17 "github.com/tendermint/abci/types"
18 cmn "github.com/tendermint/tmlibs/common"
19 "github.com/tendermint/tmlibs/log"
21 "github.com/spf13/cobra"
24 // Structure for data passed to print response.
25 type response struct {
26 // generic abci response
34 type queryResponse struct {
41 // client is a global variable so it can be reused by the console
42 var client abcicli.Client
67 var RootCmd = &cobra.Command{
71 PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
74 // for the examples apps, don't pre-run
75 case "counter", "dummy":
80 logger = log.NewFilter(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), log.AllowError())
84 client, err = abcicli.NewClient(address, abci, false)
88 client.SetLogger(logger.With("module", "abci-client"))
89 if _, err := client.Start(); err != nil {
103 func addGlobalFlags() {
104 RootCmd.PersistentFlags().StringVarP(&address, "address", "", "tcp://127.0.0.1:46658", "Address of application socket")
105 RootCmd.PersistentFlags().StringVarP(&abci, "abci", "", "socket", "Either socket or grpc")
106 RootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Print the command and results as if it were a console session")
109 func addQueryFlags() {
110 queryCmd.PersistentFlags().StringVarP(&path, "path", "", "/store", "Path to prefix query with")
111 queryCmd.PersistentFlags().IntVarP(&height, "height", "", 0, "Height to query the blockchain at")
112 queryCmd.PersistentFlags().BoolVarP(&prove, "prove", "", false, "Whether or not to return a merkle proof of the query result")
115 func addCounterFlags() {
116 counterCmd.PersistentFlags().StringVarP(&addrC, "addr", "", "tcp://0.0.0.0:46658", "Listen address")
117 counterCmd.PersistentFlags().BoolVarP(&serial, "serial", "", false, "Enforce incrementing (serial) transactions")
120 func addDummyFlags() {
121 dummyCmd.PersistentFlags().StringVarP(&addrD, "addr", "", "tcp://0.0.0.0:46658", "Listen address")
122 dummyCmd.PersistentFlags().StringVarP(&persist, "persist", "", "", "Directory to use for a database")
125 RootCmd.AddCommand(batchCmd)
126 RootCmd.AddCommand(consoleCmd)
127 RootCmd.AddCommand(echoCmd)
128 RootCmd.AddCommand(infoCmd)
129 RootCmd.AddCommand(setOptionCmd)
130 RootCmd.AddCommand(deliverTxCmd)
131 RootCmd.AddCommand(checkTxCmd)
132 RootCmd.AddCommand(commitCmd)
134 RootCmd.AddCommand(queryCmd)
138 RootCmd.AddCommand(counterCmd)
140 RootCmd.AddCommand(dummyCmd)
143 var batchCmd = &cobra.Command{
145 Short: "Run a batch of abci commands against an application",
147 Args: cobra.ExactArgs(0),
148 RunE: func(cmd *cobra.Command, args []string) error {
149 return cmdBatch(cmd, args)
153 var consoleCmd = &cobra.Command{
155 Short: "Start an interactive abci console for multiple commands",
157 Args: cobra.ExactArgs(0),
158 ValidArgs: []string{"batch", "echo", "info", "set_option", "deliver_tx", "check_tx", "commit", "query"},
159 RunE: func(cmd *cobra.Command, args []string) error {
160 return cmdConsole(cmd, args)
164 var echoCmd = &cobra.Command{
166 Short: "Have the application echo a message",
168 Args: cobra.ExactArgs(1),
169 RunE: func(cmd *cobra.Command, args []string) error {
170 return cmdEcho(cmd, args)
173 var infoCmd = &cobra.Command{
175 Short: "Get some info about the application",
177 Args: cobra.ExactArgs(0),
178 RunE: func(cmd *cobra.Command, args []string) error {
179 return cmdInfo(cmd, args)
182 var setOptionCmd = &cobra.Command{
184 Short: "Set an option on the application",
186 Args: cobra.ExactArgs(2),
187 RunE: func(cmd *cobra.Command, args []string) error {
188 return cmdSetOption(cmd, args)
192 var deliverTxCmd = &cobra.Command{
194 Short: "Deliver a new transaction to the application",
196 Args: cobra.ExactArgs(1),
197 RunE: func(cmd *cobra.Command, args []string) error {
198 return cmdDeliverTx(cmd, args)
202 var checkTxCmd = &cobra.Command{
204 Short: "Validate a transaction",
206 Args: cobra.ExactArgs(1),
207 RunE: func(cmd *cobra.Command, args []string) error {
208 return cmdCheckTx(cmd, args)
212 var commitCmd = &cobra.Command{
214 Short: "Commit the application state and return the Merkle root hash",
216 Args: cobra.ExactArgs(0),
217 RunE: func(cmd *cobra.Command, args []string) error {
218 return cmdCommit(cmd, args)
222 var queryCmd = &cobra.Command{
224 Short: "Query the application state",
226 Args: cobra.ExactArgs(1),
227 RunE: func(cmd *cobra.Command, args []string) error {
228 return cmdQuery(cmd, args)
232 var counterCmd = &cobra.Command{
234 Short: "ABCI demo example",
236 Args: cobra.ExactArgs(0),
237 RunE: func(cmd *cobra.Command, args []string) error {
238 return cmdCounter(cmd, args)
242 var dummyCmd = &cobra.Command{
244 Short: "ABCI demo example",
246 Args: cobra.ExactArgs(0),
247 RunE: func(cmd *cobra.Command, args []string) error {
248 return cmdDummy(cmd, args)
252 // Generates new Args array based off of previous call args to maintain flag persistence
253 func persistentArgs(line []byte) []string {
255 // generate the arguments to run from original os.Args
256 // to maintain flag arguments
258 args = args[:len(args)-1] // remove the previous command argument
260 if len(line) > 0 { // prevents introduction of extra space leading to argument parse errors
261 args = append(args, strings.Split(string(line), " ")...)
266 //--------------------------------------------------------------------------------
268 func cmdBatch(cmd *cobra.Command, args []string) error {
269 bufReader := bufio.NewReader(os.Stdin)
271 line, more, err := bufReader.ReadLine()
273 return errors.New("Input line is too long")
274 } else if err == io.EOF {
276 } else if len(line) == 0 {
278 } else if err != nil {
282 pArgs := persistentArgs(line)
283 out, err := exec.Command(pArgs[0], pArgs[1:]...).Output()
287 fmt.Println(string(out))
292 func cmdConsole(cmd *cobra.Command, args []string) error {
296 bufReader := bufio.NewReader(os.Stdin)
297 line, more, err := bufReader.ReadLine()
299 return errors.New("Input is too long")
300 } else if err != nil {
304 pArgs := persistentArgs(line)
305 out, err := exec.Command(pArgs[0], pArgs[1:]...).Output()
309 fmt.Println(string(out))
314 // Have the application echo a message
315 func cmdEcho(cmd *cobra.Command, args []string) error {
316 resEcho := client.EchoSync(args[0])
317 printResponse(cmd, args, response{
323 // Get some info from the application
324 func cmdInfo(cmd *cobra.Command, args []string) error {
329 resInfo, err := client.InfoSync(types.RequestInfo{version})
333 printResponse(cmd, args, response{
334 Data: []byte(resInfo.Data),
339 // Set an option on the application
340 func cmdSetOption(cmd *cobra.Command, args []string) error {
341 resSetOption := client.SetOptionSync(args[0], args[1])
342 printResponse(cmd, args, response{
343 Log: resSetOption.Log,
348 // Append a new tx to application
349 func cmdDeliverTx(cmd *cobra.Command, args []string) error {
350 txBytes, err := stringOrHexToBytes(args[0])
354 res := client.DeliverTxSync(txBytes)
355 printResponse(cmd, args, response{
364 func cmdCheckTx(cmd *cobra.Command, args []string) error {
365 txBytes, err := stringOrHexToBytes(args[0])
369 res := client.CheckTxSync(txBytes)
370 printResponse(cmd, args, response{
378 // Get application Merkle root hash
379 func cmdCommit(cmd *cobra.Command, args []string) error {
380 res := client.CommitSync()
381 printResponse(cmd, args, response{
389 // Query application state
390 func cmdQuery(cmd *cobra.Command, args []string) error {
391 queryBytes, err := stringOrHexToBytes(args[0])
396 resQuery, err := client.QuerySync(types.RequestQuery{
399 Height: uint64(height),
405 printResponse(cmd, args, response{
408 Query: &queryResponse{
410 Value: resQuery.Value,
411 Height: resQuery.Height,
412 Proof: resQuery.Proof,
418 func cmdCounter(cmd *cobra.Command, args []string) error {
420 app := counter.NewCounterApplication(serial)
422 logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
424 // Start the listener
425 srv, err := server.NewServer(addrC, abci, app)
429 srv.SetLogger(logger.With("module", "abci-server"))
430 if _, err := srv.Start(); err != nil {
435 cmn.TrapSignal(func() {
442 func cmdDummy(cmd *cobra.Command, args []string) error {
443 logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
445 // Create the application - in memory or persisted to disk
446 var app types.Application
448 app = dummy.NewDummyApplication()
450 app = dummy.NewPersistentDummyApplication(persist)
451 app.(*dummy.PersistentDummyApplication).SetLogger(logger.With("module", "dummy"))
454 // Start the listener
455 srv, err := server.NewServer(addrD, abci, app)
459 srv.SetLogger(logger.With("module", "abci-server"))
460 if _, err := srv.Start(); err != nil {
465 cmn.TrapSignal(func() {
472 //--------------------------------------------------------------------------------
474 func printResponse(cmd *cobra.Command, args []string, rsp response) {
477 fmt.Println(">", cmd.Use, strings.Join(args, " "))
480 // Always print the status code.
481 fmt.Printf("-> code: %s\n", rsp.Code.String())
483 if len(rsp.Data) != 0 {
484 // Do no print this line when using the commit command
485 // because the string comes out as gibberish
486 if cmd.Use != "commit" {
487 fmt.Printf("-> data: %s\n", rsp.Data)
489 fmt.Printf("-> data.hex: 0x%X\n", rsp.Data)
492 fmt.Printf("-> log: %s\n", rsp.Log)
495 if rsp.Query != nil {
496 fmt.Printf("-> height: %d\n", rsp.Query.Height)
497 if rsp.Query.Key != nil {
498 fmt.Printf("-> key: %s\n", rsp.Query.Key)
499 fmt.Printf("-> key.hex: %X\n", rsp.Query.Key)
501 if rsp.Query.Value != nil {
502 fmt.Printf("-> value: %s\n", rsp.Query.Value)
503 fmt.Printf("-> value.hex: %X\n", rsp.Query.Value)
505 if rsp.Query.Proof != nil {
506 fmt.Printf("-> proof: %X\n", rsp.Query.Proof)
511 // NOTE: s is interpreted as a string unless prefixed with 0x
512 func stringOrHexToBytes(s string) ([]byte, error) {
513 if len(s) > 2 && strings.ToLower(s[:2]) == "0x" {
514 b, err := hex.DecodeString(s[2:])
516 err = fmt.Errorf("Error decoding hex argument: %s", err.Error())
522 if !strings.HasPrefix(s, "\"") || !strings.HasSuffix(s, "\"") {
523 err := fmt.Errorf("Invalid string arg: \"%s\". Must be quoted or a \"0x\"-prefixed hex string", s)
527 return []byte(s[1 : len(s)-1]), nil