OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / tendermint / abci / cmd / abci-cli / abci-cli.go
1 package main
2
3 import (
4         "bufio"
5         "encoding/hex"
6         "errors"
7         "fmt"
8         "io"
9         "os"
10         "os/exec"
11         "strings"
12
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"
20
21         "github.com/spf13/cobra"
22 )
23
24 // Structure for data passed to print response.
25 type response struct {
26         // generic abci response
27         Data []byte
28         Code types.CodeType
29         Log  string
30
31         Query *queryResponse
32 }
33
34 type queryResponse struct {
35         Key    []byte
36         Value  []byte
37         Height uint64
38         Proof  []byte
39 }
40
41 // client is a global variable so it can be reused by the console
42 var client abcicli.Client
43
44 var logger log.Logger
45
46 // flags
47 var (
48         // global
49         address string
50         abci    string
51         verbose bool
52
53         // query
54         path   string
55         height int
56         prove  bool
57
58         // counter
59         addrC  string
60         serial bool
61
62         // dummy
63         addrD   string
64         persist string
65 )
66
67 var RootCmd = &cobra.Command{
68         Use:   "abci-cli",
69         Short: "",
70         Long:  "",
71         PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
72
73                 switch cmd.Use {
74                 // for the examples apps, don't pre-run
75                 case "counter", "dummy":
76                         return nil
77                 }
78
79                 if logger == nil {
80                         logger = log.NewFilter(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), log.AllowError())
81                 }
82                 if client == nil {
83                         var err error
84                         client, err = abcicli.NewClient(address, abci, 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 func Execute() {
98         addGlobalFlags()
99         addCommands()
100         RootCmd.Execute()
101 }
102
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")
107 }
108
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")
113 }
114
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")
118 }
119
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")
123 }
124 func addCommands() {
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)
133         addQueryFlags()
134         RootCmd.AddCommand(queryCmd)
135
136         // examples
137         addCounterFlags()
138         RootCmd.AddCommand(counterCmd)
139         addDummyFlags()
140         RootCmd.AddCommand(dummyCmd)
141 }
142
143 var batchCmd = &cobra.Command{
144         Use:   "batch",
145         Short: "Run a batch of abci commands against an application",
146         Long:  "",
147         Args:  cobra.ExactArgs(0),
148         RunE: func(cmd *cobra.Command, args []string) error {
149                 return cmdBatch(cmd, args)
150         },
151 }
152
153 var consoleCmd = &cobra.Command{
154         Use:       "console",
155         Short:     "Start an interactive abci console for multiple commands",
156         Long:      "",
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)
161         },
162 }
163
164 var echoCmd = &cobra.Command{
165         Use:   "echo",
166         Short: "Have the application echo a message",
167         Long:  "",
168         Args:  cobra.ExactArgs(1),
169         RunE: func(cmd *cobra.Command, args []string) error {
170                 return cmdEcho(cmd, args)
171         },
172 }
173 var infoCmd = &cobra.Command{
174         Use:   "info",
175         Short: "Get some info about the application",
176         Long:  "",
177         Args:  cobra.ExactArgs(0),
178         RunE: func(cmd *cobra.Command, args []string) error {
179                 return cmdInfo(cmd, args)
180         },
181 }
182 var setOptionCmd = &cobra.Command{
183         Use:   "set_option",
184         Short: "Set an option on the application",
185         Long:  "",
186         Args:  cobra.ExactArgs(2),
187         RunE: func(cmd *cobra.Command, args []string) error {
188                 return cmdSetOption(cmd, args)
189         },
190 }
191
192 var deliverTxCmd = &cobra.Command{
193         Use:   "deliver_tx",
194         Short: "Deliver a new transaction to the application",
195         Long:  "",
196         Args:  cobra.ExactArgs(1),
197         RunE: func(cmd *cobra.Command, args []string) error {
198                 return cmdDeliverTx(cmd, args)
199         },
200 }
201
202 var checkTxCmd = &cobra.Command{
203         Use:   "check_tx",
204         Short: "Validate a transaction",
205         Long:  "",
206         Args:  cobra.ExactArgs(1),
207         RunE: func(cmd *cobra.Command, args []string) error {
208                 return cmdCheckTx(cmd, args)
209         },
210 }
211
212 var commitCmd = &cobra.Command{
213         Use:   "commit",
214         Short: "Commit the application state and return the Merkle root hash",
215         Long:  "",
216         Args:  cobra.ExactArgs(0),
217         RunE: func(cmd *cobra.Command, args []string) error {
218                 return cmdCommit(cmd, args)
219         },
220 }
221
222 var queryCmd = &cobra.Command{
223         Use:   "query",
224         Short: "Query the application state",
225         Long:  "",
226         Args:  cobra.ExactArgs(1),
227         RunE: func(cmd *cobra.Command, args []string) error {
228                 return cmdQuery(cmd, args)
229         },
230 }
231
232 var counterCmd = &cobra.Command{
233         Use:   "counter",
234         Short: "ABCI demo example",
235         Long:  "",
236         Args:  cobra.ExactArgs(0),
237         RunE: func(cmd *cobra.Command, args []string) error {
238                 return cmdCounter(cmd, args)
239         },
240 }
241
242 var dummyCmd = &cobra.Command{
243         Use:   "dummy",
244         Short: "ABCI demo example",
245         Long:  "",
246         Args:  cobra.ExactArgs(0),
247         RunE: func(cmd *cobra.Command, args []string) error {
248                 return cmdDummy(cmd, args)
249         },
250 }
251
252 // Generates new Args array based off of previous call args to maintain flag persistence
253 func persistentArgs(line []byte) []string {
254
255         // generate the arguments to run from original os.Args
256         // to maintain flag arguments
257         args := os.Args
258         args = args[:len(args)-1] // remove the previous command argument
259
260         if len(line) > 0 { // prevents introduction of extra space leading to argument parse errors
261                 args = append(args, strings.Split(string(line), " ")...)
262         }
263         return args
264 }
265
266 //--------------------------------------------------------------------------------
267
268 func cmdBatch(cmd *cobra.Command, args []string) error {
269         bufReader := bufio.NewReader(os.Stdin)
270         for {
271                 line, more, err := bufReader.ReadLine()
272                 if more {
273                         return errors.New("Input line is too long")
274                 } else if err == io.EOF {
275                         break
276                 } else if len(line) == 0 {
277                         continue
278                 } else if err != nil {
279                         return err
280                 }
281
282                 pArgs := persistentArgs(line)
283                 out, err := exec.Command(pArgs[0], pArgs[1:]...).Output()
284                 if err != nil {
285                         return err
286                 }
287                 fmt.Println(string(out))
288         }
289         return nil
290 }
291
292 func cmdConsole(cmd *cobra.Command, args []string) error {
293
294         for {
295                 fmt.Printf("> ")
296                 bufReader := bufio.NewReader(os.Stdin)
297                 line, more, err := bufReader.ReadLine()
298                 if more {
299                         return errors.New("Input is too long")
300                 } else if err != nil {
301                         return err
302                 }
303
304                 pArgs := persistentArgs(line)
305                 out, err := exec.Command(pArgs[0], pArgs[1:]...).Output()
306                 if err != nil {
307                         return err
308                 }
309                 fmt.Println(string(out))
310         }
311         return nil
312 }
313
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{
318                 Data: resEcho.Data,
319         })
320         return nil
321 }
322
323 // Get some info from the application
324 func cmdInfo(cmd *cobra.Command, args []string) error {
325         var version string
326         if len(args) == 1 {
327                 version = args[0]
328         }
329         resInfo, err := client.InfoSync(types.RequestInfo{version})
330         if err != nil {
331                 return err
332         }
333         printResponse(cmd, args, response{
334                 Data: []byte(resInfo.Data),
335         })
336         return nil
337 }
338
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,
344         })
345         return nil
346 }
347
348 // Append a new tx to application
349 func cmdDeliverTx(cmd *cobra.Command, args []string) error {
350         txBytes, err := stringOrHexToBytes(args[0])
351         if err != nil {
352                 return err
353         }
354         res := client.DeliverTxSync(txBytes)
355         printResponse(cmd, args, response{
356                 Code: res.Code,
357                 Data: res.Data,
358                 Log:  res.Log,
359         })
360         return nil
361 }
362
363 // Validate a tx
364 func cmdCheckTx(cmd *cobra.Command, args []string) error {
365         txBytes, err := stringOrHexToBytes(args[0])
366         if err != nil {
367                 return err
368         }
369         res := client.CheckTxSync(txBytes)
370         printResponse(cmd, args, response{
371                 Code: res.Code,
372                 Data: res.Data,
373                 Log:  res.Log,
374         })
375         return nil
376 }
377
378 // Get application Merkle root hash
379 func cmdCommit(cmd *cobra.Command, args []string) error {
380         res := client.CommitSync()
381         printResponse(cmd, args, response{
382                 Code: res.Code,
383                 Data: res.Data,
384                 Log:  res.Log,
385         })
386         return nil
387 }
388
389 // Query application state
390 func cmdQuery(cmd *cobra.Command, args []string) error {
391         queryBytes, err := stringOrHexToBytes(args[0])
392         if err != nil {
393                 return err
394         }
395
396         resQuery, err := client.QuerySync(types.RequestQuery{
397                 Data:   queryBytes,
398                 Path:   path,
399                 Height: uint64(height),
400                 Prove:  prove,
401         })
402         if err != nil {
403                 return err
404         }
405         printResponse(cmd, args, response{
406                 Code: resQuery.Code,
407                 Log:  resQuery.Log,
408                 Query: &queryResponse{
409                         Key:    resQuery.Key,
410                         Value:  resQuery.Value,
411                         Height: resQuery.Height,
412                         Proof:  resQuery.Proof,
413                 },
414         })
415         return nil
416 }
417
418 func cmdCounter(cmd *cobra.Command, args []string) error {
419
420         app := counter.NewCounterApplication(serial)
421
422         logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
423
424         // Start the listener
425         srv, err := server.NewServer(addrC, abci, app)
426         if err != nil {
427                 return err
428         }
429         srv.SetLogger(logger.With("module", "abci-server"))
430         if _, err := srv.Start(); err != nil {
431                 return err
432         }
433
434         // Wait forever
435         cmn.TrapSignal(func() {
436                 // Cleanup
437                 srv.Stop()
438         })
439         return nil
440 }
441
442 func cmdDummy(cmd *cobra.Command, args []string) error {
443         logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
444
445         // Create the application - in memory or persisted to disk
446         var app types.Application
447         if persist == "" {
448                 app = dummy.NewDummyApplication()
449         } else {
450                 app = dummy.NewPersistentDummyApplication(persist)
451                 app.(*dummy.PersistentDummyApplication).SetLogger(logger.With("module", "dummy"))
452         }
453
454         // Start the listener
455         srv, err := server.NewServer(addrD, abci, app)
456         if err != nil {
457                 return err
458         }
459         srv.SetLogger(logger.With("module", "abci-server"))
460         if _, err := srv.Start(); err != nil {
461                 return err
462         }
463
464         // Wait forever
465         cmn.TrapSignal(func() {
466                 // Cleanup
467                 srv.Stop()
468         })
469         return nil
470 }
471
472 //--------------------------------------------------------------------------------
473
474 func printResponse(cmd *cobra.Command, args []string, rsp response) {
475
476         if verbose {
477                 fmt.Println(">", cmd.Use, strings.Join(args, " "))
478         }
479
480         // Always print the status code.
481         fmt.Printf("-> code: %s\n", rsp.Code.String())
482
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)
488                 }
489                 fmt.Printf("-> data.hex: 0x%X\n", rsp.Data)
490         }
491         if rsp.Log != "" {
492                 fmt.Printf("-> log: %s\n", rsp.Log)
493         }
494
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)
500                 }
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)
504                 }
505                 if rsp.Query.Proof != nil {
506                         fmt.Printf("-> proof: %X\n", rsp.Query.Proof)
507                 }
508         }
509 }
510
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:])
515                 if err != nil {
516                         err = fmt.Errorf("Error decoding hex argument: %s", err.Error())
517                         return nil, err
518                 }
519                 return b, nil
520         }
521
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)
524                 return nil, err
525         }
526
527         return []byte(s[1 : len(s)-1]), nil
528 }