diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dc591d1..9a990a86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,18 @@ # Changelog -## 0.9.0 (TBD) +## 0.9.0 (December 28, 2017) BREAKING CHANGES: + - [types] Id -> ID - [types] ResponseEndBlock: renamed Diffs field to ValidatorUpdates - [types] changed protobuf field indices for Request and Response oneof types FEATURES: - [types] ResponseEndBlock: added ConsensusParamUpdates +BUG FIXES: + - [cmd] fix console and batch commands to use a single persistent connection + ## 0.8.0 (December 6, 2017) BREAKING CHANGES: diff --git a/README.md b/README.md index 902e3a08..5089f5da 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,20 @@ The two guides to focus on are the `Application Development Guide` and `Using AB Previously, the ABCI was referred to as TMSP. -The community has provided a number of addtional implementations, see the `Tendermint Ecosystem` in [the documentation](http://tendermint.readthedocs.io/en/master/). +The community has provided a number of addtional implementations, see the [Tendermint Ecosystem](https://tendermint.com/ecosystem) + +## Specification + +See the [spec file](specification.rst) for more information. + +## Install + +``` +go get github.com/tendermint/abci +cd $GOPATH/src/github.com/tendermint/abci +make get_vendor_deps +make install +``` ## Implementation @@ -24,19 +37,21 @@ We provide three implementations of the ABCI in Go: - GRPC Note the GRPC version is maintained primarily to simplify onboarding and prototyping and is not receiving the same -attention to security and performance as the others. +attention to security and performance as the others ### In Process The simplest implementation just uses function calls within Go. This means ABCI applications written in Golang can be compiled with TendermintCore and run as a single binary. +See the [examples](#examples) below for more information. + ### Socket (TSP) ABCI is best implemented as a streaming protocol. The socket implementation provides for asynchronous, ordered message passing over unix or tcp. Messages are serialized using Protobuf3 and length-prefixed. -Protobuf3 doesn't have an official length-prefix standard, so we use our own. The first byte represents the length of the big-endian encoded length. +Protobuf3 doesn't have an official length-prefix standard, so we use our own. The first byte represents the length of the big-endian encoded length. For example, if the Protobuf3 encoded ABCI message is `0xDEADBEEF` (4 bytes), the length-prefixed message is `0x0104DEADBEEF`. If the Protobuf3 encoded ABCI message is 65535 bytes long, the length-prefixed message would be like `0x02FFFF...`. @@ -48,36 +63,85 @@ the ordered, asynchronous socket protocol. The implementation has also not recei Note the length-prefixing used in the socket implementation does not apply for GRPC. -## Tools +## Usage The `abci-cli` tool wraps an ABCI client and can be used for probing/testing an ABCI server. For instance, `abci-cli test` will run a test sequence against a listening server running the Counter application (see below). It can also be used to run some example applications. See [the documentation](http://tendermint.readthedocs.io/en/master/) for more details. -### Example Apps +### Examples -Multiple example apps are included: -- 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 +Check out the variety of example applications in the [example directory](example/). +It also contains the code refered to by the `counter` and `dummy` apps; these apps come +built into the `abci-cli` binary. -### Install +#### Counter -``` -go get github.com/tendermint/abci -cd $GOPATH/src/github.com/tendermint/abci -make get_vendor_deps -make install +The `abci-cli counter` application illustrates nonce checking in transactions. It's code looks like: + +```golang +func cmdCounter(cmd *cobra.Command, args []string) error { + + app := counter.NewCounterApplication(flagSerial) + + logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) + + // Start the listener + srv, err := server.NewServer(flagAddrC, flagAbci, 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 +} ``` -## Specification +and can be found in [this file](cmd/abci-cli/abci-cli.go). -The [primary specification](https://github.com/tendermint/abci/blob/master/types/types.proto) is made using Protocol Buffers. -To build it, run +#### Dummy -``` -make protoc +The `abci-cli dummy` application, which illustrates a simple key-value Merkle tree + +```golang +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 flagPersist == "" { + app = dummy.NewDummyApplication() + } else { + app = dummy.NewPersistentDummyApplication(flagPersist) + app.(*dummy.PersistentDummyApplication).SetLogger(logger.With("module", "dummy")) + } + + // Start the listener + srv, err := server.NewServer(flagAddrD, flagAbci, 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 +} ``` See `protoc --help` and [the Protocol Buffers site](https://developers.google.com/protocol-buffers/) for details on compiling for other languages. @@ -200,3 +264,5 @@ Here, we describe the requests and responses as function arguments and return va * `Log (string)`: Debug or error message * __Usage__:
Return a Merkle root hash of the application state. +and can be found in [this file](cmd/abci-cli/abci-cli.go). + diff --git a/circle.yml b/circle.yml index 2f52ce9f..8e737339 100644 --- a/circle.yml +++ b/circle.yml @@ -15,7 +15,7 @@ checkout: test: override: - - cd $REPO && make get_tools check build test_integrations + - cd $REPO && make get_tools check get_vendor_deps install test_integrations post: - cd "$REPO" && bash <(curl -s https://codecov.io/bash) -f coverage.txt - cd "$REPO" && mv coverage.txt "${CIRCLE_ARTIFACTS}" diff --git a/cmd/abci-cli/abci-cli.go b/cmd/abci-cli/abci-cli.go index 0b8102ee..7d257f27 100644 --- a/cmd/abci-cli/abci-cli.go +++ b/cmd/abci-cli/abci-cli.go @@ -54,8 +54,8 @@ var ( var RootCmd = &cobra.Command{ Use: "abci-cli", - Short: "", - Long: "", + Short: "the ABCI CLI tool wraps an ABCI client", + Long: "the ABCI CLI tool wraps an ABCI client and is used for testing ABCI servers", PersistentPreRunE: func(cmd *cobra.Command, args []string) error { switch cmd.Use { @@ -112,26 +112,26 @@ func Execute() error { } func addGlobalFlags() { - RootCmd.PersistentFlags().StringVarP(&flagAddress, "address", "", "tcp://0.0.0.0:46658", "Address of application socket") - RootCmd.PersistentFlags().StringVarP(&flagAbci, "abci", "", "socket", "Either socket or grpc") - RootCmd.PersistentFlags().BoolVarP(&flagVerbose, "verbose", "v", false, "Print the command and results as if it were a console session") - RootCmd.PersistentFlags().StringVarP(&flagLogLevel, "log_level", "", "debug", "Set the logger level") + RootCmd.PersistentFlags().StringVarP(&flagAddress, "address", "", "tcp://0.0.0.0:46658", "address of application socket") + RootCmd.PersistentFlags().StringVarP(&flagAbci, "abci", "", "socket", "either socket or grpc") + RootCmd.PersistentFlags().BoolVarP(&flagVerbose, "verbose", "v", false, "print the command and results as if it were a console session") + RootCmd.PersistentFlags().StringVarP(&flagLogLevel, "log_level", "", "debug", "set the logger level") } func addQueryFlags() { - queryCmd.PersistentFlags().StringVarP(&flagPath, "path", "", "/store", "Path to prefix query with") - queryCmd.PersistentFlags().IntVarP(&flagHeight, "height", "", 0, "Height to query the blockchain at") - queryCmd.PersistentFlags().BoolVarP(&flagProve, "prove", "", false, "Whether or not to return a merkle proof of the query result") + queryCmd.PersistentFlags().StringVarP(&flagPath, "path", "", "/store", "path to prefix query with") + queryCmd.PersistentFlags().IntVarP(&flagHeight, "height", "", 0, "height to query the blockchain at") + queryCmd.PersistentFlags().BoolVarP(&flagProve, "prove", "", false, "whether or not to return a merkle proof of the query result") } func addCounterFlags() { - counterCmd.PersistentFlags().StringVarP(&flagAddrC, "addr", "", "tcp://0.0.0.0:46658", "Listen address") - counterCmd.PersistentFlags().BoolVarP(&flagSerial, "serial", "", false, "Enforce incrementing (serial) transactions") + counterCmd.PersistentFlags().StringVarP(&flagAddrC, "addr", "", "tcp://0.0.0.0:46658", "listen address") + counterCmd.PersistentFlags().BoolVarP(&flagSerial, "serial", "", false, "enforce incrementing (serial) transactions") } func addDummyFlags() { - dummyCmd.PersistentFlags().StringVarP(&flagAddrD, "addr", "", "tcp://0.0.0.0:46658", "Listen address") - dummyCmd.PersistentFlags().StringVarP(&flagPersist, "persist", "", "", "Directory to use for a database") + dummyCmd.PersistentFlags().StringVarP(&flagAddrD, "addr", "", "tcp://0.0.0.0:46658", "listen address") + dummyCmd.PersistentFlags().StringVarP(&flagPersist, "persist", "", "", "directory to use for a database") } func addCommands() { RootCmd.AddCommand(batchCmd) @@ -156,18 +156,39 @@ func addCommands() { var batchCmd = &cobra.Command{ Use: "batch", - Short: "Run a batch of abci commands against an application", - Long: "", - Args: cobra.ExactArgs(0), + Short: "run a batch of abci commands against an application", + Long: `run a batch of abci commands against an application + +This command is run by piping in a file containing a series of commands +you'd like to run: + + abci-cli batch < example.file + +where example.file looks something like: + + set_option serial on + check_tx 0x00 + check_tx 0xff + deliver_tx 0x00 + check_tx 0x00 + deliver_tx 0x01 + deliver_tx 0x04 + info +`, + 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: "", + Use: "console", + Short: "start an interactive ABCI console for multiple commands", + Long: `start an interactive ABCI console for multiple commands + +This command opens an interactive console for running any of the other commands +without opening a new connection each time +`, Args: cobra.ExactArgs(0), ValidArgs: []string{"echo", "info", "set_option", "deliver_tx", "check_tx", "commit", "query"}, RunE: func(cmd *cobra.Command, args []string) error { @@ -177,8 +198,8 @@ var consoleCmd = &cobra.Command{ var echoCmd = &cobra.Command{ Use: "echo", - Short: "Have the application echo a message", - Long: "", + Short: "have the application echo a message", + Long: "have the application echo a message", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { return cmdEcho(cmd, args) @@ -186,8 +207,8 @@ var echoCmd = &cobra.Command{ } var infoCmd = &cobra.Command{ Use: "info", - Short: "Get some info about the application", - Long: "", + Short: "get some info about the application", + Long: "get some info about the application", Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { return cmdInfo(cmd, args) @@ -195,8 +216,8 @@ var infoCmd = &cobra.Command{ } var setOptionCmd = &cobra.Command{ Use: "set_option", - Short: "Set an option on the application", - Long: "", + Short: "set an option on the application", + Long: "set an option on the application", Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { return cmdSetOption(cmd, args) @@ -205,8 +226,8 @@ var setOptionCmd = &cobra.Command{ var deliverTxCmd = &cobra.Command{ Use: "deliver_tx", - Short: "Deliver a new transaction to the application", - Long: "", + Short: "deliver a new transaction to the application", + Long: "deliver a new transaction to the application", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { return cmdDeliverTx(cmd, args) @@ -215,8 +236,8 @@ var deliverTxCmd = &cobra.Command{ var checkTxCmd = &cobra.Command{ Use: "check_tx", - Short: "Validate a transaction", - Long: "", + Short: "validate a transaction", + Long: "validate a transaction", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { return cmdCheckTx(cmd, args) @@ -225,8 +246,8 @@ var checkTxCmd = &cobra.Command{ var commitCmd = &cobra.Command{ Use: "commit", - Short: "Commit the application state and return the Merkle root hash", - Long: "", + Short: "commit the application state and return the Merkle root hash", + Long: "commit the application state and return the Merkle root hash", Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { return cmdCommit(cmd, args) @@ -235,8 +256,8 @@ var commitCmd = &cobra.Command{ var versionCmd = &cobra.Command{ Use: "version", - Short: "Print abci console version", - Long: "", + Short: "print ABCI console version", + Long: "print ABCI console version", Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { fmt.Println(version.Version) @@ -246,8 +267,8 @@ var versionCmd = &cobra.Command{ var queryCmd = &cobra.Command{ Use: "query", - Short: "Query the application state", - Long: "", + Short: "query the application state", + Long: "query the application state", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { return cmdQuery(cmd, args) @@ -257,7 +278,7 @@ var queryCmd = &cobra.Command{ var counterCmd = &cobra.Command{ Use: "counter", Short: "ABCI demo example", - Long: "", + Long: "ABCI demo example", Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { return cmdCounter(cmd, args) @@ -267,7 +288,7 @@ var counterCmd = &cobra.Command{ var dummyCmd = &cobra.Command{ Use: "dummy", Short: "ABCI demo example", - Long: "", + Long: "ABCI demo example", Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { return cmdDummy(cmd, args) @@ -276,8 +297,8 @@ var dummyCmd = &cobra.Command{ var testCmd = &cobra.Command{ Use: "test", - Short: "Run integration tests", - Long: "", + Short: "run integration tests", + Long: "run integration tests", Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { return cmdTest(cmd, args) @@ -300,49 +321,39 @@ func persistentArgs(line []byte) []string { //-------------------------------------------------------------------------------- -func or(err1 error, err2 error) error { - if err1 == nil { - return err2 +func compose(fs []func() error) error { + if len(fs) == 0 { + return nil } else { - return err1 + err := fs[0]() + if err == nil { + return compose(fs[1:]) + } else { + return err + } } } func cmdTest(cmd *cobra.Command, args []string) error { - fmt.Println("Running tests") - - err := servertest.InitChain(client) - fmt.Println("") - err = or(err, servertest.SetOption(client, "serial", "on")) - fmt.Println("") - err = or(err, servertest.Commit(client, nil)) - fmt.Println("") - err = or(err, servertest.DeliverTx(client, []byte("abc"), code.CodeTypeBadNonce, nil)) - fmt.Println("") - err = or(err, servertest.Commit(client, nil)) - fmt.Println("") - err = or(err, servertest.DeliverTx(client, []byte{0x00}, code.CodeTypeOK, nil)) - fmt.Println("") - err = or(err, servertest.Commit(client, []byte{0, 0, 0, 0, 0, 0, 0, 1})) - fmt.Println("") - err = or(err, servertest.DeliverTx(client, []byte{0x00}, code.CodeTypeBadNonce, nil)) - fmt.Println("") - err = or(err, servertest.DeliverTx(client, []byte{0x01}, code.CodeTypeOK, nil)) - fmt.Println("") - err = or(err, servertest.DeliverTx(client, []byte{0x00, 0x02}, code.CodeTypeOK, nil)) - fmt.Println("") - err = or(err, servertest.DeliverTx(client, []byte{0x00, 0x03}, code.CodeTypeOK, nil)) - fmt.Println("") - err = or(err, servertest.DeliverTx(client, []byte{0x00, 0x00, 0x04}, code.CodeTypeOK, nil)) - fmt.Println("") - err = or(err, servertest.DeliverTx(client, []byte{0x00, 0x00, 0x06}, code.CodeTypeBadNonce, nil)) - fmt.Println("") - err = or(err, servertest.Commit(client, []byte{0, 0, 0, 0, 0, 0, 0, 5})) - - if err != nil { - return errors.New("Some checks didn't pass, please inspect stdout to see the exact failures.") - } - return nil + return compose( + []func() error{ + func() error { return servertest.InitChain(client) }, + func() error { return servertest.SetOption(client, "serial", "on") }, + func() error { return servertest.Commit(client, nil) }, + func() error { return servertest.DeliverTx(client, []byte("abc"), code.CodeTypeBadNonce, nil) }, + func() error { return servertest.Commit(client, nil) }, + func() error { return servertest.DeliverTx(client, []byte{0x00}, code.CodeTypeOK, nil) }, + func() error { return servertest.Commit(client, []byte{0, 0, 0, 0, 0, 0, 0, 1}) }, + func() error { return servertest.DeliverTx(client, []byte{0x00}, code.CodeTypeBadNonce, nil) }, + func() error { return servertest.DeliverTx(client, []byte{0x01}, code.CodeTypeOK, nil) }, + func() error { return servertest.DeliverTx(client, []byte{0x00, 0x02}, code.CodeTypeOK, nil) }, + func() error { return servertest.DeliverTx(client, []byte{0x00, 0x03}, code.CodeTypeOK, nil) }, + func() error { return servertest.DeliverTx(client, []byte{0x00, 0x00, 0x04}, code.CodeTypeOK, nil) }, + func() error { + return servertest.DeliverTx(client, []byte{0x00, 0x00, 0x06}, code.CodeTypeBadNonce, nil) + }, + func() error { return servertest.Commit(client, []byte{0, 0, 0, 0, 0, 0, 0, 5}) }, + }) } func cmdBatch(cmd *cobra.Command, args []string) error { diff --git a/specification.rst b/specification.rst new file mode 100644 index 00000000..282178ce --- /dev/null +++ b/specification.rst @@ -0,0 +1,221 @@ +Specification +============= + +The `primary +specification `__ +is made using Protocol Buffers. To build it, run + +:: + + make protoc + +See ``protoc --help`` and `the Protocol Buffers +site `__ for details on +compiling for other languages. Note we also include a +`GRPC `__ service definition. + +For the specification as an interface in Go, see the +`types/application.go +file `__. + +Message Types +~~~~~~~~~~~~~ + +ABCI requests/responses are defined as simple Protobuf messages in `this +schema +file `__. +TendermintCore sends the requests, and the ABCI application sends the +responses. Here, we describe the requests and responses as function +arguments and return values, and make some notes about usage: + +Echo +^^^^ + +- **Arguments**: + + - ``Message (string)``: A string to echo back + +- **Returns**: + + - ``Message (string)``: The input string + +- **Usage**: + + - Echo a string to test an abci client/server implementation + +Flush +^^^^^ + +- **Usage**: + + - Signals that messages queued on the client should be flushed to + the server. It is called periodically by the client implementation + to ensure asynchronous requests are actually sent, and is called + immediately to make a synchronous request, which returns when the + Flush response comes back. + +Info +^^^^ + +- **Returns**: + + - ``Data (string)``: Some arbitrary information + - ``Version (Version)``: Version information + - ``LastBlockHeight (int64)``: Latest block for which the app has + called Commit + - ``LastBlockAppHash ([]byte)``: Latest result of Commit + +- **Usage**: Return information about the application state. Used to + sync the app with Tendermint on crash/restart. + +SetOption +^^^^^^^^^ + +- **Arguments**: + + - ``Key (string)``: Key to set + - ``Value (string)``: Value to set for key + +- **Returns**: + + - ``Code (uint32)``: Response code + - ``Log (string)``: Debug or error message + +- **Usage**: Set application options. E.g. Key="mode", Value="mempool" + for a mempool connection, or Key="mode", Value="consensus" for a + consensus connection. Other options are application specific. + +InitChain +^^^^^^^^^ + +- **Arguments**: + + - ``Validators ([]Validator)``: Initial genesis validators + +- **Usage**: Called once upon genesis + +Query +^^^^^ + +- **Arguments**: + + - ``Data ([]byte)``: Raw query bytes. Can be used with or in lieu of + Path. + - ``Path (string)``: Path of request, like an HTTP GET path. Can be + used with or in liue of Data. + - Apps MUST interpret '/store' as a query by key on the underlying + store. The key SHOULD be specified in the Data field. + - Apps SHOULD allow queries over specific types like '/accounts/...' + or '/votes/...' + - ``Height (int64)``: The block height for which you want the query + (default=0 returns data for the latest committed block). Note that + this is the height of the block containing the application's + Merkle root hash, which represents the state as it was after + committing the block at Height-1 + - ``Prove (bool)``: Return Merkle proof with response if possible + +- **Returns**: + + - ``Code (uint32)``: Response code + - ``Key ([]byte)``: The key of the matching data + - ``Value ([]byte)``: The value of the matching data + - ``Proof ([]byte)``: Proof for the data, if requested + - ``Height (int64)``: The block height from which data was derived. + Note that this is the height of the block containing the + application's Merkle root hash, which represents the state as it + was after committing the block at Height-1 + - ``Log (string)``: Debug or error message + +BeginBlock +^^^^^^^^^^ + +- **Arguments**: + + - ``Hash ([]byte)``: The block's hash. This can be derived from the + block header. + - ``Header (struct{})``: The block header + - ``AbsentValidators ([]int32)``: List of indices of validators not + included in the LastCommit + - ``ByzantineValidators ([]Evidence)``: List of evidence of + validators that acted maliciously + +- **Usage**: Signals the beginning of a new block. Called prior to any + DeliverTxs. The header is expected to at least contain the Height. + The ``AbsentValidators`` and ``ByzantineValidators`` can be used to + determine rewards and punishments for the validators. + +CheckTx +^^^^^^^ + +- **Arguments**: + + - ``Data ([]byte)``: The request transaction bytes + +- **Returns**: + + - ``Code (uint32)``: Response code + - ``Data ([]byte)``: Result bytes, if any + - ``Log (string)``: Debug or error message + - ``Gas (int64)``: Amount of gas consumed by transaction + - ``Fee (int64)``: Fee paid by transaction + +- **Usage**: Validate a mempool transaction, prior to broadcasting or + proposing. This message should not mutate the main state, but + application developers may want to keep a separate CheckTx state that + gets reset upon Commit. + + CheckTx can happen interspersed with DeliverTx, but they happen on + different ABCI connections - CheckTx from the mempool connection, and + DeliverTx from the consensus connection. During Commit, the mempool + is locked, so you can reset the mempool state to the latest state + after running all those DeliverTxs, and then the mempool will re-run + whatever txs it has against that latest mempool state. + + Transactions are first run through CheckTx before broadcast to peers + in the mempool layer. You can make CheckTx semi-stateful and clear + the state upon ``Commit`` or ``BeginBlock``, to allow for dependent + sequences of transactions in the same block. + +DeliverTx +^^^^^^^^^ + +- **Arguments**: + + - ``Data ([]byte)``: The request transaction bytes + +- **Returns**: + + - ``Code (uint32)``: Response code + - ``Data ([]byte)``: Result bytes, if any + - ``Log (string)``: Debug or error message + - ``Tags ([]*KVPair)``: Optional tags for indexing + +- **Usage**: Append and run a transaction. If the transaction is valid, + returns CodeType.OK + +EndBlock +^^^^^^^^ + +- **Arguments**: + + - ``Height (int64)``: The block height that ended + +- **Returns**: + + - ``ValidatorUpdates ([]Validator)``: Changes to validator set (set + voting power to 0 to remove) + - ``ConsensusParamUpdates (ConsensusParams)``: Changes to + consensus-critical time/size parameters + +- **Usage**: Signals the end of a block. Called prior to each Commit + after all transactions. Validator set is updated with the result. + +Commit +^^^^^^ + +- **Returns**: + + - ``Data ([]byte)``: The Merkle root hash + - ``Log (string)``: Debug or error message + +- **Usage**: Return a Merkle root hash of the application state. diff --git a/tests/test_cli/test.sh b/tests/test_cli/test.sh index ed00b9d7..dcf2dcc8 100755 --- a/tests/test_cli/test.sh +++ b/tests/test_cli/test.sh @@ -20,8 +20,8 @@ function testExample() { abci-cli --log_level=error --verbose batch < "$INPUT" > "${INPUT}.out.new" killall "$3" - pre=$(shasum < "${INPUT}.out") - post=$(shasum < "${INPUT}.out.new") + pre=$(sha256sum < "${INPUT}.out") + post=$(sha256sum < "${INPUT}.out.new") if [[ "$pre" != "$post" ]]; then echo "You broke the tutorial" diff --git a/version/version.go b/version/version.go index c0699526..982a8886 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 = "8" +const Min = "9" const Fix = "0" -const Version = "0.8.0" +const Version = "0.9.0"