diff --git a/CHANGELOG.md b/CHANGELOG.md index 91bd06494..5ed93b91c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## 0.7.0 (October 27, 2017) + +BREAKING CHANGES: + - [cli] consolidate example apps under a single `abci-cli` binary + +IMPROVEMENTS: + - [cli] use spf13/cobra instead of urfave/cli + - [dummy] use iavl instead of merkleeyes, and add support for historical queries + +BUG FIXES: + - [client] fix deadlock on StopForError + ## 0.6.0 (September 22, 2017) BREAKING CHANGES: diff --git a/Makefile b/Makefile index d097ae72b..588e12df5 100644 --- a/Makefile +++ b/Makefile @@ -52,13 +52,12 @@ metalinter: tools metalinter_test: tools @gometalinter --install gometalinter --vendor --deadline=600s --disable-all \ - --enable=aligncheck \ + --enable=maligned \ --enable=deadcode \ --enable=gas \ --enable=goconst \ --enable=goimports \ --enable=gosimple \ - --enable=gotype \ --enable=ineffassign \ --enable=megacheck \ --enable=misspell \ @@ -75,6 +74,7 @@ metalinter_test: tools #--enable=errcheck \ #--enable=gocyclo \ #--enable=golint \ <== comments on anything exported + #--enable=gotype \ #--enable=interfacer \ #--enable=unparam \ #--enable=vet \ diff --git a/README.md b/README.md index f1b2ebb37..33b037da0 100644 --- a/README.md +++ b/README.md @@ -60,9 +60,9 @@ The `abci-cli` tool wraps any ABCI client and can be used for probing/testing an See [the documentation](http://tendermint.readthedocs.io/en/master/) for more details. Multiple example apps are included: -- the `counter` application, which illustrates nonce checking in txs -- the `dummy` application, which illustrates a simple key-value merkle tree -- the `dummy --persistent` application, which augments the dummy with persistence and validator set changes +- the `abci-cli counter` application, which illustrates nonce checking in txs +- the `abci-cli dummy` application, which illustrates a simple key-value merkle tree +- the `abci-cli dummy --persistent` application, which augments the dummy with persistence and validator set changes ## Specification diff --git a/client/socket_client.go b/client/socket_client.go index fd9d0ae9a..1045dea78 100644 --- a/client/socket_client.go +++ b/client/socket_client.go @@ -97,11 +97,11 @@ func (cli *socketClient) OnStop() { // Stop the client and set the error func (cli *socketClient) StopForError(err error) { - cli.mtx.Lock() if !cli.IsRunning() { return } + cli.mtx.Lock() if cli.err == nil { cli.err = err } diff --git a/client/socket_client_test.go b/client/socket_client_test.go new file mode 100644 index 000000000..814d5a68c --- /dev/null +++ b/client/socket_client_test.go @@ -0,0 +1,28 @@ +package abcicli_test + +import ( + "errors" + "testing" + "time" + + "github.com/tendermint/abci/client" +) + +func TestSocketClientStopForErrorDeadlock(t *testing.T) { + c := abcicli.NewSocketClient(":80", false) + err := errors.New("foo-tendermint") + + // See Issue https://github.com/tendermint/abci/issues/114 + doneChan := make(chan bool) + go func() { + defer close(doneChan) + c.StopForError(err) + c.StopForError(err) + }() + + select { + case <-doneChan: + case <-time.After(time.Second * 4): + t.Fatalf("Test took too long, potential deadlock still exists") + } +} diff --git a/cmd/abci-cli/abci-cli.go b/cmd/abci-cli/abci-cli.go index c73169499..1beb08507 100644 --- a/cmd/abci-cli/abci-cli.go +++ b/cmd/abci-cli/abci-cli.go @@ -7,13 +7,18 @@ import ( "fmt" "io" "os" + "os/exec" "strings" abcicli "github.com/tendermint/abci/client" + "github.com/tendermint/abci/example/counter" + "github.com/tendermint/abci/example/dummy" + "github.com/tendermint/abci/server" "github.com/tendermint/abci/types" - "github.com/tendermint/abci/version" + cmn "github.com/tendermint/tmlibs/common" "github.com/tendermint/tmlibs/log" - "github.com/urfave/cli" + + "github.com/spf13/cobra" ) // Structure for data passed to print response. @@ -38,149 +43,213 @@ var client abcicli.Client var logger log.Logger -func main() { - - //workaround for the cli library (https://github.com/urfave/cli/issues/565) - cli.OsExiter = func(_ int) {} +// flags +var ( + // global + address string + abci string + verbose bool + + // query + path string + height int + prove bool + + // counter + addrC string + serial bool + + // dummy + addrD string + persist string +) - app := cli.NewApp() - app.Name = "abci-cli" - app.Usage = "abci-cli [command] [args...]" - app.Version = version.Version - app.Flags = []cli.Flag{ - cli.StringFlag{ - Name: "address", - Value: "tcp://127.0.0.1:46658", - Usage: "address of application socket", - }, - cli.StringFlag{ - Name: "abci", - Value: "socket", - Usage: "socket or grpc", - }, - cli.BoolFlag{ - Name: "verbose", - Usage: "print the command and results as if it were a console session", - }, - } - app.Commands = []cli.Command{ - { - Name: "batch", - Usage: "Run a batch of abci commands against an application", - Action: func(c *cli.Context) error { - return cmdBatch(app, c) - }, - }, - { - Name: "console", - Usage: "Start an interactive abci console for multiple commands", - Action: func(c *cli.Context) error { - return cmdConsole(app, c) - }, - }, - { - Name: "echo", - Usage: "Have the application echo a message", - Action: func(c *cli.Context) error { - return cmdEcho(c) - }, - }, - { - Name: "info", - Usage: "Get some info about the application", - Action: func(c *cli.Context) error { - return cmdInfo(c) - }, - }, - { - Name: "set_option", - Usage: "Set an option on the application", - Action: func(c *cli.Context) error { - return cmdSetOption(c) - }, - }, - { - Name: "deliver_tx", - Usage: "Deliver a new tx to application", - Action: func(c *cli.Context) error { - return cmdDeliverTx(c) - }, - }, - { - Name: "check_tx", - Usage: "Validate a tx", - Action: func(c *cli.Context) error { - return cmdCheckTx(c) - }, - }, - { - Name: "commit", - Usage: "Commit the application state and return the Merkle root hash", - Action: func(c *cli.Context) error { - return cmdCommit(c) - }, - }, - { - Name: "query", - Usage: "Query application state", - Action: func(c *cli.Context) error { - return cmdQuery(c) - }, - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "path", - Value: "/store", - Usage: "Path to prefix the query with", - }, - cli.IntFlag{ - Name: "height", - Value: 0, - Usage: "Height to query the blockchain at", - }, - cli.BoolFlag{ - Name: "prove", - Usage: "Whether or not to return a merkle proof of the query result", - }, - }, - }, - } - app.Before = before - err := app.Run(os.Args) - if err != nil { - logger.Error(err.Error()) - os.Exit(1) - } +var RootCmd = &cobra.Command{ + Use: "abci-cli", + Short: "", + Long: "", + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { -} + switch cmd.Use { + // for the examples apps, don't pre-run + case "counter", "dummy": + return nil + } -func before(c *cli.Context) error { - if logger == nil { - logger = log.NewFilter(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), log.AllowError()) - } - if client == nil { - var err error - client, err = abcicli.NewClient(c.GlobalString("address"), c.GlobalString("abci"), false) - if err != nil { - logger.Error(err.Error()) - os.Exit(1) + if logger == nil { + logger = log.NewFilter(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), log.AllowError()) } - client.SetLogger(logger.With("module", "abci-client")) - if _, err := client.Start(); err != nil { - return err + if client == nil { + var err error + client, err = abcicli.NewClient(address, abci, false) + if err != nil { + return err + } + client.SetLogger(logger.With("module", "abci-client")) + if _, err := client.Start(); err != nil { + return err + } } - } - return nil + return nil + }, +} + +func Execute() { + addGlobalFlags() + addCommands() + RootCmd.Execute() +} + +func addGlobalFlags() { + RootCmd.PersistentFlags().StringVarP(&address, "address", "", "tcp://127.0.0.1:46658", "Address of application socket") + RootCmd.PersistentFlags().StringVarP(&abci, "abci", "", "socket", "Either socket or grpc") + RootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Print the command and results as if it were a console session") +} + +func addQueryFlags() { + queryCmd.PersistentFlags().StringVarP(&path, "path", "", "/store", "Path to prefix query with") + queryCmd.PersistentFlags().IntVarP(&height, "height", "", 0, "Height to query the blockchain at") + queryCmd.PersistentFlags().BoolVarP(&prove, "prove", "", false, "Whether or not to return a merkle proof of the query result") +} + +func addCounterFlags() { + counterCmd.PersistentFlags().StringVarP(&addrC, "addr", "", "tcp://0.0.0.0:46658", "Listen address") + counterCmd.PersistentFlags().BoolVarP(&serial, "serial", "", false, "Enforce incrementing (serial) transactions") +} + +func addDummyFlags() { + dummyCmd.PersistentFlags().StringVarP(&addrD, "addr", "", "tcp://0.0.0.0:46658", "Listen address") + dummyCmd.PersistentFlags().StringVarP(&persist, "persist", "", "", "Directory to use for a database") +} +func addCommands() { + RootCmd.AddCommand(batchCmd) + RootCmd.AddCommand(consoleCmd) + RootCmd.AddCommand(echoCmd) + RootCmd.AddCommand(infoCmd) + RootCmd.AddCommand(setOptionCmd) + RootCmd.AddCommand(deliverTxCmd) + RootCmd.AddCommand(checkTxCmd) + RootCmd.AddCommand(commitCmd) + addQueryFlags() + RootCmd.AddCommand(queryCmd) + + // examples + addCounterFlags() + RootCmd.AddCommand(counterCmd) + addDummyFlags() + RootCmd.AddCommand(dummyCmd) +} + +var batchCmd = &cobra.Command{ + Use: "batch", + Short: "Run a batch of abci commands against an application", + Long: "", + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + return cmdBatch(cmd, args) + }, +} + +var consoleCmd = &cobra.Command{ + Use: "console", + Short: "Start an interactive abci console for multiple commands", + Long: "", + Args: cobra.ExactArgs(0), + ValidArgs: []string{"batch", "echo", "info", "set_option", "deliver_tx", "check_tx", "commit", "query"}, + RunE: func(cmd *cobra.Command, args []string) error { + return cmdConsole(cmd, args) + }, +} + +var echoCmd = &cobra.Command{ + Use: "echo", + Short: "Have the application echo a message", + Long: "", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + return cmdEcho(cmd, args) + }, +} +var infoCmd = &cobra.Command{ + Use: "info", + Short: "Get some info about the application", + Long: "", + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + return cmdInfo(cmd, args) + }, +} +var setOptionCmd = &cobra.Command{ + Use: "set_option", + Short: "Set an option on the application", + Long: "", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + return cmdSetOption(cmd, args) + }, +} + +var deliverTxCmd = &cobra.Command{ + Use: "deliver_tx", + Short: "Deliver a new transaction to the application", + Long: "", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + return cmdDeliverTx(cmd, args) + }, +} + +var checkTxCmd = &cobra.Command{ + Use: "check_tx", + Short: "Validate a transaction", + Long: "", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + return cmdCheckTx(cmd, args) + }, +} + +var commitCmd = &cobra.Command{ + Use: "commit", + Short: "Commit the application state and return the Merkle root hash", + Long: "", + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + return cmdCommit(cmd, args) + }, +} + +var queryCmd = &cobra.Command{ + Use: "query", + Short: "Query the application state", + Long: "", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + return cmdQuery(cmd, args) + }, +} + +var counterCmd = &cobra.Command{ + Use: "counter", + Short: "ABCI demo example", + Long: "", + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + return cmdCounter(cmd, args) + }, } -// badCmd is called when we invoke with an invalid first argument (just for console for now) -func badCmd(c *cli.Context, cmd string) { - fmt.Println("Unknown command:", cmd) - fmt.Println("Please try one of the following:") - fmt.Println("") - cli.DefaultAppComplete(c) +var dummyCmd = &cobra.Command{ + Use: "dummy", + Short: "ABCI demo example", + Long: "", + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + return cmdDummy(cmd, args) + }, } -//Generates new Args array based off of previous call args to maintain flag persistence +// Generates new Args array based off of previous call args to maintain flag persistence func persistentArgs(line []byte) []string { // generate the arguments to run from original os.Args @@ -196,7 +265,7 @@ func persistentArgs(line []byte) []string { //-------------------------------------------------------------------------------- -func cmdBatch(app *cli.App, c *cli.Context) error { +func cmdBatch(cmd *cobra.Command, args []string) error { bufReader := bufio.NewReader(os.Stdin) for { line, more, err := bufReader.ReadLine() @@ -210,18 +279,20 @@ func cmdBatch(app *cli.App, c *cli.Context) error { return err } - args := persistentArgs(line) - app.Run(args) //cli prints error within its func call + pArgs := persistentArgs(line) + out, err := exec.Command(pArgs[0], pArgs[1:]...).Output() + if err != nil { + return err + } + fmt.Println(string(out)) } return nil } -func cmdConsole(app *cli.App, c *cli.Context) error { - // don't hard exit on mistyped commands (eg. check vs check_tx) - app.CommandNotFound = badCmd +func cmdConsole(cmd *cobra.Command, args []string) error { for { - fmt.Printf("\n> ") + fmt.Printf("> ") bufReader := bufio.NewReader(os.Stdin) line, more, err := bufReader.ReadLine() if more { @@ -230,27 +301,27 @@ func cmdConsole(app *cli.App, c *cli.Context) error { return err } - args := persistentArgs(line) - app.Run(args) //cli prints error within its func call + pArgs := persistentArgs(line) + out, err := exec.Command(pArgs[0], pArgs[1:]...).Output() + if err != nil { + return err + } + fmt.Println(string(out)) } + return nil } // Have the application echo a message -func cmdEcho(c *cli.Context) error { - args := c.Args() - if len(args) != 1 { - return errors.New("Command echo takes 1 argument") - } +func cmdEcho(cmd *cobra.Command, args []string) error { resEcho := client.EchoSync(args[0]) - printResponse(c, response{ + printResponse(cmd, args, response{ Data: resEcho.Data, }) return nil } // Get some info from the application -func cmdInfo(c *cli.Context) error { - args := c.Args() +func cmdInfo(cmd *cobra.Command, args []string) error { var version string if len(args) == 1 { version = args[0] @@ -259,37 +330,29 @@ func cmdInfo(c *cli.Context) error { if err != nil { return err } - printResponse(c, response{ + printResponse(cmd, args, response{ Data: []byte(resInfo.Data), }) return nil } // Set an option on the application -func cmdSetOption(c *cli.Context) error { - args := c.Args() - if len(args) != 2 { - return errors.New("Command set_option takes 2 arguments (key, value)") - } +func cmdSetOption(cmd *cobra.Command, args []string) error { resSetOption := client.SetOptionSync(args[0], args[1]) - printResponse(c, response{ + printResponse(cmd, args, response{ Log: resSetOption.Log, }) return nil } // Append a new tx to application -func cmdDeliverTx(c *cli.Context) error { - args := c.Args() - if len(args) != 1 { - return errors.New("Command deliver_tx takes 1 argument") - } - txBytes, err := stringOrHexToBytes(c.Args()[0]) +func cmdDeliverTx(cmd *cobra.Command, args []string) error { + txBytes, err := stringOrHexToBytes(args[0]) if err != nil { return err } res := client.DeliverTxSync(txBytes) - printResponse(c, response{ + printResponse(cmd, args, response{ Code: res.Code, Data: res.Data, Log: res.Log, @@ -298,17 +361,13 @@ func cmdDeliverTx(c *cli.Context) error { } // Validate a tx -func cmdCheckTx(c *cli.Context) error { - args := c.Args() - if len(args) != 1 { - return errors.New("Command check_tx takes 1 argument") - } - txBytes, err := stringOrHexToBytes(c.Args()[0]) +func cmdCheckTx(cmd *cobra.Command, args []string) error { + txBytes, err := stringOrHexToBytes(args[0]) if err != nil { return err } res := client.CheckTxSync(txBytes) - printResponse(c, response{ + printResponse(cmd, args, response{ Code: res.Code, Data: res.Data, Log: res.Log, @@ -317,9 +376,9 @@ func cmdCheckTx(c *cli.Context) error { } // Get application Merkle root hash -func cmdCommit(c *cli.Context) error { +func cmdCommit(cmd *cobra.Command, args []string) error { res := client.CommitSync() - printResponse(c, response{ + printResponse(cmd, args, response{ Code: res.Code, Data: res.Data, Log: res.Log, @@ -328,22 +387,12 @@ func cmdCommit(c *cli.Context) error { } // Query application state -func cmdQuery(c *cli.Context) error { - args := c.Args() - - if len(args) != 1 { - return errors.New("Command query takes 1 argument, the query bytes") - } - +func cmdQuery(cmd *cobra.Command, args []string) error { queryBytes, err := stringOrHexToBytes(args[0]) if err != nil { return err } - path := c.String("path") - height := c.Int("height") - prove := c.Bool("prove") - resQuery, err := client.QuerySync(types.RequestQuery{ Data: queryBytes, Path: path, @@ -353,7 +402,7 @@ func cmdQuery(c *cli.Context) error { if err != nil { return err } - printResponse(c, response{ + printResponse(cmd, args, response{ Code: resQuery.Code, Log: resQuery.Log, Query: &queryResponse{ @@ -366,22 +415,78 @@ func cmdQuery(c *cli.Context) error { return nil } -//-------------------------------------------------------------------------------- +func cmdCounter(cmd *cobra.Command, args []string) error { -func printResponse(c *cli.Context, rsp response) { + app := counter.NewCounterApplication(serial) - verbose := c.GlobalBool("verbose") + logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) - if verbose { - fmt.Println(">", c.Command.Name, strings.Join(c.Args(), " ")) + // Start the listener + srv, err := server.NewServer(addrC, abci, app) + if err != nil { + return err + } + srv.SetLogger(logger.With("module", "abci-server")) + if _, err := srv.Start(); err != nil { + return err + } + + // Wait forever + cmn.TrapSignal(func() { + // Cleanup + srv.Stop() + }) + return nil +} + +func cmdDummy(cmd *cobra.Command, args []string) error { + logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) + + // Create the application - in memory or persisted to disk + var app types.Application + if persist == "" { + app = dummy.NewDummyApplication() + } else { + app = dummy.NewPersistentDummyApplication(persist) + app.(*dummy.PersistentDummyApplication).SetLogger(logger.With("module", "dummy")) } - if !rsp.Code.IsOK() { - fmt.Printf("-> code: %s\n", rsp.Code.String()) + // Start the listener + srv, err := server.NewServer(addrD, abci, app) + if err != nil { + return err + } + srv.SetLogger(logger.With("module", "abci-server")) + if _, err := srv.Start(); err != nil { + return err + } + + // Wait forever + cmn.TrapSignal(func() { + // Cleanup + srv.Stop() + }) + return nil +} + +//-------------------------------------------------------------------------------- + +func printResponse(cmd *cobra.Command, args []string, rsp response) { + + if verbose { + fmt.Println(">", cmd.Use, strings.Join(args, " ")) } + + // Always print the status code. + fmt.Printf("-> code: %s\n", rsp.Code.String()) + if len(rsp.Data) != 0 { - fmt.Printf("-> data: %s\n", rsp.Data) - fmt.Printf("-> data.hex: %X\n", rsp.Data) + // Do no print this line when using the commit command + // because the string comes out as gibberish + if cmd.Use != "commit" { + fmt.Printf("-> data: %s\n", rsp.Data) + } + fmt.Printf("-> data.hex: 0x%X\n", rsp.Data) } if rsp.Log != "" { fmt.Printf("-> log: %s\n", rsp.Log) @@ -401,11 +506,6 @@ func printResponse(c *cli.Context, rsp response) { fmt.Printf("-> proof: %X\n", rsp.Query.Proof) } } - - if verbose { - fmt.Println("") - } - } // NOTE: s is interpreted as a string unless prefixed with 0x diff --git a/cmd/abci-cli/main.go b/cmd/abci-cli/main.go new file mode 100644 index 000000000..736ef3102 --- /dev/null +++ b/cmd/abci-cli/main.go @@ -0,0 +1,5 @@ +package main + +func main() { + Execute() +} diff --git a/cmd/counter/main.go b/cmd/counter/main.go deleted file mode 100644 index aa55778cc..000000000 --- a/cmd/counter/main.go +++ /dev/null @@ -1,41 +0,0 @@ -package main - -import ( - "flag" - "os" - - "github.com/tendermint/abci/example/counter" - "github.com/tendermint/abci/server" - cmn "github.com/tendermint/tmlibs/common" - "github.com/tendermint/tmlibs/log" -) - -func main() { - - addrPtr := flag.String("addr", "tcp://0.0.0.0:46658", "Listen address") - abciPtr := flag.String("abci", "socket", "ABCI server: socket | grpc") - serialPtr := flag.Bool("serial", false, "Enforce incrementing (serial) txs") - flag.Parse() - app := counter.NewCounterApplication(*serialPtr) - - logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) - - // Start the listener - srv, err := server.NewServer(*addrPtr, *abciPtr, app) - if err != nil { - logger.Error(err.Error()) - os.Exit(1) - } - srv.SetLogger(logger.With("module", "abci-server")) - if _, err := srv.Start(); err != nil { - logger.Error(err.Error()) - os.Exit(1) - } - - // Wait forever - cmn.TrapSignal(func() { - // Cleanup - srv.Stop() - }) - -} diff --git a/cmd/dummy/main.go b/cmd/dummy/main.go deleted file mode 100644 index 85bbca18d..000000000 --- a/cmd/dummy/main.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -import ( - "flag" - "os" - - "github.com/tendermint/abci/example/dummy" - "github.com/tendermint/abci/server" - "github.com/tendermint/abci/types" - cmn "github.com/tendermint/tmlibs/common" - "github.com/tendermint/tmlibs/log" -) - -func main() { - - addrPtr := flag.String("addr", "tcp://0.0.0.0:46658", "Listen address") - abciPtr := flag.String("abci", "socket", "socket | grpc") - persistencePtr := flag.String("persist", "", "directory to use for a database") - flag.Parse() - - logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) - - // Create the application - in memory or persisted to disk - var app types.Application - if *persistencePtr == "" { - app = dummy.NewDummyApplication() - } else { - app = dummy.NewPersistentDummyApplication(*persistencePtr) - app.(*dummy.PersistentDummyApplication).SetLogger(logger.With("module", "dummy")) - } - - // Start the listener - srv, err := server.NewServer(*addrPtr, *abciPtr, app) - if err != nil { - logger.Error(err.Error()) - os.Exit(1) - } - srv.SetLogger(logger.With("module", "abci-server")) - if _, err := srv.Start(); err != nil { - logger.Error(err.Error()) - os.Exit(1) - } - - // Wait forever - cmn.TrapSignal(func() { - // Cleanup - srv.Stop() - }) - -} diff --git a/example/dummy/dummy.go b/example/dummy/dummy.go index 5db71f96c..7e95c859b 100644 --- a/example/dummy/dummy.go +++ b/example/dummy/dummy.go @@ -4,19 +4,20 @@ import ( "strings" "github.com/tendermint/abci/types" - "github.com/tendermint/merkleeyes/iavl" + wire "github.com/tendermint/go-wire" + "github.com/tendermint/iavl" cmn "github.com/tendermint/tmlibs/common" - "github.com/tendermint/tmlibs/merkle" + dbm "github.com/tendermint/tmlibs/db" ) type DummyApplication struct { types.BaseApplication - state merkle.Tree + state *iavl.VersionedTree } func NewDummyApplication() *DummyApplication { - state := iavl.NewIAVLTree(0, nil) + state := iavl.NewVersionedTree(0, dbm.NewMemDB()) return &DummyApplication{state: state} } @@ -40,28 +41,45 @@ func (app *DummyApplication) CheckTx(tx []byte) types.Result { } func (app *DummyApplication) Commit() types.Result { - hash := app.state.Hash() + // Save a new version + var hash []byte + var err error + + if app.state.Size() > 0 { + // just add one more to height (kind of arbitrarily stupid) + height := app.state.LatestVersion() + 1 + hash, err = app.state.SaveVersion(height) + if err != nil { + // if this wasn't a dummy app, we'd do something smarter + panic(err) + } + } + return types.NewResultOK(hash, "") } func (app *DummyApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) { if reqQuery.Prove { - value, proof, exists := app.state.Proof(reqQuery.Data) + value, proof, err := app.state.GetWithProof(reqQuery.Data) + // if this wasn't a dummy app, we'd do something smarter + if err != nil { + panic(err) + } resQuery.Index = -1 // TODO make Proof return index resQuery.Key = reqQuery.Data resQuery.Value = value - resQuery.Proof = proof - if exists { + resQuery.Proof = wire.BinaryBytes(proof) + if value != nil { resQuery.Log = "exists" } else { resQuery.Log = "does not exist" } return } else { - index, value, exists := app.state.Get(reqQuery.Data) + index, value := app.state.Get(reqQuery.Data) resQuery.Index = int64(index) resQuery.Value = value - if exists { + if value != nil { resQuery.Log = "exists" } else { resQuery.Log = "does not exist" diff --git a/example/dummy/dummy_test.go b/example/dummy/dummy_test.go index fa9d531b7..751a2e910 100644 --- a/example/dummy/dummy_test.go +++ b/example/dummy/dummy_test.go @@ -10,8 +10,7 @@ import ( abcicli "github.com/tendermint/abci/client" "github.com/tendermint/abci/server" "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" - "github.com/tendermint/merkleeyes/iavl" + "github.com/tendermint/iavl" cmn "github.com/tendermint/tmlibs/common" "github.com/tendermint/tmlibs/log" ) @@ -39,9 +38,10 @@ func testDummy(t *testing.T, app types.Application, tx []byte, key, value string }) require.Equal(t, types.CodeType_OK, resQuery.Code) require.Equal(t, value, string(resQuery.Value)) - proof, err := iavl.ReadProof(resQuery.Proof) + proof, err := iavl.ReadKeyExistsProof(resQuery.Proof) require.Nil(t, err) - require.True(t, proof.Verify([]byte(key), resQuery.Value, proof.RootHash)) // NOTE: we have no way to verify the RootHash + err = proof.Verify([]byte(key), resQuery.Value, proof.RootHash) + require.Nil(t, err, "%+v", err) // NOTE: we have no way to verify the RootHash } func TestDummyKV(t *testing.T) { @@ -78,6 +78,7 @@ func TestPersistentDummyInfo(t *testing.T) { t.Fatal(err) } dummy := NewPersistentDummyApplication(dir) + InitDummy(dummy) height := uint64(0) resInfo := dummy.Info(types.RequestInfo{}) @@ -113,12 +114,7 @@ func TestValSetChanges(t *testing.T) { // init with some validators total := 10 nInit := 5 - vals := make([]*types.Validator, total) - for i := 0; i < total; i++ { - pubkey := crypto.GenPrivKeyEd25519FromSecret([]byte(cmn.Fmt("test%d", i))).PubKey().Bytes() - power := cmn.RandInt() - vals[i] = &types.Validator{pubkey, uint64(power)} - } + vals := RandVals(total) // iniitalize with the first nInit dummy.InitChain(types.RequestInitChain{vals[:nInit]}) @@ -309,7 +305,8 @@ func testClient(t *testing.T, app abcicli.Client, tx []byte, key, value string) require.Nil(t, err) require.Equal(t, types.CodeType_OK, resQuery.Code) require.Equal(t, value, string(resQuery.Value)) - proof, err := iavl.ReadProof(resQuery.Proof) + proof, err := iavl.ReadKeyExistsProof(resQuery.Proof) require.Nil(t, err) - require.True(t, proof.Verify([]byte(key), resQuery.Value, proof.RootHash)) // NOTE: we have no way to verify the RootHash + err = proof.Verify([]byte(key), resQuery.Value, proof.RootHash) + require.Nil(t, err, "%+v", err) // NOTE: we have no way to verify the RootHash } diff --git a/example/dummy/helpers.go b/example/dummy/helpers.go new file mode 100644 index 000000000..55c464de0 --- /dev/null +++ b/example/dummy/helpers.go @@ -0,0 +1,34 @@ +package dummy + +import ( + "github.com/tendermint/abci/types" + crypto "github.com/tendermint/go-crypto" + cmn "github.com/tendermint/tmlibs/common" +) + +// RandVal creates one random validator, with a key derived +// from the input value +func RandVal(i int) *types.Validator { + pubkey := crypto.GenPrivKeyEd25519FromSecret([]byte(cmn.Fmt("test%d", i))).PubKey().Bytes() + power := cmn.RandUint16() + 1 + return &types.Validator{pubkey, uint64(power)} +} + +// RandVals returns a list of cnt validators for initializing +// the application. Note that the keys are deterministically +// derived from the index in the array, while the power is +// random (Change this if not desired) +func RandVals(cnt int) []*types.Validator { + res := make([]*types.Validator, cnt) + for i := 0; i < cnt; i++ { + res[i] = RandVal(i) + } + return res +} + +// InitDummy initializes the dummy app with some data, +// which allows tests to pass and is fine as long as you +// don't make any tx that modify the validator state +func InitDummy(app *PersistentDummyApplication) { + app.InitChain(types.RequestInitChain{RandVals(1)}) +} diff --git a/example/dummy/persistent_dummy.go b/example/dummy/persistent_dummy.go index d392be53c..4c4801755 100644 --- a/example/dummy/persistent_dummy.go +++ b/example/dummy/persistent_dummy.go @@ -6,10 +6,9 @@ import ( "strconv" "strings" - "github.com/pkg/errors" "github.com/tendermint/abci/types" - wire "github.com/tendermint/go-wire" - "github.com/tendermint/merkleeyes/iavl" + crypto "github.com/tendermint/go-crypto" + "github.com/tendermint/iavl" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" @@ -23,11 +22,6 @@ const ( type PersistentDummyApplication struct { app *DummyApplication - db dbm.DB - - // latest received - // TODO: move to merkle tree? - blockHeader *types.Header // validator set changes []*types.Validator @@ -36,17 +30,17 @@ type PersistentDummyApplication struct { } func NewPersistentDummyApplication(dbDir string) *PersistentDummyApplication { - db := dbm.NewDB("dummy", "leveldb", dbDir) - lastBlock := LoadLastBlock(db) - - stateTree := iavl.NewIAVLTree(0, db) - stateTree.Load(lastBlock.AppHash) + name := "dummy" + db, err := dbm.NewGoLevelDB(name, dbDir) + if err != nil { + panic(err) + } - // log.Notice("Loaded state", "block", lastBlock.Height, "root", stateTree.Hash()) + stateTree := iavl.NewVersionedTree(500, db) + stateTree.Load() return &PersistentDummyApplication{ app: &DummyApplication{state: stateTree}, - db: db, logger: log.NewNopLogger(), } } @@ -57,9 +51,8 @@ func (app *PersistentDummyApplication) SetLogger(l log.Logger) { func (app *PersistentDummyApplication) Info(req types.RequestInfo) (resInfo types.ResponseInfo) { resInfo = app.app.Info(req) - lastBlock := LoadLastBlock(app.db) - resInfo.LastBlockHeight = lastBlock.Height - resInfo.LastBlockAppHash = lastBlock.AppHash + resInfo.LastBlockHeight = app.app.state.LatestVersion() + resInfo.LastBlockAppHash = app.app.state.Hash() return resInfo } @@ -67,7 +60,7 @@ func (app *PersistentDummyApplication) SetOption(key string, value string) (log return app.app.SetOption(key, value) } -// tx is either "key=value" or just arbitrary bytes +// tx is either "val:pubkey/power" or "key=value" or just arbitrary bytes func (app *PersistentDummyApplication) DeliverTx(tx []byte) types.Result { // if it starts with "val:", update the validator set // format is "val:pubkey/power" @@ -85,19 +78,21 @@ func (app *PersistentDummyApplication) CheckTx(tx []byte) types.Result { return app.app.CheckTx(tx) } +// Commit will panic if InitChain was not called func (app *PersistentDummyApplication) Commit() types.Result { - // Save - appHash := app.app.state.Save() - app.logger.Info("Saved state", "root", appHash) - lastBlock := LastBlockInfo{ - Height: app.blockHeader.Height, - AppHash: appHash, // this hash will be in the next block header - } + // Save a new version for next height + height := app.app.state.LatestVersion() + 1 + var appHash []byte + var err error - app.logger.Info("Saving block", "height", lastBlock.Height, "root", lastBlock.AppHash) - SaveLastBlock(app.db, lastBlock) + appHash, err = app.app.state.SaveVersion(height) + if err != nil { + // if this wasn't a dummy app, we'd do something smarter + panic(err) + } + app.logger.Info("Commit block", "height", height, "root", appHash) return types.NewResultOK(appHash, "") } @@ -117,9 +112,6 @@ func (app *PersistentDummyApplication) InitChain(params types.RequestInitChain) // Track the block hash and header information func (app *PersistentDummyApplication) BeginBlock(params types.RequestBeginBlock) { - // update latest block info - app.blockHeader = params.Header - // reset valset changes app.changes = make([]*types.Validator, 0) } @@ -129,41 +121,6 @@ func (app *PersistentDummyApplication) EndBlock(height uint64) (resEndBlock type return types.ResponseEndBlock{Diffs: app.changes} } -//----------------------------------------- -// persist the last block info - -var lastBlockKey = []byte("lastblock") - -type LastBlockInfo struct { - Height uint64 - AppHash []byte -} - -// Get the last block from the db -func LoadLastBlock(db dbm.DB) (lastBlock LastBlockInfo) { - buf := db.Get(lastBlockKey) - if len(buf) != 0 { - r, n, err := bytes.NewReader(buf), new(int), new(error) - wire.ReadBinaryPtr(&lastBlock, r, 0, n, err) - if *err != nil { - cmn.PanicCrisis(errors.Wrap(*err, "cannot load last block (data has been corrupted or its spec has changed)")) - } - // TODO: ensure that buf is completely read. - } - - return lastBlock -} - -func SaveLastBlock(db dbm.DB, lastBlock LastBlockInfo) { - buf, n, err := new(bytes.Buffer), new(int), new(error) - wire.WriteBinary(lastBlock, buf, n, err) - if *err != nil { - // TODO - cmn.PanicCrisis(errors.Wrap(*err, "cannot save last block")) - } - db.Set(lastBlockKey, buf.Bytes()) -} - //--------------------------------------------- // update validators @@ -193,15 +150,25 @@ func isValidatorTx(tx []byte) bool { // format is "val:pubkey1/power1,addr2/power2,addr3/power3"tx func (app *PersistentDummyApplication) execValidatorTx(tx []byte) types.Result { tx = tx[len(ValidatorSetChangePrefix):] + + //get the pubkey and power pubKeyAndPower := strings.Split(string(tx), "/") if len(pubKeyAndPower) != 2 { return types.ErrEncodingError.SetLog(cmn.Fmt("Expected 'pubkey/power'. Got %v", pubKeyAndPower)) } pubkeyS, powerS := pubKeyAndPower[0], pubKeyAndPower[1] + + // decode the pubkey, ensuring its go-crypto encoded pubkey, err := hex.DecodeString(pubkeyS) if err != nil { return types.ErrEncodingError.SetLog(cmn.Fmt("Pubkey (%s) is invalid hex", pubkeyS)) } + _, err = crypto.PubKeyFromBytes(pubkey) + if err != nil { + return types.ErrEncodingError.SetLog(cmn.Fmt("Pubkey (%X) is invalid go-crypto encoded", pubkey)) + } + + // decode the power power, err := strconv.Atoi(powerS) if err != nil { return types.ErrEncodingError.SetLog(cmn.Fmt("Power (%s) is not an int", powerS)) diff --git a/glide.lock b/glide.lock index 7b79f0e55..2a992d724 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: f9c2ddad16bf8652076a93bd9f398bb498eefb2f5bd2c89a77d966ebd12feec8 -updated: 2017-09-22T10:34:17.228026799-04:00 +hash: 3c8680f0a289567a29f737be5f1d5f242c7e2afd84bdd023dd74596b88508fc2 +updated: 2017-10-27T12:12:58.940745472-04:00 imports: - name: github.com/btcsuite/btcd version: b8df516b4b267acf2de46be593a9d948d1d2c420 @@ -24,18 +24,27 @@ imports: - name: github.com/go-stack/stack version: 100eb0c0a9c5b306ca2fb4f165df21d80ada4b82 - name: github.com/golang/protobuf - version: 18c9bb3261723cd5401db4d0c9fbc5c3b6c70fe8 + version: 1643683e1b54a9e88ad26d98f81400c8c9d9f4f9 subpackages: - proto + - ptypes - ptypes/any + - ptypes/duration + - ptypes/timestamp - name: github.com/golang/snappy version: 553a641470496b2327abcac10b36396bd98e45c9 +- name: github.com/inconshreveable/mousetrap + version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 - name: github.com/jmhodges/levigo version: c42d9e0ca023e2198120196f842701bb4c55d7b9 - name: github.com/kr/logfmt version: b84e30acd515aadc4b783ad4ff83aff3299bdfe0 - name: github.com/pkg/errors version: 645ef00459ed84a119197bfb8d8205042c6df63d +- name: github.com/spf13/cobra + version: 7b2c5ac9fc04fc5efafb60700713d4fa609b777b +- name: github.com/spf13/pflag + version: 80fe0fb4eba54167e2ccae1c6c950e72abf61b73 - name: github.com/syndtr/goleveldb version: 8c81ea47d4c41a385645e133e15510fc6a2a74b4 subpackages: @@ -57,25 +66,21 @@ imports: - edwards25519 - extra25519 - name: github.com/tendermint/go-crypto - version: e6ea9499ff958479e4a921850d2382eb599f204c + version: db5603e37435933c13665a708055fadd18222f5f - name: github.com/tendermint/go-wire - version: 5f88da3dbc1a72844e6dfaf274ce87f851d488eb + version: 8ee84b5b2581530168daf66fc89c548d27403c57 subpackages: - data -- name: github.com/tendermint/merkleeyes - version: 2f6e5d31e7a35045d8d0a5895cb1fec33dd4d32b - subpackages: - - iavl +- name: github.com/tendermint/iavl + version: 595f3dcd5b6cd4a292e90757ae6d367fd7a6e653 - name: github.com/tendermint/tmlibs - version: bffe6744ec277d60f707ab442e25513617842f8e + version: 092eb701c7276907cdbed258750e22ce895b6735 subpackages: - common - db - log - merkle - process -- name: github.com/urfave/cli - version: d70f47eeca3afd795160003bc6e28b001d60c67c - name: golang.org/x/crypto version: c7af5bf2638a1164f2eb5467c39c6cffbd13a02e subpackages: @@ -86,7 +91,7 @@ imports: - ripemd160 - salsa20/salsa - name: golang.org/x/net - version: feeb485667d1fdabe727840fe00adc22431bc86e + version: cd69bc3fc700721b709c3a59e16e24c67b58f6ff subpackages: - context - http2 @@ -103,27 +108,30 @@ imports: - unicode/bidi - unicode/norm - name: google.golang.org/genproto - version: 411e09b969b1170a9f0c467558eb4c4c110d9c77 + version: f676e0f3ac6395ff1a529ae59a6670878a8371a6 subpackages: - googleapis/rpc/status - name: google.golang.org/grpc - version: 844f573616520565fdc6fb4db242321b5456fd6d + version: f7bf885db0b7479a537ec317c6e48ce53145f3db subpackages: + - balancer - codes + - connectivity - credentials - - grpclb/grpc_lb_v1 + - grpclb/grpc_lb_v1/messages - grpclog - internal - keepalive - metadata - naming - peer + - resolver - stats - status - tap - transport - name: gopkg.in/go-playground/validator.v9 - version: d529ee1b0f30352444f507cc6cdac96bfd12decc + version: 6d8c18553ea1ac493d049edd6f102f52e618f085 testImports: - name: github.com/davecgh/go-spew version: 6d212800a42e8ab5c146b8ace3490ee17e5225f9 diff --git a/glide.yaml b/glide.yaml index 11379aad4..ccd41cdc3 100644 --- a/glide.yaml +++ b/glide.yaml @@ -8,10 +8,8 @@ import: version: develop - package: github.com/tendermint/go-wire version: develop -- package: github.com/tendermint/merkleeyes +- package: github.com/tendermint/iavl version: develop - subpackages: - - iavl - package: github.com/tendermint/tmlibs version: develop subpackages: @@ -20,7 +18,8 @@ import: - log - merkle - process -- package: github.com/urfave/cli +- package: github.com/spf13/cobra + version: master - package: golang.org/x/net subpackages: - context diff --git a/scripts/dist_build.sh b/scripts/dist_build.sh index 0f5e3e3b0..adaca24a8 100755 --- a/scripts/dist_build.sh +++ b/scripts/dist_build.sh @@ -24,30 +24,28 @@ make tools # Get VENDORED dependencies make get_vendor_deps -BINARIES=( "abci-cli" "dummy" "counter" ) - -for binary in ${BINARIES[@]}; do - # Build! - echo "==> Building..." - "$(which gox)" \ - -os="${XC_OS}" \ - -arch="${XC_ARCH}" \ - -osarch="!darwin/arm !solaris/amd64 !freebsd/amd64" \ - -ldflags "-X ${GIT_IMPORT}.GitCommit='${GIT_COMMIT}' -X ${GIT_IMPORT}.GitDescribe='${GIT_DESCRIBE}'" \ - -output "build/pkg/{{.OS}}_{{.Arch}}/$binary" \ - -tags="${BUILD_TAGS}" \ - github.com/tendermint/abci/cmd/$binary - - # Zip all the files. - echo "==> Packaging..." - for PLATFORM in $(find ./build/pkg -mindepth 1 -maxdepth 1 -type d); do - OSARCH=$(basename "${PLATFORM}") - echo "--> ${OSARCH}" - - pushd "$PLATFORM" >/dev/null 2>&1 - zip "../${OSARCH}.zip" ./* - popd >/dev/null 2>&1 - done +BINARY="abci-cli" + +# Build! +echo "==> Building..." +"$(which gox)" \ + -os="${XC_OS}" \ + -arch="${XC_ARCH}" \ + -osarch="!darwin/arm !solaris/amd64 !freebsd/amd64" \ + -ldflags "-X ${GIT_IMPORT}.GitCommit='${GIT_COMMIT}' -X ${GIT_IMPORT}.GitDescribe='${GIT_DESCRIBE}'" \ + -output "build/pkg/{{.OS}}_{{.Arch}}/$BINARY" \ + -tags="${BUILD_TAGS}" \ + github.com/tendermint/abci/cmd/$BINARY + +# Zip all the files. +echo "==> Packaging..." +for PLATFORM in $(find ./build/pkg -mindepth 1 -maxdepth 1 -type d); do + OSARCH=$(basename "${PLATFORM}") + echo "--> ${OSARCH}" + + pushd "$PLATFORM" >/dev/null 2>&1 + zip "../${OSARCH}.zip" ./* + popd >/dev/null 2>&1 done diff --git a/server/grpc_server.go b/server/grpc_server.go index ac3d728ac..077f0e525 100644 --- a/server/grpc_server.go +++ b/server/grpc_server.go @@ -2,7 +2,6 @@ package server import ( "net" - "strings" "google.golang.org/grpc" @@ -23,8 +22,7 @@ type GRPCServer struct { // NewGRPCServer returns a new gRPC ABCI server func NewGRPCServer(protoAddr string, app types.ABCIApplicationServer) cmn.Service { - parts := strings.SplitN(protoAddr, "://", 2) - proto, addr := parts[0], parts[1] + proto, addr := cmn.ProtocolAndAddress(protoAddr) s := &GRPCServer{ proto: proto, addr: addr, diff --git a/server/socket_server.go b/server/socket_server.go index 304a2c7f7..adc7516c6 100644 --- a/server/socket_server.go +++ b/server/socket_server.go @@ -5,7 +5,6 @@ import ( "fmt" "io" "net" - "strings" "sync" "github.com/tendermint/abci/types" @@ -30,8 +29,7 @@ type SocketServer struct { } func NewSocketServer(protoAddr string, app types.Application) cmn.Service { - parts := strings.SplitN(protoAddr, "://", 2) - proto, addr := parts[0], parts[1] + proto, addr := cmn.ProtocolAndAddress(protoAddr) s := &SocketServer{ proto: proto, addr: addr, diff --git a/tests/client_server_test.go b/tests/client_server_test.go new file mode 100644 index 000000000..cc946fcef --- /dev/null +++ b/tests/client_server_test.go @@ -0,0 +1,27 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + abciclient "github.com/tendermint/abci/client" + "github.com/tendermint/abci/example/dummy" + abciserver "github.com/tendermint/abci/server" +) + +func TestClientServerNoAddrPrefix(t *testing.T) { + addr := "localhost:46658" + transport := "socket" + app := dummy.NewDummyApplication() + + server, err := abciserver.NewServer(addr, transport, app) + assert.NoError(t, err, "expected no error on NewServer") + _, err = server.Start() + assert.NoError(t, err, "expected no error on server.Start") + + client, err := abciclient.NewClient(addr, transport, true) + assert.NoError(t, err, "expected no error on NewClient") + _, err = client.Start() + assert.NoError(t, err, "expected no error on client.Start") +} diff --git a/tests/test_cli/ex1.abci.out b/tests/test_cli/ex1.abci.out index e434944a4..6e3440712 100644 --- a/tests/test_cli/ex1.abci.out +++ b/tests/test_cli/ex1.abci.out @@ -1,36 +1,44 @@ > echo hello +-> code: OK -> data: hello --> data.hex: 68656C6C6F +-> data.hex: 0x68656C6C6F > info +-> code: OK -> data: {"size":0} --> data.hex: 7B2273697A65223A307D +-> data.hex: 0x7B2273697A65223A307D > commit +-> code: OK > deliver_tx "abc" +-> code: OK > info +-> code: OK -> data: {"size":1} --> data.hex: 7B2273697A65223A317D +-> data.hex: 0x7B2273697A65223A317D > commit --> data: uü~„»×ˆíX–$ðlú‡EÑ --> data.hex: 750502FC7E84BBD788ED589624F06CFA871845D1 +-> code: OK +-> data.hex: 0x49DFD15CCDACDEAE9728CB01FBB5E8688CA58B91 > query "abc" +-> code: OK -> log: exists -> height: 0 -> value: abc -> value.hex: 616263 > deliver_tx "def=xyz" +-> code: OK > commit --> data: v9;Š.E†°iLbžËQ²†ïÕ --> data.hex: 76393B8A182E450286B0694C629ECB51B286EFD5 +-> code: OK +-> data.hex: 0x70102DB32280373FBF3F9F89DA2A20CE2CD62B0B > query "def" +-> code: OK -> log: exists -> height: 0 -> value: xyz diff --git a/tests/test_cli/ex2.abci.out b/tests/test_cli/ex2.abci.out index 202861cf4..40e10f83e 100644 --- a/tests/test_cli/ex2.abci.out +++ b/tests/test_cli/ex2.abci.out @@ -1,22 +1,28 @@ > set_option serial on +-> code: OK > check_tx 0x00 +-> code: OK > check_tx 0xff +-> code: OK > deliver_tx 0x00 +-> code: OK > check_tx 0x00 -> code: BadNonce -> log: Invalid nonce. Expected >= 1, got 0 > deliver_tx 0x01 +-> code: OK > deliver_tx 0x04 -> code: BadNonce -> log: Invalid nonce. Expected 2, got 4 > info +-> code: OK -> data: {"hashes":0,"txs":2} --> data.hex: 7B22686173686573223A302C22747873223A327D +-> data.hex: 0x7B22686173686573223A302C22747873223A327D diff --git a/tests/test_cli/test.sh b/tests/test_cli/test.sh index 4266dd16f..81b06a0ec 100644 --- a/tests/test_cli/test.sh +++ b/tests/test_cli/test.sh @@ -11,13 +11,13 @@ cd "$DIR" || exit function testExample() { N=$1 INPUT=$2 - APP=$3 + APP="$3 $4" - echo "Example $N" + echo "Example $N: $APP" $APP &> /dev/null & sleep 2 abci-cli --verbose batch < "$INPUT" > "${INPUT}.out.new" - killall "$APP" + killall $3 pre=$(shasum < "${INPUT}.out") post=$(shasum < "${INPUT}.out.new") @@ -34,8 +34,8 @@ function testExample() { rm "${INPUT}".out.new } -testExample 1 tests/test_cli/ex1.abci dummy -testExample 2 tests/test_cli/ex2.abci counter +testExample 1 tests/test_cli/ex1.abci abci-cli dummy +testExample 2 tests/test_cli/ex2.abci abci-cli counter echo "" echo "PASS" diff --git a/testutil/messages.go b/testutil/messages.go deleted file mode 100644 index 0cdddb443..000000000 --- a/testutil/messages.go +++ /dev/null @@ -1,17 +0,0 @@ -package testutil - -import ( - "github.com/tendermint/abci/types" - "github.com/tendermint/go-crypto" -) - -//---------------------------------------- - -// UTILITY -func Validator(secret string, power uint64) *types.Validator { - privKey := crypto.GenPrivKeyEd25519FromSecret([]byte(secret)) - return &types.Validator{ - PubKey: privKey.PubKey().Bytes(), - Power: power, - } -} diff --git a/version/version.go b/version/version.go index 34b1230ed..bbea51bcb 100644 --- a/version/version.go +++ b/version/version.go @@ -3,7 +3,7 @@ package version // NOTE: we should probably be versioning the ABCI and the abci-cli separately const Maj = "0" -const Min = "6" +const Min = "7" const Fix = "0" -const Version = "0.6.0" +const Version = "0.7.0"